- 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.
1 line
No EOL
39 KiB
JSON
1 line
No EOL
39 KiB
JSON
{"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"}]}} |