WFDASH-WEBAPP/n8n_workfows/SNAPSHOT-WFDASH-v8-from-live-2026-08-21/paqlZICDbXbmY61V.json
Dave c3b452dbc4 feat(orders): enhance order handling with email_message_id deduplication and displayContactName utility
- Added support for deduplication of orders based on the `email_message_id`, preventing duplicate entries during email intake.
- Introduced the `displayContactName` utility to sanitize and format contact names, improving the display of order details by removing extraneous whitespace.
- Updated relevant order-related components to utilize the new utility for consistent contact name rendering.
- Enhanced tests to cover the new deduplication logic and the functionality of the `displayContactName` utility, ensuring robust behavior in various scenarios.
2026-08-21 19:18:02 +02:00

1 line
No EOL
39 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{"updatedAt":"2026-08-18T07:57:53.259Z","createdAt":"2026-08-10T21:43:03.644Z","id":"paqlZICDbXbmY61V","name":"WFDASH — Populate Item Intel (Live)","description":"WFDASH — Populate Item Intel (Live)","active":true,"isArchived":false,"nodes":[{"parameters":{},"type":"n8n-nodes-base.manualTrigger","typeVersion":1,"position":[-720,-16],"id":"5fcddf3e-573e-474a-a688-5272b188c0e6","name":"When clicking ‘Execute workflow’"},{"parameters":{"promptType":"define","text":"=Analyze the following JSON. I am looking for items where the description, name, or equivalent field is a match or high-confidence product match for: {{ $json.description }}\n\nCRITICAL MATCHING RULES:\n- Include exact matches.\n- Include close semantic variations of the exact same pack size (e.g., if targeting \"20L\", include matches for \"20 LT\" or \"20 Litre\").\n- STRIKTLY EXCLUDE different pack sizes or bulk configurations (e.g., if targeting \"20L\", do NOT match \"210L\", \"1000L\", \"20X500ML\", or \"12X1LT\").\n- Ignore minor specification differences like \"SF/CF4\" as long as the base product and pack size are the exact same.\n\nReturn a valid JSON object containing ONLY the arrays and the specific items that match this item based on the rules above.\n\nCRITICAL INSTRUCTIONS:\n- Output ONLY raw JSON. \n- DO NOT wrap the output in markdown blocks.\n- DO NOT include backticks (```).\n- DO NOT write any explanations, greetings, or conversational text. \n- If you write anything other than the raw JSON object, the system will break.\n\nData to filter:\n{{ JSON.stringify($json.ai_item_insights, null, 2) }}","hasOutputParser":true,"needsFallback":true,"options":{}},"type":"@n8n/n8n-nodes-langchain.agent","typeVersion":3.1,"position":[112,-176],"id":"96b4f602-97d6-4aec-a920-ba2e09f5c4f3","name":"AI Agent"},{"parameters":{"model":"MiniMax-M2.1","options":{}},"type":"@n8n/n8n-nodes-langchain.lmChatMinimax","typeVersion":1,"position":[80,64],"id":"05947ad8-ec67-49f2-aeef-68bd61a82b4d","name":"MiniMax Chat Model","credentials":{"minimaxApi":{"id":"kn97KHCrkyTm3v2g","name":"MiniMax account"}}},{"parameters":{"schemaType":"manual","inputSchema":"{\n \"type\": \"object\",\n \"properties\": {\n \"stock_list\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the stock list. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"supplier_history\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the supplier history. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"price_list\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the price list. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"recent_quote\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the recent quotes. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"recent_order\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the recent orders. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n }\n },\n \"required\": [\n \"stock_list\",\n \"supplier_history\"\n ]\n}","autoFix":true},"type":"@n8n/n8n-nodes-langchain.outputParserStructured","typeVersion":1.3,"position":[336,64],"id":"3548a5a7-25b8-4a4e-8e09-60a5282c6022","name":"Structured Output Parser"},{"parameters":{"model":{"__rl":true,"value":"google/gemma-4-e2b","mode":"list","cachedResultName":"google/gemma-4-e2b"},"responsesApiEnabled":false,"options":{}},"type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","typeVersion":1.3,"position":[208,64],"id":"b566b192-2cfe-4f22-8ca3-863ae295d4c4","name":"OpenAI Chat Model1","credentials":{"openAiApi":{"id":"LcoRpE8OF7QrpByT","name":"OpenAI account"}}},{"parameters":{"model":"MiniMax-M2.1","options":{}},"type":"@n8n/n8n-nodes-langchain.lmChatMinimax","typeVersion":1,"position":[416,272],"id":"19f05b98-850b-4bc6-9ffb-3681a708584d","name":"MiniMax Chat Model1","credentials":{"minimaxApi":{"id":"kn97KHCrkyTm3v2g","name":"MiniMax account"}}},{"parameters":{"resource":"quote_items","operation":"update","elementId":"={{ $('Search quote_items').item.json.id }}","parameters":{"allElements":false,"elementsPerPage":1},"fields":{"assignments":[{"id":"44822f7e-b731-463b-a1f5-d46484853e11","name":"ai_item_insights","value":"={{ $json.ai_item_insights }}","type":"object"}]},"requestOptions":{}},"type":"n8n-nodes-pocketbase.pocketbaseHttp","typeVersion":1,"position":[912,0],"id":"6c8e5ae6-b56b-4468-afe4-947e13274f0e","name":"Update quote_items","credentials":{"pocketbaseHttpApi":{"id":"hLwB1QPIJEWsuVyW","name":"PocketBase HTTP account"}}},{"parameters":{"jsCode":"const allSearch = $('Search quote_items').all();\nconsole.log(\"Search returned \" + allSearch.length + \" items\");\nif (allSearch.length > 0) {\n console.log(\"First item keys: \" + Object.keys(allSearch[0]).join(\", \"));\n console.log(\"First item id: \" + allSearch[0].id);\n console.log(\"First item description: \" + allSearch[0].description);\n}\n\nconst items = $('Search quote_items').all();\nconst llmOutput = ($input.all()[0] && $input.all()[0].json && $input.all()[0].json.output) || {\n stock_list: [],\n supplier_history: [],\n price_list: [],\n recent_quote: [],\n recent_order: [],\n};\n\nif (!items || items.length === 0) {\n console.log(\"WARN: no items returned from Search\");\n return [{ json: { _status: \"no_items\" } }];\n}\n\nconst src = items[0];\nconsole.log(\"Processing item: \" + (src.id || \"UNKNOWN\") + \" \" + (src.description || \"\"));\n\nreturn items.map((src) => ({\n json: {\n ai_item_insights: {\n item: {\n id: src.id || \"\",\n collection: src.collectionName || src.collectionId || \"quote_items\",\n description: src.description || \"\",\n sku: src.sku || \"\",\n quantity: Number(src.quantity) || 0,\n },\n stock_list: (llmOutput.stock_list || []).filter((r) => r && r.stock_item_id),\n supplier_history: (llmOutput.supplier_history || []).filter((r) => r && r.supplier_id),\n price_list: (llmOutput.price_list || []).filter((r) => r && r.sku),\n recent_quote: (llmOutput.recent_quote || []).filter((r) => r && r.quote_item_id),\n recent_order: (llmOutput.recent_order || []).filter((r) => r && r.order_item_id),\n verified: {\n at: new Date().toISOString(),\n by: \"n8n:ai-verifier\",\n removed_count: Number(llmOutput.removed_count) || 0,\n notes: llmOutput.notes || \"\",\n },\n },\n },\n}));"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[688,-176],"id":"835e218b-b10b-4f3e-a39d-5ea76af364b9","name":"Code in JavaScript"},{"parameters":{"resource":"quote_items","parameters":{"allElements":true,"elementsPerPage":1,"filter":"=ai_item_insights !~ 'verified' && is_processed = false"},"requestOptions":{}},"type":"n8n-nodes-pocketbase.pocketbaseHttp","typeVersion":1,"position":[-384,0],"id":"96180b56-34a5-4778-aff3-0a219fbc7051","name":"Search quote_items","credentials":{"pocketbaseHttpApi":{"id":"hLwB1QPIJEWsuVyW","name":"PocketBase HTTP account"}}},{"parameters":{"method":"POST","url":"=https://wfdash.apphub.co.za/api/v1/items/quote_items/{{$json.id}}/intel/refresh","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Content-Type","value":"application/json"}]},"sendBody":true,"specifyBody":"json","jsonBody":"{\n \"dry_run\": false\n}","options":{"timeout":30000}},"type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[176,-720],"id":"26b77edc-8f2b-4022-a481-bc022cbd2645","name":"Populate Intel"},{"parameters":{"rule":{"interval":[{"field":"minutes","minutesInterval":10}]}},"type":"n8n-nodes-base.scheduleTrigger","typeVersion":1.3,"position":[-688,-304],"id":"41db390c-fdcf-44e0-8e57-983f54858ff6","name":"Schedule Trigger"},{"parameters":{"resource":"quote_items","parameters":{"allElements":true,"elementsPerPage":100,"filter":"is_processed = false && ai_item_insights !~ 'verified'"},"requestOptions":{}},"type":"n8n-nodes-pocketbase.pocketbaseHttp","typeVersion":1,"position":[-416,-736],"id":"a8c8d1dc-bf87-4629-bd04-07d22a768753","name":"Search quote_items1","credentials":{"pocketbaseHttpApi":{"id":"hLwB1QPIJEWsuVyW","name":"PocketBase HTTP account"}}},{"parameters":{"options":{}},"type":"n8n-nodes-base.splitInBatches","typeVersion":3,"position":[-112,-736],"id":"cb6ab626-c03e-4447-b4c7-96e628cf8c6d","name":"Loop Over Items"},{"parameters":{"options":{}},"type":"n8n-nodes-base.splitInBatches","typeVersion":3,"position":[-160,0],"id":"13119c03-aecd-4185-b525-5768842b43e2","name":"Loop Over Items1"},{"parameters":{"resource":"order_items","parameters":{"allElements":true,"elementsPerPage":100,"filter":"item_status = 'pending' && ai_item_insights !~ 'verified'"},"requestOptions":{}},"type":"n8n-nodes-pocketbase.pocketbaseHttp","typeVersion":1,"position":[-416,-448],"id":"c0546ab5-22e7-4a2d-b411-74f12cdf9de4","name":"Search order_items","credentials":{"pocketbaseHttpApi":{"id":"hLwB1QPIJEWsuVyW","name":"PocketBase HTTP account"}}},{"parameters":{"method":"POST","url":"=https://wfdash.apphub.co.za/api/v1/items/order_items/{{$json.id}}/intel/refresh","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Content-Type","value":"application/json"}]},"sendBody":true,"specifyBody":"json","jsonBody":"{\n \"dry_run\": false\n}","options":{"timeout":30000}},"type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[176,-432],"id":"c47af114-5528-403f-b9ff-bd315df13188","name":"Populate Intel1"},{"parameters":{"options":{}},"type":"n8n-nodes-base.splitInBatches","typeVersion":3,"position":[-112,-448],"id":"e6fcf475-246e-48a8-a0b4-4b54a0af0e9f","name":"Loop Over Items2"},{"parameters":{"promptType":"define","text":"=Analyze the following JSON. I am looking for items where the description, name, or equivalent field is a match or high-confidence product match for: {{ $json.description }}\n\nCRITICAL MATCHING RULES:\n- Include exact matches.\n- Include close semantic variations of the exact same pack size (e.g., if targeting \"20L\", include matches for \"20 LT\" or \"20 Litre\").\n- STRIKTLY EXCLUDE different pack sizes or bulk configurations (e.g., if targeting \"20L\", do NOT match \"210L\", \"1000L\", \"20X500ML\", or \"12X1LT\").\n- Ignore minor specification differences like \"SF/CF4\" as long as the base product and pack size are the exact same.\n\nReturn a valid JSON object containing ONLY the arrays and the specific items that match this item based on the rules above.\n\nCRITICAL INSTRUCTIONS:\n- Output ONLY raw JSON. \n- DO NOT wrap the output in markdown blocks.\n- DO NOT include backticks (```).\n- DO NOT write any explanations, greetings, or conversational text. \n- If you write anything other than the raw JSON object, the system will break.\n\nData to filter:\n{{ JSON.stringify($json.ai_item_insights, null, 2) }}","hasOutputParser":true,"needsFallback":true,"options":{}},"type":"@n8n/n8n-nodes-langchain.agent","typeVersion":3.1,"position":[144,464],"id":"523116c3-ad4b-4380-bffc-0aba1d9399c8","name":"AI Agent1"},{"parameters":{"model":"MiniMax-M2.1","options":{}},"type":"@n8n/n8n-nodes-langchain.lmChatMinimax","typeVersion":1,"position":[64,688],"id":"4cada161-d25e-491e-8dac-f2f313671452","name":"MiniMax Chat Model2","credentials":{"minimaxApi":{"id":"kn97KHCrkyTm3v2g","name":"MiniMax account"}}},{"parameters":{"schemaType":"manual","inputSchema":"{\n \"type\": \"object\",\n \"properties\": {\n \"stock_list\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the stock list. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"supplier_history\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the supplier history. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"price_list\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the price list. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"recent_quote\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the recent quotes. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"recent_order\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the recent orders. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n }\n },\n \"required\": [\n \"stock_list\",\n \"supplier_history\"\n ]\n}","autoFix":true},"type":"@n8n/n8n-nodes-langchain.outputParserStructured","typeVersion":1.3,"position":[368,704],"id":"3d83d84d-9ad3-4813-85d2-4a5afa03565e","name":"Structured Output Parser1"},{"parameters":{"model":{"__rl":true,"value":"google/gemma-4-e2b","mode":"list","cachedResultName":"google/gemma-4-e2b"},"responsesApiEnabled":false,"options":{}},"type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","typeVersion":1.3,"position":[240,704],"id":"ffab19be-af58-48d6-8d16-809581169864","name":"OpenAI Chat Model","credentials":{"openAiApi":{"id":"LcoRpE8OF7QrpByT","name":"OpenAI account"}}},{"parameters":{"model":"MiniMax-M2.1","options":{}},"type":"@n8n/n8n-nodes-langchain.lmChatMinimax","typeVersion":1,"position":[448,912],"id":"e6743555-b40b-4f00-bed4-20957679c394","name":"MiniMax Chat Model3","credentials":{"minimaxApi":{"id":"kn97KHCrkyTm3v2g","name":"MiniMax account"}}},{"parameters":{"jsCode":"const allSearch = $('Search order_items1').all();\nconsole.log(\"Search returned \" + allSearch.length + \" items\");\nif (allSearch.length > 0) {\n console.log(\"First item keys: \" + Object.keys(allSearch[0]).join(\", \"));\n console.log(\"First item id: \" + allSearch[0].id);\n console.log(\"First item description: \" + allSearch[0].description);\n}\n\nconst items = $('Search order_items1').all();\nconst llmOutput = ($input.all()[0] && $input.all()[0].json && $input.all()[0].json.output) || {\n stock_list: [],\n supplier_history: [],\n price_list: [],\n recent_quote: [],\n recent_order: [],\n};\n\nif (!items || items.length === 0) {\n console.log(\"WARN: no items returned from Search\");\n return [{ json: { _status: \"no_items\" } }];\n}\n\nconst src = items[0];\nconsole.log(\"Processing item: \" + (src.id || \"UNKNOWN\") + \" \" + (src.description || \"\"));\n\nreturn items.map((src) => ({\n json: {\n ai_item_insights: {\n item: {\n id: src.id || \"\",\n collection: src.collectionName || src.collectionId || \"quote_items\",\n description: src.description || \"\",\n sku: src.sku || \"\",\n quantity: Number(src.quantity) || 0,\n },\n stock_list: (llmOutput.stock_list || []).filter((r) => r && r.stock_item_id),\n supplier_history: (llmOutput.supplier_history || []).filter((r) => r && r.supplier_id),\n price_list: (llmOutput.price_list || []).filter((r) => r && r.sku),\n recent_quote: (llmOutput.recent_quote || []).filter((r) => r && r.quote_item_id),\n recent_order: (llmOutput.recent_order || []).filter((r) => r && r.order_item_id),\n verified: {\n at: new Date().toISOString(),\n by: \"n8n:ai-verifier\",\n removed_count: Number(llmOutput.removed_count) || 0,\n notes: llmOutput.notes || \"\",\n },\n },\n },\n}));"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[720,464],"id":"8e2ed6ba-0d10-4557-88da-69de165c1833","name":"Code in JavaScript1"},{"parameters":{"options":{}},"type":"n8n-nodes-base.splitInBatches","typeVersion":3,"position":[-128,640],"id":"22056cfa-0380-4f1b-93f7-9aa6370ffc1f","name":"Loop Over Items3"},{"parameters":{"resource":"order_items","parameters":{"allElements":true,"elementsPerPage":1,"filter":"=ai_item_insights !~ 'verified' && item_status = 'pending'"},"requestOptions":{}},"type":"n8n-nodes-pocketbase.pocketbaseHttp","typeVersion":1,"position":[-352,640],"id":"5689e9e2-0e6c-4be0-ac37-cbb8385ce366","name":"Search order_items1","credentials":{"pocketbaseHttpApi":{"id":"hLwB1QPIJEWsuVyW","name":"PocketBase HTTP account"}}},{"parameters":{"resource":"order_items","operation":"update","elementId":"={{ $('Search order_items1').item.json.id }}","parameters":{"allElements":false,"elementsPerPage":1},"fields":{"assignments":[{"id":"44822f7e-b731-463b-a1f5-d46484853e11","name":"ai_item_insights","value":"={{ $json.ai_item_insights }}","type":"object"}]},"requestOptions":{}},"type":"n8n-nodes-pocketbase.pocketbaseHttp","typeVersion":1,"position":[944,640],"id":"c1fb7c3a-8486-45b6-8471-4ace2c17dd81","name":"Update order_items","credentials":{"pocketbaseHttpApi":{"id":"hLwB1QPIJEWsuVyW","name":"PocketBase HTTP account"}}}],"connections":{"When clicking ‘Execute workflow’":{"main":[[{"node":"Search quote_items","type":"main","index":0}]]},"MiniMax Chat Model":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":0}]]},"AI Agent":{"main":[[{"node":"Code in JavaScript","type":"main","index":0}]]},"Structured Output Parser":{"ai_outputParser":[[{"node":"AI Agent","type":"ai_outputParser","index":0}]]},"OpenAI Chat Model1":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":1}]]},"MiniMax Chat Model1":{"ai_languageModel":[[{"node":"Structured Output Parser","type":"ai_languageModel","index":0}]]},"Code in JavaScript":{"main":[[{"node":"Update quote_items","type":"main","index":0}]]},"Search quote_items":{"main":[[{"node":"Loop Over Items1","type":"main","index":0}]]},"Schedule Trigger":{"main":[[{"node":"Search quote_items1","type":"main","index":0},{"node":"Search quote_items","type":"main","index":0},{"node":"Search order_items","type":"main","index":0},{"node":"Search order_items1","type":"main","index":0}]]},"Search quote_items1":{"main":[[{"node":"Loop Over Items","type":"main","index":0}]]},"Loop Over Items":{"main":[[],[{"node":"Populate Intel","type":"main","index":0}]]},"Populate Intel":{"main":[[{"node":"Loop Over Items","type":"main","index":0}]]},"Loop Over Items1":{"main":[[],[{"node":"AI Agent","type":"main","index":0}]]},"Update quote_items":{"main":[[{"node":"Loop Over Items1","type":"main","index":0}]]},"Search order_items":{"main":[[{"node":"Loop Over Items2","type":"main","index":0}]]},"Populate Intel1":{"main":[[{"node":"Loop Over Items2","type":"main","index":0}]]},"Loop Over Items2":{"main":[[],[{"node":"Populate Intel1","type":"main","index":0}]]},"AI Agent1":{"main":[[{"node":"Code in JavaScript1","type":"main","index":0}]]},"MiniMax Chat Model2":{"ai_languageModel":[[{"node":"AI Agent1","type":"ai_languageModel","index":0}]]},"Structured Output Parser1":{"ai_outputParser":[[{"node":"AI Agent1","type":"ai_outputParser","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"AI Agent1","type":"ai_languageModel","index":1}]]},"MiniMax Chat Model3":{"ai_languageModel":[[{"node":"Structured Output Parser1","type":"ai_languageModel","index":0}]]},"Code in JavaScript1":{"main":[[{"node":"Update order_items","type":"main","index":0}]]},"Loop Over Items3":{"main":[[],[{"node":"AI Agent1","type":"main","index":0}]]},"Search order_items1":{"main":[[{"node":"Loop Over Items3","type":"main","index":0}]]},"Update order_items":{"main":[[{"node":"Loop Over Items3","type":"main","index":0}]]}},"settings":{"executionOrder":"v1","binaryMode":"separate","availableInMCP":true},"staticData":{"node:Schedule Trigger":{"recurrenceRules":[null],"recurrenceRuleSignatures":[null]}},"meta":{"templateCredsSetupCompleted":true},"nodeGroups":[],"pinData":{},"versionId":"eab8fa65-84ba-4524-86fd-59fa36225861","activeVersionId":"eab8fa65-84ba-4524-86fd-59fa36225861","versionCounter":292,"triggerCount":1,"sourceWorkflowId":null,"shared":[{"updatedAt":"2026-08-10T21:43:03.644Z","createdAt":"2026-08-10T21:43:03.644Z","role":"workflow:owner","workflowId":"paqlZICDbXbmY61V","projectId":"UhHq8eAZFxiYmQxH","project":{"updatedAt":"2026-06-11T15:00:27.533Z","createdAt":"2026-06-11T14:30:25.543Z","id":"UhHq8eAZFxiYmQxH","name":"David Els <david.els1@outlook.com>","type":"personal","icon":null,"description":null,"customTelemetryTags":[],"creatorId":"4f770df2-bd2f-4436-b153-b27004efc7b6"}}],"tags":[],"activeVersion":{"updatedAt":"2026-08-11T20:38:45.833Z","createdAt":"2026-08-11T12:03:56.052Z","versionId":"eab8fa65-84ba-4524-86fd-59fa36225861","workflowId":"paqlZICDbXbmY61V","nodes":[{"parameters":{},"type":"n8n-nodes-base.manualTrigger","typeVersion":1,"position":[-720,-16],"id":"5fcddf3e-573e-474a-a688-5272b188c0e6","name":"When clicking ‘Execute workflow’"},{"parameters":{"promptType":"define","text":"=Analyze the following JSON. I am looking for items where the description, name, or equivalent field is a match or high-confidence product match for: {{ $json.description }}\n\nCRITICAL MATCHING RULES:\n- Include exact matches.\n- Include close semantic variations of the exact same pack size (e.g., if targeting \"20L\", include matches for \"20 LT\" or \"20 Litre\").\n- STRIKTLY EXCLUDE different pack sizes or bulk configurations (e.g., if targeting \"20L\", do NOT match \"210L\", \"1000L\", \"20X500ML\", or \"12X1LT\").\n- Ignore minor specification differences like \"SF/CF4\" as long as the base product and pack size are the exact same.\n\nReturn a valid JSON object containing ONLY the arrays and the specific items that match this item based on the rules above.\n\nCRITICAL INSTRUCTIONS:\n- Output ONLY raw JSON. \n- DO NOT wrap the output in markdown blocks.\n- DO NOT include backticks (```).\n- DO NOT write any explanations, greetings, or conversational text. \n- If you write anything other than the raw JSON object, the system will break.\n\nData to filter:\n{{ JSON.stringify($json.ai_item_insights, null, 2) }}","hasOutputParser":true,"needsFallback":true,"options":{}},"type":"@n8n/n8n-nodes-langchain.agent","typeVersion":3.1,"position":[112,-176],"id":"96b4f602-97d6-4aec-a920-ba2e09f5c4f3","name":"AI Agent"},{"parameters":{"model":"MiniMax-M2.1","options":{}},"type":"@n8n/n8n-nodes-langchain.lmChatMinimax","typeVersion":1,"position":[80,64],"id":"05947ad8-ec67-49f2-aeef-68bd61a82b4d","name":"MiniMax Chat Model","credentials":{"minimaxApi":{"id":"kn97KHCrkyTm3v2g","name":"MiniMax account"}}},{"parameters":{"schemaType":"manual","inputSchema":"{\n \"type\": \"object\",\n \"properties\": {\n \"stock_list\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the stock list. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"supplier_history\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the supplier history. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"price_list\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the price list. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"recent_quote\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the recent quotes. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"recent_order\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the recent orders. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n }\n },\n \"required\": [\n \"stock_list\",\n \"supplier_history\"\n ]\n}","autoFix":true},"type":"@n8n/n8n-nodes-langchain.outputParserStructured","typeVersion":1.3,"position":[336,64],"id":"3548a5a7-25b8-4a4e-8e09-60a5282c6022","name":"Structured Output Parser"},{"parameters":{"model":{"__rl":true,"value":"google/gemma-4-e2b","mode":"list","cachedResultName":"google/gemma-4-e2b"},"responsesApiEnabled":false,"options":{}},"type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","typeVersion":1.3,"position":[208,64],"id":"b566b192-2cfe-4f22-8ca3-863ae295d4c4","name":"OpenAI Chat Model1","credentials":{"openAiApi":{"id":"LcoRpE8OF7QrpByT","name":"OpenAI account"}}},{"parameters":{"model":"MiniMax-M2.1","options":{}},"type":"@n8n/n8n-nodes-langchain.lmChatMinimax","typeVersion":1,"position":[416,272],"id":"19f05b98-850b-4bc6-9ffb-3681a708584d","name":"MiniMax Chat Model1","credentials":{"minimaxApi":{"id":"kn97KHCrkyTm3v2g","name":"MiniMax account"}}},{"parameters":{"resource":"quote_items","operation":"update","elementId":"={{ $('Search quote_items').item.json.id }}","parameters":{"allElements":false,"elementsPerPage":1},"fields":{"assignments":[{"id":"44822f7e-b731-463b-a1f5-d46484853e11","name":"ai_item_insights","value":"={{ $json.ai_item_insights }}","type":"object"}]},"requestOptions":{}},"type":"n8n-nodes-pocketbase.pocketbaseHttp","typeVersion":1,"position":[912,0],"id":"6c8e5ae6-b56b-4468-afe4-947e13274f0e","name":"Update quote_items","credentials":{"pocketbaseHttpApi":{"id":"hLwB1QPIJEWsuVyW","name":"PocketBase HTTP account"}}},{"parameters":{"jsCode":"const allSearch = $('Search quote_items').all();\nconsole.log(\"Search returned \" + allSearch.length + \" items\");\nif (allSearch.length > 0) {\n console.log(\"First item keys: \" + Object.keys(allSearch[0]).join(\", \"));\n console.log(\"First item id: \" + allSearch[0].id);\n console.log(\"First item description: \" + allSearch[0].description);\n}\n\nconst items = $('Search quote_items').all();\nconst llmOutput = ($input.all()[0] && $input.all()[0].json && $input.all()[0].json.output) || {\n stock_list: [],\n supplier_history: [],\n price_list: [],\n recent_quote: [],\n recent_order: [],\n};\n\nif (!items || items.length === 0) {\n console.log(\"WARN: no items returned from Search\");\n return [{ json: { _status: \"no_items\" } }];\n}\n\nconst src = items[0];\nconsole.log(\"Processing item: \" + (src.id || \"UNKNOWN\") + \" \" + (src.description || \"\"));\n\nreturn items.map((src) => ({\n json: {\n ai_item_insights: {\n item: {\n id: src.id || \"\",\n collection: src.collectionName || src.collectionId || \"quote_items\",\n description: src.description || \"\",\n sku: src.sku || \"\",\n quantity: Number(src.quantity) || 0,\n },\n stock_list: (llmOutput.stock_list || []).filter((r) => r && r.stock_item_id),\n supplier_history: (llmOutput.supplier_history || []).filter((r) => r && r.supplier_id),\n price_list: (llmOutput.price_list || []).filter((r) => r && r.sku),\n recent_quote: (llmOutput.recent_quote || []).filter((r) => r && r.quote_item_id),\n recent_order: (llmOutput.recent_order || []).filter((r) => r && r.order_item_id),\n verified: {\n at: new Date().toISOString(),\n by: \"n8n:ai-verifier\",\n removed_count: Number(llmOutput.removed_count) || 0,\n notes: llmOutput.notes || \"\",\n },\n },\n },\n}));"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[688,-176],"id":"835e218b-b10b-4f3e-a39d-5ea76af364b9","name":"Code in JavaScript"},{"parameters":{"resource":"quote_items","parameters":{"allElements":true,"elementsPerPage":1,"filter":"=ai_item_insights !~ 'verified' && is_processed = false"},"requestOptions":{}},"type":"n8n-nodes-pocketbase.pocketbaseHttp","typeVersion":1,"position":[-384,0],"id":"96180b56-34a5-4778-aff3-0a219fbc7051","name":"Search quote_items","credentials":{"pocketbaseHttpApi":{"id":"hLwB1QPIJEWsuVyW","name":"PocketBase HTTP account"}}},{"parameters":{"method":"POST","url":"=https://wfdash.apphub.co.za/api/v1/items/quote_items/{{$json.id}}/intel/refresh","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Content-Type","value":"application/json"}]},"sendBody":true,"specifyBody":"json","jsonBody":"{\n \"dry_run\": false\n}","options":{"timeout":30000}},"type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[176,-720],"id":"26b77edc-8f2b-4022-a481-bc022cbd2645","name":"Populate Intel"},{"parameters":{"rule":{"interval":[{"field":"minutes","minutesInterval":10}]}},"type":"n8n-nodes-base.scheduleTrigger","typeVersion":1.3,"position":[-688,-304],"id":"41db390c-fdcf-44e0-8e57-983f54858ff6","name":"Schedule Trigger"},{"parameters":{"resource":"quote_items","parameters":{"allElements":true,"elementsPerPage":100,"filter":"is_processed = false && ai_item_insights !~ 'verified'"},"requestOptions":{}},"type":"n8n-nodes-pocketbase.pocketbaseHttp","typeVersion":1,"position":[-416,-736],"id":"a8c8d1dc-bf87-4629-bd04-07d22a768753","name":"Search quote_items1","credentials":{"pocketbaseHttpApi":{"id":"hLwB1QPIJEWsuVyW","name":"PocketBase HTTP account"}}},{"parameters":{"options":{}},"type":"n8n-nodes-base.splitInBatches","typeVersion":3,"position":[-112,-736],"id":"cb6ab626-c03e-4447-b4c7-96e628cf8c6d","name":"Loop Over Items"},{"parameters":{"options":{}},"type":"n8n-nodes-base.splitInBatches","typeVersion":3,"position":[-160,0],"id":"13119c03-aecd-4185-b525-5768842b43e2","name":"Loop Over Items1"},{"parameters":{"resource":"order_items","parameters":{"allElements":true,"elementsPerPage":100,"filter":"item_status = 'pending' && ai_item_insights !~ 'verified'"},"requestOptions":{}},"type":"n8n-nodes-pocketbase.pocketbaseHttp","typeVersion":1,"position":[-416,-448],"id":"c0546ab5-22e7-4a2d-b411-74f12cdf9de4","name":"Search order_items","credentials":{"pocketbaseHttpApi":{"id":"hLwB1QPIJEWsuVyW","name":"PocketBase HTTP account"}}},{"parameters":{"method":"POST","url":"=https://wfdash.apphub.co.za/api/v1/items/order_items/{{$json.id}}/intel/refresh","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Content-Type","value":"application/json"}]},"sendBody":true,"specifyBody":"json","jsonBody":"{\n \"dry_run\": false\n}","options":{"timeout":30000}},"type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[176,-432],"id":"c47af114-5528-403f-b9ff-bd315df13188","name":"Populate Intel1"},{"parameters":{"options":{}},"type":"n8n-nodes-base.splitInBatches","typeVersion":3,"position":[-112,-448],"id":"e6fcf475-246e-48a8-a0b4-4b54a0af0e9f","name":"Loop Over Items2"},{"parameters":{"promptType":"define","text":"=Analyze the following JSON. I am looking for items where the description, name, or equivalent field is a match or high-confidence product match for: {{ $json.description }}\n\nCRITICAL MATCHING RULES:\n- Include exact matches.\n- Include close semantic variations of the exact same pack size (e.g., if targeting \"20L\", include matches for \"20 LT\" or \"20 Litre\").\n- STRIKTLY EXCLUDE different pack sizes or bulk configurations (e.g., if targeting \"20L\", do NOT match \"210L\", \"1000L\", \"20X500ML\", or \"12X1LT\").\n- Ignore minor specification differences like \"SF/CF4\" as long as the base product and pack size are the exact same.\n\nReturn a valid JSON object containing ONLY the arrays and the specific items that match this item based on the rules above.\n\nCRITICAL INSTRUCTIONS:\n- Output ONLY raw JSON. \n- DO NOT wrap the output in markdown blocks.\n- DO NOT include backticks (```).\n- DO NOT write any explanations, greetings, or conversational text. \n- If you write anything other than the raw JSON object, the system will break.\n\nData to filter:\n{{ JSON.stringify($json.ai_item_insights, null, 2) }}","hasOutputParser":true,"needsFallback":true,"options":{}},"type":"@n8n/n8n-nodes-langchain.agent","typeVersion":3.1,"position":[144,464],"id":"523116c3-ad4b-4380-bffc-0aba1d9399c8","name":"AI Agent1"},{"parameters":{"model":"MiniMax-M2.1","options":{}},"type":"@n8n/n8n-nodes-langchain.lmChatMinimax","typeVersion":1,"position":[64,688],"id":"4cada161-d25e-491e-8dac-f2f313671452","name":"MiniMax Chat Model2","credentials":{"minimaxApi":{"id":"kn97KHCrkyTm3v2g","name":"MiniMax account"}}},{"parameters":{"schemaType":"manual","inputSchema":"{\n \"type\": \"object\",\n \"properties\": {\n \"stock_list\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the stock list. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"supplier_history\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the supplier history. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"price_list\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the price list. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"recent_quote\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the recent quotes. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"recent_order\": {\n \"type\": \"array\",\n \"description\": \"Exact matching items from the recent orders. Leave empty if no match.\",\n \"items\": {\n \"type\": \"object\"\n }\n }\n },\n \"required\": [\n \"stock_list\",\n \"supplier_history\"\n ]\n}","autoFix":true},"type":"@n8n/n8n-nodes-langchain.outputParserStructured","typeVersion":1.3,"position":[368,704],"id":"3d83d84d-9ad3-4813-85d2-4a5afa03565e","name":"Structured Output Parser1"},{"parameters":{"model":{"__rl":true,"value":"google/gemma-4-e2b","mode":"list","cachedResultName":"google/gemma-4-e2b"},"responsesApiEnabled":false,"options":{}},"type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","typeVersion":1.3,"position":[240,704],"id":"ffab19be-af58-48d6-8d16-809581169864","name":"OpenAI Chat Model","credentials":{"openAiApi":{"id":"LcoRpE8OF7QrpByT","name":"OpenAI account"}}},{"parameters":{"model":"MiniMax-M2.1","options":{}},"type":"@n8n/n8n-nodes-langchain.lmChatMinimax","typeVersion":1,"position":[448,912],"id":"e6743555-b40b-4f00-bed4-20957679c394","name":"MiniMax Chat Model3","credentials":{"minimaxApi":{"id":"kn97KHCrkyTm3v2g","name":"MiniMax account"}}},{"parameters":{"jsCode":"const allSearch = $('Search order_items1').all();\nconsole.log(\"Search returned \" + allSearch.length + \" items\");\nif (allSearch.length > 0) {\n console.log(\"First item keys: \" + Object.keys(allSearch[0]).join(\", \"));\n console.log(\"First item id: \" + allSearch[0].id);\n console.log(\"First item description: \" + allSearch[0].description);\n}\n\nconst items = $('Search order_items1').all();\nconst llmOutput = ($input.all()[0] && $input.all()[0].json && $input.all()[0].json.output) || {\n stock_list: [],\n supplier_history: [],\n price_list: [],\n recent_quote: [],\n recent_order: [],\n};\n\nif (!items || items.length === 0) {\n console.log(\"WARN: no items returned from Search\");\n return [{ json: { _status: \"no_items\" } }];\n}\n\nconst src = items[0];\nconsole.log(\"Processing item: \" + (src.id || \"UNKNOWN\") + \" \" + (src.description || \"\"));\n\nreturn items.map((src) => ({\n json: {\n ai_item_insights: {\n item: {\n id: src.id || \"\",\n collection: src.collectionName || src.collectionId || \"quote_items\",\n description: src.description || \"\",\n sku: src.sku || \"\",\n quantity: Number(src.quantity) || 0,\n },\n stock_list: (llmOutput.stock_list || []).filter((r) => r && r.stock_item_id),\n supplier_history: (llmOutput.supplier_history || []).filter((r) => r && r.supplier_id),\n price_list: (llmOutput.price_list || []).filter((r) => r && r.sku),\n recent_quote: (llmOutput.recent_quote || []).filter((r) => r && r.quote_item_id),\n recent_order: (llmOutput.recent_order || []).filter((r) => r && r.order_item_id),\n verified: {\n at: new Date().toISOString(),\n by: \"n8n:ai-verifier\",\n removed_count: Number(llmOutput.removed_count) || 0,\n notes: llmOutput.notes || \"\",\n },\n },\n },\n}));"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[720,464],"id":"8e2ed6ba-0d10-4557-88da-69de165c1833","name":"Code in JavaScript1"},{"parameters":{"options":{}},"type":"n8n-nodes-base.splitInBatches","typeVersion":3,"position":[-128,640],"id":"22056cfa-0380-4f1b-93f7-9aa6370ffc1f","name":"Loop Over Items3"},{"parameters":{"resource":"order_items","parameters":{"allElements":true,"elementsPerPage":1,"filter":"=ai_item_insights !~ 'verified' && item_status = 'pending'"},"requestOptions":{}},"type":"n8n-nodes-pocketbase.pocketbaseHttp","typeVersion":1,"position":[-352,640],"id":"5689e9e2-0e6c-4be0-ac37-cbb8385ce366","name":"Search order_items1","credentials":{"pocketbaseHttpApi":{"id":"hLwB1QPIJEWsuVyW","name":"PocketBase HTTP account"}}},{"parameters":{"resource":"order_items","operation":"update","elementId":"={{ $('Search order_items1').item.json.id }}","parameters":{"allElements":false,"elementsPerPage":1},"fields":{"assignments":[{"id":"44822f7e-b731-463b-a1f5-d46484853e11","name":"ai_item_insights","value":"={{ $json.ai_item_insights }}","type":"object"}]},"requestOptions":{}},"type":"n8n-nodes-pocketbase.pocketbaseHttp","typeVersion":1,"position":[944,640],"id":"c1fb7c3a-8486-45b6-8471-4ace2c17dd81","name":"Update order_items","credentials":{"pocketbaseHttpApi":{"id":"hLwB1QPIJEWsuVyW","name":"PocketBase HTTP account"}}}],"connections":{"When clicking ‘Execute workflow’":{"main":[[{"node":"Search quote_items","type":"main","index":0}]]},"MiniMax Chat Model":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":0}]]},"AI Agent":{"main":[[{"node":"Code in JavaScript","type":"main","index":0}]]},"Structured Output Parser":{"ai_outputParser":[[{"node":"AI Agent","type":"ai_outputParser","index":0}]]},"OpenAI Chat Model1":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":1}]]},"MiniMax Chat Model1":{"ai_languageModel":[[{"node":"Structured Output Parser","type":"ai_languageModel","index":0}]]},"Code in JavaScript":{"main":[[{"node":"Update quote_items","type":"main","index":0}]]},"Search quote_items":{"main":[[{"node":"Loop Over Items1","type":"main","index":0}]]},"Schedule Trigger":{"main":[[{"node":"Search quote_items1","type":"main","index":0},{"node":"Search quote_items","type":"main","index":0},{"node":"Search order_items","type":"main","index":0},{"node":"Search order_items1","type":"main","index":0}]]},"Search quote_items1":{"main":[[{"node":"Loop Over Items","type":"main","index":0}]]},"Loop Over Items":{"main":[[],[{"node":"Populate Intel","type":"main","index":0}]]},"Populate Intel":{"main":[[{"node":"Loop Over Items","type":"main","index":0}]]},"Loop Over Items1":{"main":[[],[{"node":"AI Agent","type":"main","index":0}]]},"Update quote_items":{"main":[[{"node":"Loop Over Items1","type":"main","index":0}]]},"Search order_items":{"main":[[{"node":"Loop Over Items2","type":"main","index":0}]]},"Populate Intel1":{"main":[[{"node":"Loop Over Items2","type":"main","index":0}]]},"Loop Over Items2":{"main":[[],[{"node":"Populate Intel1","type":"main","index":0}]]},"AI Agent1":{"main":[[{"node":"Code in JavaScript1","type":"main","index":0}]]},"MiniMax Chat Model2":{"ai_languageModel":[[{"node":"AI Agent1","type":"ai_languageModel","index":0}]]},"Structured Output Parser1":{"ai_outputParser":[[{"node":"AI Agent1","type":"ai_outputParser","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"AI Agent1","type":"ai_languageModel","index":1}]]},"MiniMax Chat Model3":{"ai_languageModel":[[{"node":"Structured Output Parser1","type":"ai_languageModel","index":0}]]},"Code in JavaScript1":{"main":[[{"node":"Update order_items","type":"main","index":0}]]},"Loop Over Items3":{"main":[[],[{"node":"AI Agent1","type":"main","index":0}]]},"Search order_items1":{"main":[[{"node":"Loop Over Items3","type":"main","index":0}]]},"Update order_items":{"main":[[{"node":"Loop Over Items3","type":"main","index":0}]]}},"nodeGroups":[],"authors":"David Els","name":"Version eab8fa65","description":"","autosaved":true,"workflowPublishHistory":[{"createdAt":"2026-08-11T20:38:45.827Z","id":721,"workflowId":"paqlZICDbXbmY61V","versionId":"eab8fa65-84ba-4524-86fd-59fa36225861","event":"activated","userId":"4f770df2-bd2f-4436-b153-b27004efc7b6"}]}}