Remove repeated Plant, Financial and Workforce shortcut cards. Add site-scoped Plant and Financial sidebar attention status with automatic refresh. Include accumulated delivery processing, purchase order recovery, supplier reconciliation, plant data and user management changes and audit records.
583 lines
29 KiB
JSON
583 lines
29 KiB
JSON
{
|
|
"workflowId": "005iI4jX5mq9DsTR",
|
|
"operations": [
|
|
{
|
|
"type": "updateNodeParameters",
|
|
"nodeName": "Build Callback Payload",
|
|
"parameters": {
|
|
"mode": "runOnceForEachItem",
|
|
"jsCode": "const sourceItem = $input.item;\nif (!sourceItem) {\n throw new Error('Build Callback Payload: no input item');\n}\nconst parsed = (sourceItem.json && typeof sourceItem.json.output === 'object' && sourceItem.json.output !== null)\n ? sourceItem.json.output\n : sourceItem.json;\n\n// This item's id is the purchase_orders row Atomic Claim just claimed --\n// the placeholder created at upload time (src/lib/po-placeholder.ts).\n// There is no separate batch row anymore.\nconst purchase_order_id = $('Atomic Claim').item.json.id;\nconst po_number_extracted = String(parsed.po_number || '').trim();\nconst supplier = String(parsed.supplier || '').trim();\nconst project_code = String(parsed.project_code || '').trim();\nif (!po_number_extracted) {\n throw new Error('AI extraction returned an empty PO number');\n}\n\nconst po_number_normalized = po_number_extracted\n .replace(/^p\\.?o\\.?([-#.]|\\s+)?/i, '')\n .replace(/\\s+/g, ' ')\n .trim()\n .toUpperCase();\nif (!po_number_normalized) {\n throw new Error('AI Agent po_number normalises to empty string: \"' + po_number_extracted + '\"');\n}\n\nconst required_by_date = parsed.required_by_date || undefined;\nconst ordered_by = parsed.ordered_by || undefined;\nconst rawItems = Array.isArray(parsed.items) ? parsed.items : [];\nconst items = rawItems.map(it => {\n if (!it) return null;\n return {\n ...it,\n qty: Number(it.qty),\n rate: Number(it.rate),\n material_code: (it.material_code && String(it.material_code).trim() !== '' && String(it.material_code).toLowerCase() !== 'null') ? String(it.material_code).trim() : '',\n cost_code: (it.cost_code && String(it.cost_code).trim() !== '' && String(it.cost_code).toLowerCase() !== 'null') ? String(it.cost_code).trim() : '',\n disc_percent: (it.disc_percent !== null && it.disc_percent !== undefined && !isNaN(it.disc_percent)) ? Number(it.disc_percent) : 0,\n vat_percent: (it.vat_percent !== null && it.vat_percent !== undefined && !isNaN(it.vat_percent)) ? Number(it.vat_percent) : 15\n };\n}).filter(it =>\n it &&\n typeof it.description === 'string' && it.description.trim().length > 0 &&\n !isNaN(it.qty) && it.qty >= 0 &&\n !isNaN(it.rate) && it.rate >= 0\n);\nif (items.length === 0) {\n throw new Error('AI Agent returned no valid line items (all missing description/qty/rate)');\n}\n\n// Duplicate detection now lives server-side in\n// /api/purchase-orders/process-batch (merge onto the existing PO, delete\n// this placeholder) -- it already owns the purchase_orders schema and is\n// covered by tests. n8n no longer queries or writes purchase_orders\n// directly to pre-empt it.\n//\n// purchase_order_number is the exact field name the route validates --\n// the old contract used po_number here, which would fail every upload.\nreturn {\n json: {\n purchase_order_id,\n extracted: {\n purchase_order_number: po_number_normalized,\n po_number_extracted,\n supplier,\n project_code,\n required_by_date,\n ordered_by,\n items,\n raw_ocr: { source: 'ai-agent', model: 'MiniMax-M3' },\n },\n },\n};\n"
|
|
},
|
|
"replace": true
|
|
},
|
|
{
|
|
"type": "updateNodeParameters",
|
|
"nodeName": "Escalate Failure",
|
|
"parameters": {
|
|
"mode": "runOnceForEachItem",
|
|
"jsCode": "const claimItem = $('Atomic Claim').item.json;\nconst purchaseOrderId = claimItem.id;\nconst attempts = Number(claimItem.attempts || 0);\nconst input = $input.item.json || {};\nconst error = input.error || input;\nconst lastError = String(typeof error === 'string' ? error : error.message || JSON.stringify(error)).slice(0, 2000);\nconst backoffMinutes = [1, 5, 15, 60][Math.min(Math.max(attempts - 1, 0), 3)];\nconst nextRetry = new Date(Date.now() + backoffMinutes * 60000).toISOString();\nconst pbToken = $('Auth PB Admin').item.json.token;\nconst url = 'https://pb.mega.infra.apphub.co.za/api/collections/purchase_orders/records/' + purchaseOrderId;\n\nlet currentBody;\ntry {\n const response = await this.helpers.httpRequest({\n method: 'GET', url, headers: { Authorization: pbToken }, returnResponse: true,\n });\n currentBody = response.body || response;\n} catch (error) {\n if (Number(error.statusCode || error.status) === 404) {\n return { json: { escalated: false, purchaseOrderId, skipped: true, reason: 'record_removed' } };\n }\n throw error;\n}\n\nif (currentBody.processing_status !== 'processing' ||\n Number(currentBody.attempts) !== attempts ||\n Date.parse(currentBody.last_attempt_at) !== Date.parse(claimItem.last_attempt_at)) {\n return { json: { escalated: false, purchaseOrderId, skipped: true, reason: 'claim_no_longer_current' } };\n}\n\nawait this.helpers.httpRequest({\n method: 'PATCH', url,\n headers: { Authorization: pbToken, 'Content-Type': 'application/json' },\n body: JSON.stringify({\n processing_status: 'failed', last_error: lastError, next_retry_at: nextRetry,\n }),\n returnResponse: true,\n});\nreturn { json: { escalated: true, purchaseOrderId, status: 'failed', next_retry_at: nextRetry } };\n"
|
|
},
|
|
"replace": true
|
|
},
|
|
{
|
|
"type": "updateNodeParameters",
|
|
"nodeName": "Fetch Pending Batches",
|
|
"parameters": {
|
|
"url": "https://pb.mega.infra.apphub.co.za/api/collections/purchase_orders/records",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "filter",
|
|
"value": "=(processing_status=\"pending\" && (next_retry_at=\"\" || next_retry_at<=\"{{ $now.toUTC().toFormat('yyyy-MM-dd HH:mm:ss.SSS') }}Z\")) || (processing_status=\"failed\" && next_retry_at!=\"\" && next_retry_at<=\"{{ $now.toUTC().toFormat('yyyy-MM-dd HH:mm:ss.SSS') }}Z\")"
|
|
},
|
|
{
|
|
"name": "sort",
|
|
"value": "date_uploaded"
|
|
},
|
|
{
|
|
"name": "perPage",
|
|
"value": "1"
|
|
}
|
|
]
|
|
},
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Authorization",
|
|
"value": "={{ $('Auth PB Admin').item.json.token }}"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"replace": true
|
|
},
|
|
{
|
|
"type": "updateNodeParameters",
|
|
"nodeName": "Atomic Claim",
|
|
"parameters": {
|
|
"method": "PATCH",
|
|
"url": "=https://pb.mega.infra.apphub.co.za/api/collections/purchase_orders/records/{{ $json.id }}",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "filter",
|
|
"value": "=(processing_status=\"pending\" || processing_status=\"failed\") && (next_retry_at=\"\" || next_retry_at<=\"{{ $now.toUTC().toFormat('yyyy-MM-dd HH:mm:ss.SSS') }}Z\")"
|
|
}
|
|
]
|
|
},
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Authorization",
|
|
"value": "={{ $('Auth PB Admin').item.json.token }}"
|
|
},
|
|
{
|
|
"name": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
]
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={ \"processing_status\": \"processing\", \"attempts\": {{ $json.attempts + 1 }}, \"last_attempt_at\": \"{{ $now.toISO() }}\" }",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"replace": true
|
|
},
|
|
{
|
|
"type": "updateNodeParameters",
|
|
"nodeName": "Analyze document",
|
|
"parameters": {
|
|
"resource": "document",
|
|
"modelId": {
|
|
"__rl": true,
|
|
"value": "MiniMax-M3",
|
|
"mode": "list",
|
|
"cachedResultName": "MiniMax-M3"
|
|
},
|
|
"text": "Transcribe the complete purchase order, including its title and order number, the full recipient block starting at 'To', Required By, Ordered By, and every line of the items table. The supplier is the company receiving the order in the 'To' or supplier/vendor field (for example Kerbing Consultant). Mega Infrastructure (Pty) Ltd in the page heading is the buyer placing the order, not the supplier. Never invent a missing supplier. Preserve the Material Code and Cost Code columns separately, including all cost codes such as C26/09, MC-KER. Preserve quantities, units, unit rates, discounts, VAT percentages and printed totals. Do not omit header fields while extracting the table.",
|
|
"inputType": "binary",
|
|
"options": {
|
|
"maxTokens": 524288
|
|
}
|
|
},
|
|
"replace": true
|
|
},
|
|
{
|
|
"type": "updateNodeParameters",
|
|
"nodeName": "Information Extractor",
|
|
"parameters": {
|
|
"text": "={{ $json.text || ($json.content && $json.content[0] && $json.content[0].text) || $json.output || \"\" }}",
|
|
"schemaType": "manual",
|
|
"inputSchema": "{\n \"type\": \"object\",\n \"required\": [\n \"po_number\",\n \"supplier\",\n \"project_code\",\n \"items\"\n ],\n \"properties\": {\n \"po_number\": {\n \"type\": \"string\",\n \"description\": \"Unique PO number printed on the document\"\n },\n \"supplier\": {\n \"type\": \"string\",\n \"description\": \"The supplier is the company receiving the order in the 'To' or supplier/vendor field (for example Kerbing Consultant). Mega Infrastructure (Pty) Ltd in the page heading is the buyer placing the order, not the supplier. Never invent a missing supplier. Return an empty string only if the recipient is unreadable.\"\n },\n \"project_code\": {\n \"type\": \"string\",\n \"description\": \"Printed project reference if present; use an empty string when missing. The upload already has a site.\"\n },\n \"required_by_date\": {\n \"type\": \"string\",\n \"nullable\": true,\n \"description\": \"Required-by date in ISO YYYY-MM-DD format, or null if not stated\"\n },\n \"ordered_by\": {\n \"type\": \"string\",\n \"nullable\": true,\n \"description\": \"Person who placed the order, or null if not shown\"\n },\n \"items\": {\n \"type\": \"array\",\n \"description\": \"Line items in the PO\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\n \"description\",\n \"qty\",\n \"rate\"\n ],\n \"properties\": {\n \"description\": {\n \"type\": \"string\",\n \"description\": \"Item description / part name\"\n },\n \"qty\": {\n \"type\": \"number\",\n \"description\": \"Quantity ordered (can be 0 or greater)\"\n },\n \"rate\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"description\": \"Unit rate excluding VAT (must be 0 or greater)\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"nullable\": true,\n \"description\": \"Unit of measure, or null if not specified\"\n },\n \"material_code\": {\n \"type\": \"string\",\n \"nullable\": true,\n \"description\": \"Internal material code, or null if not present\"\n },\n \"cost_code\": {\n \"type\": \"string\",\n \"nullable\": true,\n \"description\": \"Cost code or GL account, or null if not present\"\n },\n \"disc_percent\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 100,\n \"nullable\": true,\n \"description\": \"Discount percentage 0-100, or null if not applied\"\n },\n \"vat_percent\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 100,\n \"nullable\": true,\n \"description\": \"VAT percentage 0-100, or null if not applied\"\n }\n }\n }\n }\n }\n}",
|
|
"options": {
|
|
"systemPromptTemplate": "Extract the purchase order header and every line item from the document text. The supplier is the company receiving the order in the 'To' or supplier/vendor field (for example Kerbing Consultant). Mega Infrastructure (Pty) Ltd in the page heading is the buyer placing the order, not the supplier. Never invent a missing supplier. Read supplier from 'To'. Use the printed required-by date in YYYY-MM-DD. Preserve material_code and cost_code for every row. Only po_number and usable items are needed to process; use an empty string for an unreadable supplier or missing project_code. Never invent values."
|
|
}
|
|
},
|
|
"replace": true
|
|
},
|
|
{
|
|
"type": "updateNodeParameters",
|
|
"nodeName": "Structured Output Parser1",
|
|
"parameters": {
|
|
"schemaType": "manual",
|
|
"inputSchema": "{\n \"type\": \"object\",\n \"required\": [\n \"po_number\",\n \"supplier\",\n \"project_code\",\n \"items\"\n ],\n \"properties\": {\n \"po_number\": {\n \"type\": \"string\",\n \"description\": \"Unique PO number printed on the document\"\n },\n \"supplier\": {\n \"type\": \"string\",\n \"description\": \"The supplier is the company receiving the order in the 'To' or supplier/vendor field (for example Kerbing Consultant). Mega Infrastructure (Pty) Ltd in the page heading is the buyer placing the order, not the supplier. Never invent a missing supplier. Return an empty string only if the recipient is unreadable.\"\n },\n \"project_code\": {\n \"type\": \"string\",\n \"description\": \"Printed project reference if present; use an empty string when missing. The upload already has a site.\"\n },\n \"required_by_date\": {\n \"type\": \"string\",\n \"nullable\": true,\n \"description\": \"Required-by date in ISO YYYY-MM-DD format, or null if not stated\"\n },\n \"ordered_by\": {\n \"type\": \"string\",\n \"nullable\": true,\n \"description\": \"Person who placed the order, or null if not shown\"\n },\n \"items\": {\n \"type\": \"array\",\n \"description\": \"Line items in the PO\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\n \"description\",\n \"qty\",\n \"rate\"\n ],\n \"properties\": {\n \"description\": {\n \"type\": \"string\",\n \"description\": \"Item description / part name\"\n },\n \"qty\": {\n \"type\": \"number\",\n \"description\": \"Quantity ordered (can be 0 or greater)\"\n },\n \"rate\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"description\": \"Unit rate excluding VAT (must be 0 or greater)\"\n },\n \"unit\": {\n \"type\": \"string\",\n \"nullable\": true,\n \"description\": \"Unit of measure, or null if not specified\"\n },\n \"material_code\": {\n \"type\": \"string\",\n \"nullable\": true,\n \"description\": \"Internal material code, or null if not present\"\n },\n \"cost_code\": {\n \"type\": \"string\",\n \"nullable\": true,\n \"description\": \"Cost code or GL account, or null if not present\"\n },\n \"disc_percent\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 100,\n \"nullable\": true,\n \"description\": \"Discount percentage 0-100, or null if not applied\"\n },\n \"vat_percent\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 100,\n \"nullable\": true,\n \"description\": \"VAT percentage 0-100, or null if not applied\"\n }\n }\n }\n }\n }\n}",
|
|
"autoFix": "={{ true }}"
|
|
},
|
|
"replace": true
|
|
},
|
|
{
|
|
"type": "updateNodeParameters",
|
|
"nodeName": "AI Agent1",
|
|
"parameters": {
|
|
"promptType": "define",
|
|
"text": "={{ \"Extract the purchase order data from the attached image.\" }}",
|
|
"hasOutputParser": true,
|
|
"options": {
|
|
"systemMessage": "You are a purchase order parser. Given the attached PDF or scanned image, extract the purchase order header and line items.\n\nReturn ONLY a JSON object (no markdown, no commentary) matching this exact schema:\n\n{\n \"po_number\": string,\n \"supplier\": string,\n \"project_code\": string,\n \"required_by_date\": \"YYYY-MM-DD\" | null,\n \"ordered_by\": string | null,\n \"items\": [\n {\n \"description\": string,\n \"qty\": number,\n \"rate\": number,\n \"unit\": string | null,\n \"material_code\": string | null,\n \"cost_code\": string | null,\n \"disc_percent\": number | null,\n \"vat_percent\": number | null\n }\n ]\n}\n\nRules:\n- Use null (not \"\") for missing optional fields.\n- disc_percent and vat_percent must be 0-100 if provided.\n- Drop any line item missing description, qty, or rate.\n- po_number and usable items are required. If supplier or project_code is unreadable, return an empty string. The supplier is the company receiving the order in the 'To' or supplier/vendor field (for example Kerbing Consultant). Mega Infrastructure (Pty) Ltd in the page heading is the buyer placing the order, not the supplier. Never invent a missing supplier.",
|
|
"passthroughBinaryImages": "={{ true }}",
|
|
"passthroughBinaryPdfs": "={{ false }}"
|
|
}
|
|
},
|
|
"replace": true
|
|
},
|
|
{
|
|
"type": "updateNodeParameters",
|
|
"nodeName": "Send Callback",
|
|
"parameters": {
|
|
"jsonBody": "={{ $('Build Callback Payload').item.json }}"
|
|
},
|
|
"replace": false
|
|
},
|
|
{
|
|
"type": "setNodeSettings",
|
|
"nodeName": "Get File Token",
|
|
"settings": {
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 2,
|
|
"waitBetweenTries": 3000
|
|
}
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Get File Token",
|
|
"sourceIndex": 1,
|
|
"target": "Escalate Failure"
|
|
},
|
|
{
|
|
"type": "setNodeSettings",
|
|
"nodeName": "Download File",
|
|
"settings": {
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 2,
|
|
"waitBetweenTries": 3000
|
|
}
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Download File",
|
|
"sourceIndex": 1,
|
|
"target": "Escalate Failure"
|
|
},
|
|
{
|
|
"type": "setNodeSettings",
|
|
"nodeName": "Analyze document",
|
|
"settings": {
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 2,
|
|
"waitBetweenTries": 3000
|
|
}
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Analyze document",
|
|
"sourceIndex": 1,
|
|
"target": "Escalate Failure"
|
|
},
|
|
{
|
|
"type": "setNodeSettings",
|
|
"nodeName": "Information Extractor",
|
|
"settings": {
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 2,
|
|
"waitBetweenTries": 3000
|
|
}
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Information Extractor",
|
|
"sourceIndex": 1,
|
|
"target": "Escalate Failure"
|
|
},
|
|
{
|
|
"type": "setNodeSettings",
|
|
"nodeName": "AI Agent1",
|
|
"settings": {
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 2,
|
|
"waitBetweenTries": 3000
|
|
}
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "AI Agent1",
|
|
"sourceIndex": 1,
|
|
"target": "Escalate Failure"
|
|
},
|
|
{
|
|
"type": "addNode",
|
|
"node": {
|
|
"name": "Supplier Named?",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
1250,
|
|
500
|
|
],
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"leftValue": "={{ ($('Build Callback Payload').item.json.extracted.supplier.trim().replace(/\\s+/g, ' ').toUpperCase()).length > 0 && ($('Build Callback Payload').item.json.extracted.supplier.trim().replace(/\\s+/g, ' ').toUpperCase()).length <= 200 && ![\"—\", \"-\", \"N/A\", \"NA\", \"UNKNOWN\", \"NOT SPECIFIED\", \"NOT SPECIFIED IN DOCUMENT\", \"NULL\"].includes($('Build Callback Payload').item.json.extracted.supplier.trim().replace(/\\s+/g, ' ').toUpperCase()) }}",
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "equals"
|
|
},
|
|
"rightValue": true
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"options": {}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "addNode",
|
|
"node": {
|
|
"name": "Find Supplier",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.5,
|
|
"position": [
|
|
1490,
|
|
420
|
|
],
|
|
"parameters": {
|
|
"url": "https://pb.mega.infra.apphub.co.za/api/collections/suppliers/records",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Authorization",
|
|
"value": "={{ $('Auth PB Admin').item.json.token }}"
|
|
}
|
|
]
|
|
},
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "filter",
|
|
"value": "={{ 'name = \"' + ($('Build Callback Payload').item.json.extracted.supplier.trim().replace(/\\s+/g, ' ').toUpperCase()).replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"') + '\"' }}"
|
|
},
|
|
{
|
|
"name": "perPage",
|
|
"value": "1"
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "addNode",
|
|
"node": {
|
|
"name": "Supplier Found?",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
1730,
|
|
420
|
|
],
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"leftValue": "={{ $json.items.length }}",
|
|
"operator": {
|
|
"type": "number",
|
|
"operation": "gt"
|
|
},
|
|
"rightValue": 0
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"options": {}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "addNode",
|
|
"node": {
|
|
"name": "Create Supplier",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.5,
|
|
"position": [
|
|
1970,
|
|
550
|
|
],
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "https://pb.mega.infra.apphub.co.za/api/collections/suppliers/records",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Authorization",
|
|
"value": "={{ $('Auth PB Admin').item.json.token }}"
|
|
}
|
|
]
|
|
},
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={{ { name: $('Build Callback Payload').item.json.extracted.supplier.trim().replace(/\\s+/g, ' ').toUpperCase(), id: ('po-supplier:' + ($('Build Callback Payload').item.json.extracted.supplier.trim().replace(/\\s+/g, ' ').toUpperCase())).hash('sha256').slice(0, 15) } }}",
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "addNode",
|
|
"node": {
|
|
"name": "Find Supplier After Conflict",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.5,
|
|
"position": [
|
|
2210,
|
|
650
|
|
],
|
|
"parameters": {
|
|
"url": "https://pb.mega.infra.apphub.co.za/api/collections/suppliers/records",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Authorization",
|
|
"value": "={{ $('Auth PB Admin').item.json.token }}"
|
|
}
|
|
]
|
|
},
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "filter",
|
|
"value": "={{ 'name = \"' + ($('Build Callback Payload').item.json.extracted.supplier.trim().replace(/\\s+/g, ' ').toUpperCase()).replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"') + '\"' }}"
|
|
},
|
|
{
|
|
"name": "perPage",
|
|
"value": "1"
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"response": {
|
|
"response": {
|
|
"responseFormat": "json"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "addNode",
|
|
"node": {
|
|
"name": "Supplier Conflict Resolved?",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
2450,
|
|
650
|
|
],
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"leftValue": "={{ $json.items.length }}",
|
|
"operator": {
|
|
"type": "number",
|
|
"operation": "gt"
|
|
},
|
|
"rightValue": 0
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"options": {}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "setNodeSettings",
|
|
"nodeName": "Find Supplier",
|
|
"settings": {
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 2,
|
|
"waitBetweenTries": 1000
|
|
}
|
|
},
|
|
{
|
|
"type": "setNodeSettings",
|
|
"nodeName": "Create Supplier",
|
|
"settings": {
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 2,
|
|
"waitBetweenTries": 1000
|
|
}
|
|
},
|
|
{
|
|
"type": "setNodeSettings",
|
|
"nodeName": "Find Supplier After Conflict",
|
|
"settings": {
|
|
"onError": "continueErrorOutput",
|
|
"retryOnFail": true,
|
|
"maxTries": 2,
|
|
"waitBetweenTries": 1000
|
|
}
|
|
},
|
|
{
|
|
"type": "removeConnection",
|
|
"source": "Build Callback Payload",
|
|
"target": "Send Callback",
|
|
"sourceIndex": 0
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Build Callback Payload",
|
|
"target": "Supplier Named?",
|
|
"sourceIndex": 0
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Supplier Named?",
|
|
"target": "Find Supplier",
|
|
"sourceIndex": 0
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Supplier Named?",
|
|
"target": "Send Callback",
|
|
"sourceIndex": 1
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Find Supplier",
|
|
"target": "Supplier Found?",
|
|
"sourceIndex": 0
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Find Supplier",
|
|
"target": "Escalate Failure",
|
|
"sourceIndex": 1
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Supplier Found?",
|
|
"target": "Send Callback",
|
|
"sourceIndex": 0
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Supplier Found?",
|
|
"target": "Create Supplier",
|
|
"sourceIndex": 1
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Create Supplier",
|
|
"target": "Send Callback",
|
|
"sourceIndex": 0
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Create Supplier",
|
|
"target": "Find Supplier After Conflict",
|
|
"sourceIndex": 1
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Find Supplier After Conflict",
|
|
"target": "Supplier Conflict Resolved?",
|
|
"sourceIndex": 0
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Find Supplier After Conflict",
|
|
"target": "Escalate Failure",
|
|
"sourceIndex": 1
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Supplier Conflict Resolved?",
|
|
"target": "Send Callback",
|
|
"sourceIndex": 0
|
|
},
|
|
{
|
|
"type": "addConnection",
|
|
"source": "Supplier Conflict Resolved?",
|
|
"target": "Escalate Failure",
|
|
"sourceIndex": 1
|
|
}
|
|
]
|
|
}
|