semillero-special-hotel/n8n/sales_import_workflow.json
gabogg 41fb0d0d75 feat: implement phase 5 settlements and i18n support
- Add English/Spanish translation system for UI pages
- Add bilingual AI audit notes using translation LLM chains in n8n
- Support zero-trust Docker routing to dev stack via internal hostnames
- Quiet down Next.js database query and middleware logging in test runs
2026-06-12 19:00:46 +00:00

415 lines
13 KiB
JSON

{
"name": "Sales Data Import & Validation",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "calculate-commissions",
"responseMode": "responseNode",
"options": {
"rawBody": false
}
},
"id": "Webhook-Node-1",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
100,
300
]
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ ($node[\"Webhook\"].json[\"headers\"][\"x-forwarded-uri\"] || \"\").includes(\"webhook-test\") || ($node[\"Webhook\"].json[\"headers\"][\"x-semillero-env\"] || \"\").includes(\"dev\") }}",
"value2": true
}
]
}
},
"id": "If-Node-1",
"name": "Is Test/Dev Mode?",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
300,
300
]
},
{
"parameters": {
"values": {
"string": [
{
"name": "appUrl",
"value": "__APP_DEV_INTERNAL_URL__"
},
{
"name": "signature",
"value": "__N8N_WEBHOOK_SECRET_DEV__"
}
]
},
"options": {}
},
"id": "Set-Dev-Env",
"name": "Set Dev Environment",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [
500,
200
]
},
{
"parameters": {
"values": {
"string": [
{
"name": "appUrl",
"value": "__APP_PROD_INTERNAL_URL__"
},
{
"name": "signature",
"value": "__N8N_WEBHOOK_SECRET__"
}
]
},
"options": {}
},
"id": "Set-Prod-Env",
"name": "Set Prod Environment",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [
500,
400
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Set Dev Environment').isExecuted ? $('Set Dev Environment').item.json.appUrl : $('Set Prod Environment').item.json.appUrl }}/api/n8n/validate-sales",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "x-n8n-signature",
"value": "={{ $('Set Dev Environment').isExecuted ? $('Set Dev Environment').item.json.signature : $('Set Prod Environment').item.json.signature }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"sales\": {{ JSON.stringify($node[\"Webhook\"].json[\"body\"][\"sales\"]) }}\n}",
"options": {}
},
"id": "Http-Request-Validate",
"name": "HTTP Request: validate-sales",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
700,
300
]
},
{
"parameters": {
"promptType": "define",
"text": "=Verify the following sales records for anomalies. Return a JSON object containing a \"sales\" array, matching the input structure, but adding the fields \"isAnomaly\" (boolean) and \"flaggedReason\" (string or null) for each record.\nIf a record has isValid: false, set isAnomaly to true and flaggedReason to invalidReason.\nIf the amount is greater than the threshold, set isAnomaly to true and flaggedReason to \"Sales amount deviates abnormally from collaborator monthly average\".\nIf the amount is extremely high (e.g. >1000000), set isAnomaly to true and flaggedReason to \"Sales amount exceeds normal threshold limits (>1M)\".\nOtherwise, set isAnomaly to false and flaggedReason to null.\n\nInput sales data:\n{{ JSON.stringify($node[\"HTTP Request: validate-sales\"].json.validationResults) }}",
"hasOutputParser": true,
"needsFallback": true,
"options": {}
},
"id": "LLM-Chain-Anomaly",
"name": "LLM Chain: Anomaly Detection",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"typeVersion": 1.9,
"position": [
900,
300
]
},
{
"parameters": {
"options": {}
},
"id": "DeepSeek-Model-Node",
"name": "Primary Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatDeepSeek",
"typeVersion": 1,
"position": [
750,
480
],
"credentials": {
"deepSeekApi": {
"id": "YbGKBhQ9rlUebE4F",
"name": "Semillero2_Primary_deepSeekApi"
}
}
},
{
"parameters": {
"options": {}
},
"id": "Google-Gemini-Model-Node",
"name": "Fallback Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1,
"position": [
900,
480
],
"credentials": {
"googlePalmApi": {
"id": "1Vz05qteUH9kLf7Z",
"name": "Google Gemini(PaLM) Api account"
}
}
},
{
"parameters": {
"jsonSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"sales\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"username\": { \"type\": \"string\" },\n \"hotelCode\": { \"type\": \"string\" },\n \"period\": { \"type\": \"string\" },\n \"amount\": { \"type\": \"number\" },\n \"salesCount\": { \"type\": \"number\" },\n \"transactionId\": { \"type\": \"string\" },\n \"isAnomaly\": { \"type\": \"boolean\" },\n \"flaggedReason\": { \"type\": \"string\" }\n },\n \"required\": [\"username\", \"hotelCode\", \"period\", \"amount\", \"salesCount\", \"isAnomaly\"]\n }\n }\n },\n \"required\": [\"sales\"]\n}"
},
"id": "Structured-Output-Parser-Node",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"typeVersion": 1,
"position": [
1050,
480
]
},
{
"parameters": {
"promptType": "define",
"text": "=Translate the flaggedReason for each record in the sales array into a localized JSON object containing \"en\" and \"es\" keys. If flaggedReason is NOT null and NOT empty, you MUST translate it to Spanish for the \"es\" key, and keep the original English value for the \"en\" key (both must be non-empty strings). Only if flaggedReason is null or empty, set both \"en\" and \"es\" to null.\n\nInput sales data:\n{{ JSON.stringify($node[\"LLM Chain: Anomaly Detection\"].json[\"sales\"]) }}",
"hasOutputParser": true,
"needsFallback": true,
"options": {}
},
"id": "LLM-Chain-Translation",
"name": "LLM Chain: Translation",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"typeVersion": 1.9,
"position": [
1100,
300
]
},
{
"parameters": {
"jsonSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"sales\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"username\": { \"type\": \"string\" },\n \"hotelCode\": { \"type\": \"string\" },\n \"period\": { \"type\": \"string\" },\n \"amount\": { \"type\": \"number\" },\n \"salesCount\": { \"type\": \"number\" },\n \"transactionId\": { \"type\": \"string\", \"nullable\": true },\n \"isAnomaly\": { \"type\": \"boolean\" },\n \"flaggedReason\": {\n \"type\": \"object\",\n \"properties\": {\n \"en\": { \"type\": \"string\", \"nullable\": true },\n \"es\": { \"type\": \"string\", \"nullable\": true }\n },\n \"required\": [\"en\", \"es\"]\n }\n },\n \"required\": [\"username\", \"hotelCode\", \"period\", \"amount\", \"salesCount\", \"isAnomaly\"]\n }\n }\n },\n \"required\": [\"sales\"]\n}"
},
"id": "Structured-Output-Parser-Translation",
"name": "Structured Output Parser (Translation)",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"typeVersion": 1,
"position": [
1200,
480
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $('Set Dev Environment').isExecuted ? $('Set Dev Environment').item.json.appUrl : $('Set Prod Environment').item.json.appUrl }}/api/sales/batch-save",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "x-n8n-signature",
"value": "={{ $('Set Dev Environment').isExecuted ? $('Set Dev Environment').item.json.signature : $('Set Prod Environment').item.json.signature }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"idempotencyKey\": \"{{ $node[\"Webhook\"].json[\"body\"][\"idempotencyKey\"] }}\",\n \"uploaderId\": {{ $node[\"Webhook\"].json[\"body\"][\"uploaderId\"] }},\n \"sales\": {{ JSON.stringify($node[\"LLM Chain: Translation\"].json[\"sales\"]) }}\n}",
"options": {}
},
"id": "Http-Request-1",
"name": "Callback batch-save",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
1350,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\n \"success\": true,\n \"code\": \"IMPORT_ACCEPTED\",\n \"metadata\": {\n \"idempotencyKey\": \"{{ $node[\"Webhook\"].json[\"body\"][\"idempotencyKey\"] }}\",\n \"status\": \"PROCESSING\"\n }\n}"
},
"id": "Respond-To-Webhook",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
450,
550
]
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Is Test/Dev Mode?",
"type": "main",
"index": 0
},
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Is Test/Dev Mode?": {
"main": [
[
{
"node": "Set Dev Environment",
"type": "main",
"index": 0
}
],
[
{
"node": "Set Prod Environment",
"type": "main",
"index": 0
}
]
]
},
"Set Dev Environment": {
"main": [
[
{
"node": "HTTP Request: validate-sales",
"type": "main",
"index": 0
}
]
]
},
"Set Prod Environment": {
"main": [
[
{
"node": "HTTP Request: validate-sales",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request: validate-sales": {
"main": [
[
{
"node": "LLM Chain: Anomaly Detection",
"type": "main",
"index": 0
}
]
]
},
"Primary Chat Model": {
"ai_languageModel": [
[
{
"node": "LLM Chain: Anomaly Detection",
"type": "ai_languageModel",
"index": 0
},
{
"node": "LLM Chain: Translation",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Fallback Chat Model": {
"ai_languageModel": [
[
{
"node": "LLM Chain: Anomaly Detection",
"type": "ai_languageModel",
"index": 1
},
{
"node": "LLM Chain: Translation",
"type": "ai_languageModel",
"index": 1
}
]
]
},
"Structured Output Parser": {
"outputParser": [
[
{
"node": "LLM Chain: Anomaly Detection",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Structured Output Parser (Translation)": {
"outputParser": [
[
{
"node": "LLM Chain: Translation",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"LLM Chain: Anomaly Detection": {
"main": [
[
{
"node": "LLM Chain: Translation",
"type": "main",
"index": 0
}
]
]
},
"LLM Chain: Translation": {
"main": [
[
{
"node": "Callback batch-save",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {},
"id": "sales-import-workflow"
}