backup: Freshdesk AI [2026-11-04]

This commit is contained in:
moonside committed 2026-11-04 05:00:36 +00:00
1 parent 6f5cd1b4cd
commit 667fca0261
1 file changed
+564 -8
+564 -8
View File
@@ -2,11 +2,11 @@
"id": "bjH659Q8VTSEpAGw",
"name": "Freshdesk AI",
"active": true,
"activeVersionId": "16d723dc-88d5-44c6-a4aa-46d052ca141a",
"activeVersionId": "f2818a1f-3067-4c99-820d-e231e04f3244",
"createdAt": "2026-06-24T01:06:29.500Z",
"updatedAt": "2026-10-28T20:15:44.847Z",
"updatedAt": "2026-11-03T15:44:28.746Z",
"isArchived": false,
"versionId": "16d723dc-88d5-44c6-a4aa-46d052ca141a",
"versionId": "f2818a1f-3067-4c99-820d-e231e04f3244",
"triggerCount": 1,
"nodes": [
{
@@ -813,6 +813,193 @@
}
}
},
{
"id": "6e4ab4df-2386-44d9-855e-18545b066364",
"name": "New Deal Invoice Gate",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-48,
33296
],
"parameters": {
"jsCode": "// DETERMINISTIC selection gate for InvoiceBot. This used to live inside the\n// InvoiceBot agent prompt, where the model re-interpreted it every 5 minutes.\n// It is code now, so the rule cannot drift.\n//\n// A ticket is an invoicing candidate only when its SUBJECT contains BOTH\n// \"closed won\" AND \"new deal\" (case-insensitive), and it is still actionable.\n// Anything else passes through untouched.\n//\n// Read from the source nodes explicitly: the preceding Freshdesk tag update\n// returns an API response, not the ticket.\nconst t = $('One Ticket at a Time').item.json;\nconst subject = String(t.subject || '');\nconst s = subject.toLowerCase();\n\nconst hasClosedWon = s.includes('closed won');\nconst hasNewDeal = s.includes('new deal');\n\n// InvoiceBot files its own exception tickets with this prefix. They must never\n// be fed back in as deals to invoice.\nconst isBotException = /invoicebot exception/i.test(subject) || /^new_deal_invoice/i.test(subject);\n\nlet dealId = '';\ntry { dealId = String($('Extract Deal ID').item.json.deal_id_hint || ''); } catch (e) {}\n\nconst clientName = String(t.client_name || '');\n\nconst isCandidate = hasClosedWon && hasNewDeal && !isBotException;\n\nconsole.log('invoice gate: ticket=' + t.ticket_id + ' closedWon=' + hasClosedWon + ' newDeal=' + hasNewDeal + ' botException=' + isBotException + ' candidate=' + isCandidate);\n\nreturn [{ json: {\n ticket_id: String(t.ticket_id || ''),\n ticket_subject: subject,\n client_name: clientName,\n deal_id: dealId,\n is_invoice_candidate: isCandidate\n} }];"
}
},
{
"id": "cf7291e1-2515-4cd3-b565-5a657399cfd7",
"name": "Invoice Candidate?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
176,
33296
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose",
"version": 2
},
"conditions": [
{
"id": "is-candidate",
"leftValue": "={{ $json.is_invoice_candidate }}",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"looseTypeValidation": true,
"options": {}
}
},
{
"id": "3c286294-670c-48d0-854d-362b347f5b64",
"name": "Resolve Billing Entity",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
400,
33232
],
"parameters": {
"operation": "executeQuery",
"query": "-- Resolve the legal entity to invoice under from the ingested contract.\n-- Prefer the deal id (filenames always contain it); fall back to client name.\nSELECT entity, client_name, filename\nFROM contracts\nWHERE ($1 <> '' AND filename ILIKE '%' || $1 || '%')\n OR ($1 = '' AND $2 <> '' AND client_name ILIKE '%' || $2 || '%')\n AND entity IS NOT NULL AND entity <> ''\nORDER BY effective_date DESC NULLS LAST, filename ASC\nLIMIT 1",
"options": {
"queryReplacement": "={{ [$json.deal_id, $json.client_name] }}"
}
},
"credentials": {
"postgres": {
"id": "NoPrLWbqySMMmIaI",
"name": "Postgres n8n-quickbooks"
}
},
"alwaysOutputData": true
},
{
"id": "5e395973-d37c-4379-b88e-71f20236f893",
"name": "Invoiceable Entity?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
624,
33232
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "loose",
"version": 2
},
"conditions": [
{
"id": "entity-supported",
"leftValue": "={{ ['MUS','MMX','MSAG'].includes(String($json.entity || '').trim().toUpperCase()) }}",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"looseTypeValidation": true,
"options": {}
}
},
{
"id": "a1bb6750-3fc4-489d-b998-9b41eaa7e759",
"name": "Run InvoiceBot For Ticket",
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.2,
"position": [
848,
33392
],
"parameters": {
"source": "database",
"workflowId": {
"__rl": true,
"mode": "id",
"value": "ShZpx3whvS8ZIldl",
"cachedResultName": "InvoiceBot"
},
"mode": "each",
"workflowInputs": {
"mappingMode": "defineBelow",
"value": {
"ticket_id": "={{ $('New Deal Invoice Gate').item.json.ticket_id }}",
"ticket_subject": "={{ $('New Deal Invoice Gate').item.json.ticket_subject }}",
"client_name": "={{ $json.client_name || $('New Deal Invoice Gate').item.json.client_name }}",
"deal_id": "={{ $('New Deal Invoice Gate').item.json.deal_id }}",
"entity": "={{ String($json.entity).trim().toUpperCase() }}"
},
"matchingColumns": [],
"schema": [
{
"id": "ticket_id",
"displayName": "ticket_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "ticket_subject",
"displayName": "ticket_subject",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "client_name",
"displayName": "client_name",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "deal_id",
"displayName": "deal_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "entity",
"displayName": "entity",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
}
]
},
"options": {
"waitForSubWorkflow": true
}
},
"onError": "continueRegularOutput"
},
{
"id": "e2199d34-d1ab-4df3-a8a4-97cab80f518c",
"name": "One Ticket at a Time",
@@ -826,6 +1013,17 @@
"options": {}
}
},
{
"id": "874e599e-598d-490b-95e2-25c0bb46a6c9",
"name": "No Invoice Needed",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
848,
33584
],
"parameters": {}
},
{
"id": "1eef55e0-d056-4853-9d30-cedbfdf36753",
"name": "Mark Failed1",
@@ -2381,6 +2579,75 @@
]
},
"Tag Ticket Reviewed": {
"main": [
[
{
"node": "New Deal Invoice Gate",
"type": "main",
"index": 0
}
]
]
},
"New Deal Invoice Gate": {
"main": [
[
{
"node": "Invoice Candidate?",
"type": "main",
"index": 0
}
]
]
},
"Invoice Candidate?": {
"main": [
[
{
"node": "Resolve Billing Entity",
"type": "main",
"index": 0
}
],
[
{
"node": "No Invoice Needed",
"type": "main",
"index": 0
}
]
]
},
"Resolve Billing Entity": {
"main": [
[
{
"node": "Invoiceable Entity?",
"type": "main",
"index": 0
}
]
]
},
"Invoiceable Entity?": {
"main": [
[
{
"node": "Run InvoiceBot For Ticket",
"type": "main",
"index": 0
}
],
[
{
"node": "No Invoice Needed",
"type": "main",
"index": 0
}
]
]
},
"Run InvoiceBot For Ticket": {
"main": [
[
{
@@ -2403,6 +2670,17 @@
]
]
},
"No Invoice Needed": {
"main": [
[
{
"node": "One Ticket at a Time",
"type": "main",
"index": 0
}
]
]
},
"Mark Failed1": {
"main": [
[
@@ -2912,7 +3190,7 @@
}
],
"activeVersion": {
"versionId": "16d723dc-88d5-44c6-a4aa-46d052ca141a",
"versionId": "f2818a1f-3067-4c99-820d-e231e04f3244",
"workflowId": "bjH659Q8VTSEpAGw",
"nodes": [
{
@@ -3719,6 +3997,193 @@
}
}
},
{
"id": "6e4ab4df-2386-44d9-855e-18545b066364",
"name": "New Deal Invoice Gate",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-48,
33296
],
"parameters": {
"jsCode": "// DETERMINISTIC selection gate for InvoiceBot. This used to live inside the\n// InvoiceBot agent prompt, where the model re-interpreted it every 5 minutes.\n// It is code now, so the rule cannot drift.\n//\n// A ticket is an invoicing candidate only when its SUBJECT contains BOTH\n// \"closed won\" AND \"new deal\" (case-insensitive), and it is still actionable.\n// Anything else passes through untouched.\n//\n// Read from the source nodes explicitly: the preceding Freshdesk tag update\n// returns an API response, not the ticket.\nconst t = $('One Ticket at a Time').item.json;\nconst subject = String(t.subject || '');\nconst s = subject.toLowerCase();\n\nconst hasClosedWon = s.includes('closed won');\nconst hasNewDeal = s.includes('new deal');\n\n// InvoiceBot files its own exception tickets with this prefix. They must never\n// be fed back in as deals to invoice.\nconst isBotException = /invoicebot exception/i.test(subject) || /^new_deal_invoice/i.test(subject);\n\nlet dealId = '';\ntry { dealId = String($('Extract Deal ID').item.json.deal_id_hint || ''); } catch (e) {}\n\nconst clientName = String(t.client_name || '');\n\nconst isCandidate = hasClosedWon && hasNewDeal && !isBotException;\n\nconsole.log('invoice gate: ticket=' + t.ticket_id + ' closedWon=' + hasClosedWon + ' newDeal=' + hasNewDeal + ' botException=' + isBotException + ' candidate=' + isCandidate);\n\nreturn [{ json: {\n ticket_id: String(t.ticket_id || ''),\n ticket_subject: subject,\n client_name: clientName,\n deal_id: dealId,\n is_invoice_candidate: isCandidate\n} }];"
}
},
{
"id": "cf7291e1-2515-4cd3-b565-5a657399cfd7",
"name": "Invoice Candidate?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
176,
33296
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose",
"version": 2
},
"conditions": [
{
"id": "is-candidate",
"leftValue": "={{ $json.is_invoice_candidate }}",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"looseTypeValidation": true,
"options": {}
}
},
{
"id": "3c286294-670c-48d0-854d-362b347f5b64",
"name": "Resolve Billing Entity",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
400,
33232
],
"parameters": {
"operation": "executeQuery",
"query": "-- Resolve the legal entity to invoice under from the ingested contract.\n-- Prefer the deal id (filenames always contain it); fall back to client name.\nSELECT entity, client_name, filename\nFROM contracts\nWHERE ($1 <> '' AND filename ILIKE '%' || $1 || '%')\n OR ($1 = '' AND $2 <> '' AND client_name ILIKE '%' || $2 || '%')\n AND entity IS NOT NULL AND entity <> ''\nORDER BY effective_date DESC NULLS LAST, filename ASC\nLIMIT 1",
"options": {
"queryReplacement": "={{ [$json.deal_id, $json.client_name] }}"
}
},
"credentials": {
"postgres": {
"id": "NoPrLWbqySMMmIaI",
"name": "Postgres n8n-quickbooks"
}
},
"alwaysOutputData": true
},
{
"id": "5e395973-d37c-4379-b88e-71f20236f893",
"name": "Invoiceable Entity?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
624,
33232
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "loose",
"version": 2
},
"conditions": [
{
"id": "entity-supported",
"leftValue": "={{ ['MUS','MMX','MSAG'].includes(String($json.entity || '').trim().toUpperCase()) }}",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"looseTypeValidation": true,
"options": {}
}
},
{
"id": "a1bb6750-3fc4-489d-b998-9b41eaa7e759",
"name": "Run InvoiceBot For Ticket",
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1.2,
"position": [
848,
33392
],
"parameters": {
"source": "database",
"workflowId": {
"__rl": true,
"mode": "id",
"value": "ShZpx3whvS8ZIldl",
"cachedResultName": "InvoiceBot"
},
"mode": "each",
"workflowInputs": {
"mappingMode": "defineBelow",
"value": {
"ticket_id": "={{ $('New Deal Invoice Gate').item.json.ticket_id }}",
"ticket_subject": "={{ $('New Deal Invoice Gate').item.json.ticket_subject }}",
"client_name": "={{ $json.client_name || $('New Deal Invoice Gate').item.json.client_name }}",
"deal_id": "={{ $('New Deal Invoice Gate').item.json.deal_id }}",
"entity": "={{ String($json.entity).trim().toUpperCase() }}"
},
"matchingColumns": [],
"schema": [
{
"id": "ticket_id",
"displayName": "ticket_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "ticket_subject",
"displayName": "ticket_subject",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "client_name",
"displayName": "client_name",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "deal_id",
"displayName": "deal_id",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "entity",
"displayName": "entity",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
}
]
},
"options": {
"waitForSubWorkflow": true
}
},
"onError": "continueRegularOutput"
},
{
"id": "e2199d34-d1ab-4df3-a8a4-97cab80f518c",
"name": "One Ticket at a Time",
@@ -3732,6 +4197,17 @@
"options": {}
}
},
{
"id": "874e599e-598d-490b-95e2-25c0bb46a6c9",
"name": "No Invoice Needed",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
848,
33584
],
"parameters": {}
},
{
"id": "1eef55e0-d056-4853-9d30-cedbfdf36753",
"name": "Mark Failed1",
@@ -5287,6 +5763,75 @@
]
},
"Tag Ticket Reviewed": {
"main": [
[
{
"node": "New Deal Invoice Gate",
"type": "main",
"index": 0
}
]
]
},
"New Deal Invoice Gate": {
"main": [
[
{
"node": "Invoice Candidate?",
"type": "main",
"index": 0
}
]
]
},
"Invoice Candidate?": {
"main": [
[
{
"node": "Resolve Billing Entity",
"type": "main",
"index": 0
}
],
[
{
"node": "No Invoice Needed",
"type": "main",
"index": 0
}
]
]
},
"Resolve Billing Entity": {
"main": [
[
{
"node": "Invoiceable Entity?",
"type": "main",
"index": 0
}
]
]
},
"Invoiceable Entity?": {
"main": [
[
{
"node": "Run InvoiceBot For Ticket",
"type": "main",
"index": 0
}
],
[
{
"node": "No Invoice Needed",
"type": "main",
"index": 0
}
]
]
},
"Run InvoiceBot For Ticket": {
"main": [
[
{
@@ -5309,6 +5854,17 @@
]
]
},
"No Invoice Needed": {
"main": [
[
{
"node": "One Ticket at a Time",
"type": "main",
"index": 0
}
]
]
},
"Mark Failed1": {
"main": [
[
@@ -5782,10 +6338,10 @@
},
"nodeGroups": [],
"authors": "Michael Nolan (with n8n Assistant)",
"name": "Version 16d723dc",
"description": "",
"name": null,
"description": null,
"autosaved": false,
"createdAt": "2026-10-28T20:15:44.855Z",
"updatedAt": "2026-10-28T20:32:11.997Z"
"createdAt": "2026-11-03T15:44:28.752Z",
"updatedAt": "2026-11-03T15:44:28.752Z"
}
}