{ "name": "Gheeraert workflow 5 — POD naar Transpas XML", "nodes": [ { "parameters": { "operation": "executeQuery", "query": "SELECT\n id,\n order_log_id,\n gheeraert_order_id,\n purchase_order_number,\n status_id,\n tracking_date,\n tracking_comments,\n tracking_url,\n barcode,\n user_name,\n pod_downloaded,\n pod_file_name,\n pod_downloaded_at,\n transpas_export_status,\n transpas_export_error\nFROM public.ghe_status_log\nWHERE status_id = 35\n AND tracking_url IS NOT NULL\n AND COALESCE(pod_downloaded, false) = false\nORDER BY tracking_date, id\nLIMIT 50;", "options": {} }, "type": "n8n-nodes-base.postgres", "typeVersion": 2.6, "position": [ -2432, -80 ], "id": "dde4054e-d2d2-4d79-be5d-ab1f772e23e7", "name": "Get pending PODs", "credentials": { "postgres": { "id": "pxziuCOuNpsUFKrm", "name": "transpas_n8n_gheeraert" } } }, { "parameters": { "url": "={{ $json.tracking_url }}", "options": { "response": { "response": { "responseFormat": "file" } } } }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ -2192, -80 ], "id": "a94882b8-2b42-4a17-ae8a-0f3df1196a0c", "name": "Download POD", "onError": "continueErrorOutput" }, { "parameters": { "jsCode": "function safeFilePart(value) {\n return String(value || '')\n .replace(/[^a-zA-Z0-9._-]+/g, '_')\n .replace(/^_+|_+$/g, '')\n .slice(0, 80) || 'pod';\n}\n\nfunction nowStampFromInput(input) {\n const d = input ? new Date(input) : new Date();\n const dt = isNaN(d.getTime()) ? new Date() : d;\n const p = (n) => String(n).padStart(2, '0');\n return `${dt.getFullYear()}${p(dt.getMonth() + 1)}${p(dt.getDate())}_${p(dt.getHours())}${p(dt.getMinutes())}${p(dt.getSeconds())}`;\n}\n\nfunction xmlEsc(value) {\n return String(value ?? '')\n .replace(/&(?!amp;|lt;|gt;|quot;|apos;|#\\d+;|#x[0-9A-Fa-f]+;)/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\nfunction formatATDateTime(input) {\n if (!input) return '';\n const d = new Date(input);\n if (isNaN(d.getTime())) return '';\n const pad = (n) => String(n).padStart(2, '0');\n return (\n d.getFullYear() +\n pad(d.getMonth() + 1) +\n pad(d.getDate()) +\n pad(d.getHours()) +\n pad(d.getMinutes()) +\n pad(d.getSeconds())\n );\n}\n\nconst j = $json;\nif (!j.tracking_url) {\n throw new Error('tracking_url ontbreekt');\n}\nif (!$binary?.data) {\n throw new Error('Geen binary data gevonden in HTTP download');\n}\n\nlet ext = 'bin';\nlet baseName = '';\ntry {\n const u = new URL(j.tracking_url);\n const pathname = u.pathname || '';\n const parts = pathname.split('/').filter(Boolean);\n baseName = parts.length ? parts[parts.length - 1] : '';\n const m = pathname.match(/\\.([A-Za-z0-9]+)$/);\n if (m) ext = m[1].toLowerCase();\n} catch (e) {}\n\nconst podFileName = `GHE_POD_${safeFilePart(j.purchase_order_number)}_${nowStampFromInput(j.tracking_date)}.${ext}`;\nconst transpasXmlFile = `GHE_POD_XML_${safeFilePart(j.purchase_order_number)}_${nowStampFromInput(j.tracking_date)}.xml`;\nconst atDateTime = formatATDateTime(j.tracking_date) || formatATDateTime(new Date().toISOString());\n\nconst binary = $binary.data;\nbinary.fileName = podFileName;\nbinary.mimeType = binary.mimeType || 'application/octet-stream';\nconst base64Data = binary.data;\n\nconst originalName = baseName || podFileName;\nconst fileType = ext || 'bin';\nconst note = [\n 'POD Online',\n j.tracking_comments || '',\n j.tracking_url ? `URL: ${j.tracking_url}` : '',\n].filter(Boolean).join(' - ');\n\nconst transpasXml = [\n '',\n '',\n ` ${xmlEsc(atDateTime)}`,\n ' TLN',\n ' ',\n ` ${xmlEsc(j.purchase_order_number)}`,\n ' 35',\n ` ${xmlEsc(note)}`,\n ` ${base64Data}`,\n ` ${xmlEsc(originalName)}`,\n ' ',\n ''\n].join('\\n');\n\nreturn {\n json: {\n ...j,\n pod_file_name: podFileName,\n transpas_xml: transpasXml,\n transpas_xml_file: transpasXmlFile,\n },\n binary: {\n data: binary,\n },\n};" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -1952, -80 ], "id": "bc443c37-8620-4c4a-a37d-7c2632a30827", "name": "Build POD Transpas XML" }, { "parameters": { "jsCode": "const xml = $json.transpas_xml;\nconst fileName = $json.transpas_xml_file || 'pod_status.xml';\n\nconst binaryData = await this.helpers.prepareBinaryData(\n Buffer.from(xml, 'utf8'),\n fileName,\n 'application/xml'\n);\n\nreturn {\n json: {\n ...$json,\n },\n binary: {\n data: binaryData,\n },\n};" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -1712, -80 ], "id": "6c04eb86-5476-473a-a911-ced8dac43c69", "name": "Create POD XML Binary" }, { "parameters": { "protocol": "sftp", "operation": "upload", "path": "=/dewit/pod_xml/{{ $json.transpas_xml_file }}", "options": {} }, "type": "n8n-nodes-base.ftp", "typeVersion": 1, "position": [ -1472, -80 ], "id": "c5300449-3418-4f22-99e0-f017dc3e167d", "name": "SFTP Upload POD XML", "credentials": { "sftp": { "id": "uKyzg5cSXQqXOuHI", "name": "SFTP n8n" } }, "onError": "continueErrorOutput" }, { "parameters": { "operation": "executeQuery", "query": "UPDATE public.ghe_status_log\nSET\n pod_downloaded = true,\n pod_file_name = $1::varchar,\n pod_downloaded_at = CURRENT_TIMESTAMP,\n transpas_xml_file = $2::varchar,\n transpas_xml_created_at = CURRENT_TIMESTAMP,\n transpas_export_status = 'exported',\n transpas_export_error = NULL\nWHERE id = $3::bigint;", "options": { "queryReplacement": "={{ [$json.pod_file_name, $json.transpas_xml_file, $json.id] }}" } }, "type": "n8n-nodes-base.postgres", "typeVersion": 2.6, "position": [ -1232, -144 ], "id": "117c6ad2-aa7c-41aa-ae45-bf840867fd3b", "name": "Mark POD Exported", "credentials": { "postgres": { "id": "pxziuCOuNpsUFKrm", "name": "transpas_n8n_gheeraert" } } }, { "parameters": { "operation": "executeQuery", "query": "UPDATE public.ghe_order_log\nSET\n pod_downloaded_at = CURRENT_TIMESTAMP,\n next_status_poll_at = CURRENT_TIMESTAMP + INTERVAL '1 day'\nWHERE id = $1::bigint;", "options": { "queryReplacement": "={{ [$json.order_log_id] }}" } }, "type": "n8n-nodes-base.postgres", "typeVersion": 2.6, "position": [ -992, -144 ], "id": "1e1a3c7e-189d-4cb0-89c3-a200409c936d", "name": "Update ghe_order_log POD", "credentials": { "postgres": { "id": "pxziuCOuNpsUFKrm", "name": "transpas_n8n_gheeraert" } } }, { "parameters": { "operation": "executeQuery", "query": "WITH input AS (\n SELECT $1::jsonb AS j\n)\nUPDATE public.ghe_status_log\nSET\n transpas_export_status = 'error',\n transpas_export_error = COALESCE(NULLIF(transpas_export_error, ''), '') || CASE WHEN COALESCE(NULLIF(transpas_export_error, ''), '') = '' THEN '' ELSE ' | ' END || (j->>'error_text')::text\nFROM input\nWHERE public.ghe_status_log.id = (j->>'id')::bigint;", "options": { "queryReplacement": "={{ [JSON.stringify({ id: $json.id, error_text: $json.error_text || 'POD download/upload/XML verwerking mislukt' })] }}" } }, "type": "n8n-nodes-base.postgres", "typeVersion": 2.6, "position": [ -1472, 80 ], "id": "0a50219a-8844-49fc-89d1-a60cb38d07c3", "name": "Log POD Error", "credentials": { "postgres": { "id": "pxziuCOuNpsUFKrm", "name": "transpas_n8n_gheeraert" } } }, { "parameters": { "jsCode": "const err = $json.error || {};\nconst message = err.message || $json.message || 'POD download/upload/XML verwerking mislukt';\nreturn { json: { ...$json, error_text: message } };" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -1952, 80 ], "id": "6aad54d4-797f-4713-83f2-1f61d1600a7b", "name": "Prepare POD Error" }, { "parameters": { "jsCode": "const err = $json.error || {};\nconst message = err.message || $json.message || 'SFTP upload POD XML mislukt';\nreturn { json: { ...$json, error_text: message } };" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -1232, 80 ], "id": "895e1542-95c2-40a6-9101-295480730af2", "name": "Prepare SFTP Error" }, { "parameters": { "rule": { "interval": [ { "field": "cronExpression", "expression": "*/20 6-22 * * 1-5" } ] } }, "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1.3, "position": [ -2640, -80 ], "id": "1917c911-de8d-4c6b-8d71-cd0884573a08", "name": "Schedule Trigger" }, { "parameters": { "protocol": "sftp", "operation": "list", "options": {} }, "type": "n8n-nodes-base.ftp", "typeVersion": 1, "position": [ -992, 64 ], "id": "8f75c195-722e-4e8c-83ad-19d329cda22e", "name": "FTP", "credentials": { "sftp": { "id": "uKyzg5cSXQqXOuHI", "name": "SFTP n8n" } } } ], "pinData": {}, "connections": { "Get pending PODs": { "main": [ [ { "node": "Download POD", "type": "main", "index": 0 } ] ] }, "Download POD": { "main": [ [ { "node": "Build POD Transpas XML", "type": "main", "index": 0 } ], [ { "node": "Prepare POD Error", "type": "main", "index": 0 } ] ] }, "Prepare POD Error": { "main": [ [ { "node": "Log POD Error", "type": "main", "index": 0 } ] ] }, "Build POD Transpas XML": { "main": [ [ { "node": "Create POD XML Binary", "type": "main", "index": 0 } ] ] }, "Create POD XML Binary": { "main": [ [ { "node": "SFTP Upload POD XML", "type": "main", "index": 0 } ] ] }, "SFTP Upload POD XML": { "main": [ [ { "node": "Mark POD Exported", "type": "main", "index": 0 }, { "node": "FTP", "type": "main", "index": 0 } ], [ { "node": "Prepare SFTP Error", "type": "main", "index": 0 } ] ] }, "Prepare SFTP Error": { "main": [ [ { "node": "Log POD Error", "type": "main", "index": 0 } ] ] }, "Mark POD Exported": { "main": [ [ { "node": "Update ghe_order_log POD", "type": "main", "index": 0 } ] ] }, "Schedule Trigger": { "main": [ [ { "node": "Get pending PODs", "type": "main", "index": 0 } ] ] } }, "active": false, "settings": { "executionOrder": "v1", "binaryMode": "separate" }, "versionId": "1761ac71-29de-4791-880a-4d790f991107", "meta": { "templateCredsSetupCompleted": true, "instanceId": "bef8d409866a58c0777dfe7cca1b9c2400fd051c056d361501393ab423006b5f" }, "nodeGroups": [], "id": "CsLGuXIeZQszqTPz", "tags": [] }