Import voor Lightmakers
This commit is contained in:
1 parent
98e52fb90f
commit
2f589ff37e
1 file changed
+359
@@ -0,0 +1,359 @@
|
||||
{
|
||||
"name": "Lightmakers",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "xml",
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.extractFromFile",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
96,
|
||||
272
|
||||
],
|
||||
"id": "c1234889-58d7-4d4f-8776-9f5b889358f8",
|
||||
"name": "Extract from File1"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"operation": "upload",
|
||||
"path": "=/prod/totp/{{ $json.filename }}",
|
||||
"binaryData": false,
|
||||
"fileContent": "={{ $json.xml }}",
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.ftp",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
800,
|
||||
304
|
||||
],
|
||||
"id": "9d4781ed-2b86-4b26-8762-fdcd42ffbdb5",
|
||||
"name": "FTP Upload1",
|
||||
"credentials": {
|
||||
"ftp": {
|
||||
"id": "oLAZ4OgmkOopMHAq",
|
||||
"name": "FTP De Wit Transport"
|
||||
}
|
||||
},
|
||||
"onError": "continueErrorOutput"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"options": {}
|
||||
},
|
||||
"id": "e1665e95-6d3f-43d8-81cc-91bc99c54c25",
|
||||
"name": "Parse XML to JSON",
|
||||
"type": "n8n-nodes-base.xml",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
288,
|
||||
272
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"triggerTimes": {
|
||||
"item": [
|
||||
{
|
||||
"mode": "everyX",
|
||||
"value": 15,
|
||||
"unit": "minutes"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"id": "d044c9e8-2ebf-40e4-be76-35889c123660",
|
||||
"name": "Check FTP Every 15 Minutes",
|
||||
"type": "n8n-nodes-base.cron",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
-752,
|
||||
272
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"mode": "runOnceForEachItem",
|
||||
"jsCode": "// n8n Code node: NYCE.LOGIC CustomerOrderDelivery -> Transpas XML\n\n// ---------- helpers ----------\nconst AMP_FIX_RE = /&(?!amp;|lt;|gt;|quot;|apos;|#\\d+;|#x[0-9A-Fa-f]+;)/g;\n\n/**\n * Escapet tekst veilig voor XML (zonder bestaande entities dubbel te escapen)\n */\nconst xmlEsc = (s) =>\n String(s ?? '')\n // eerst ampersand, maar NIET als het al een geldige entity is\n .replace(AMP_FIX_RE, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n\n/**\n * Vangnet: repareert overgebleven losse & in de complete XML-output\n * (bijv. vaste tekst of een veld dat per ongeluk niet door xmlEsc ging)\n */\nconst repairXml = (xml) => String(xml ?? '').replace(AMP_FIX_RE, '&');\n\n\nconst ensureArray = (v) =>\n v == null ? [] : Array.isArray(v) ? v : [v];\n\nconst joinLines = (s) =>\n Array.isArray(s) ? s.join(' ') : (s ?? '');\n\nconst get = (obj, path) =>\n path.split('.').reduce((acc, key) => (acc && acc[key] != null ? acc[key] : undefined), obj);\n\n// zoek in hele objectboom op een key-fragment (ongeacht namespace/prefix)\nfunction findNodeRecursive(obj, fragment) {\n if (!obj || typeof obj !== 'object') return null;\n const frag = fragment.toLowerCase();\n const stack = [obj];\n\n while (stack.length) {\n const cur = stack.pop();\n if (!cur || typeof cur !== 'object') continue;\n\n for (const [k, v] of Object.entries(cur)) {\n if (k.toLowerCase().includes(frag)) return v;\n if (v && typeof v === 'object') stack.push(v);\n }\n }\n return null;\n}\n\n// zoek directe child met key-fragment\nfunction child(obj, fragment) {\n if (!obj || typeof obj !== 'object') return undefined;\n const frag = fragment.toLowerCase();\n for (const [k, v] of Object.entries(obj)) {\n if (k.toLowerCase().includes(frag)) return v;\n }\n return undefined;\n}\n\n// \"vandaag\" als yyyy-mm-dd in een timezone (Amsterdam)\nfunction todayYMD(tz = 'Europe/Amsterdam') {\n const parts = new Intl.DateTimeFormat('en-CA', {\n timeZone: tz,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n }).formatToParts(new Date());\n\n const m = {};\n for (const p of parts) if (p.type !== 'literal') m[p.type] = p.value;\n return `${m.year}-${m.month}-${m.day}`; // yyyy-mm-dd\n}\n\n// datum naar yyyy-mm-dd\nfunction fmtDate(raw) {\n if (!raw) return '';\n let d = String(raw).trim();\n\n // ISO: 2025-11-17T09:58:26\n const iso = d.match(/^(\\d{4})-(\\d{2})-(\\d{2})/);\n if (iso) return `${iso[1]}-${iso[2]}-${iso[3]}`;\n\n d = d.replace(/\\./g, '-').replace(/\\//g, '-');\n\n const m = d.match(/^(\\d{1,2})-(\\d{1,2})-(\\d{2,4})$/);\n if (m) {\n let day = m[1].padStart(2, '0');\n let month = m[2].padStart(2, '0');\n let year = m[3];\n if (year.length === 2) year = '20' + year;\n return `${year}-${month}-${day}`;\n }\n\n const n = d.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n if (n) return d;\n\n const dt = new Date(d);\n if (!isNaN(dt.getTime())) return dt.toISOString().substring(0, 10);\n\n return d;\n}\n\n// yyyy-mm-dd -> eerstvolgende werkdag (ma-vr), altijd minimaal +1 dag\nfunction nextWorkdayYMD(ymd) {\n if (!ymd || !/^\\d{4}-\\d{2}-\\d{2}$/.test(ymd)) return ymd;\n\n const [Y, M, D] = ymd.split('-').map(Number);\n const dt = new Date(Date.UTC(Y, M - 1, D));\n\n dt.setUTCDate(dt.getUTCDate() + 1);\n\n while (dt.getUTCDay() === 0 || dt.getUTCDay() === 6) {\n dt.setUTCDate(dt.getUTCDate() + 1);\n }\n\n return dt.toISOString().slice(0, 10);\n}\n\nfunction fmtTimeFromIso(raw) {\n if (!raw) return '';\n const m = String(raw).match(/T(\\d{2}:\\d{2})(:\\d{2})?/);\n return m ? m[1] : '';\n}\n\nconst normDec = (s) =>\n s ? String(s).replace(',', '.') : '';\n\nconst toNumber = (s) => {\n const n = parseFloat(String(s ?? '0').replace(',', '.'));\n return isNaN(n) ? 0 : n;\n};\n\n// ---------- juiste bron-node pakken ----------\n\n// Soms zit alles onder één top-key (bijv. \"NYCE.LOGIC\")\nlet root = $json;\nconst rootKeys = Object.keys(root);\nif (rootKeys.length === 1 && typeof root[rootKeys[0]] === 'object') {\n root = root[rootKeys[0]];\n}\n\n// zoek CustomerOrderDelivery in de boom\nconst cod = findNodeRecursive(root, 'CustomerOrderDelivery') || root;\nif (!cod || typeof cod !== 'object') {\n throw new Error('CustomerOrderDelivery niet gevonden in XML-JSON. Check de output van de XML-node.');\n}\n\n// ---------- CustomProperties (voor TMS_Number, etc.) ----------\nconst customPropsContainer =\n child(cod, 'CustomProperties') || {};\n\nconst propsRaw =\n child(customPropsContainer, 'CustomerOrderDeliveryCustomProperty') || [];\n\nconst props = ensureArray(propsRaw);\n\nconst findProp = (name) => {\n const p = props.find(p =>\n (p.Name ?? p.name ?? (p.Name?._) ?? '').toString() === name\n );\n if (!p) return '';\n const v = p.Value ?? p.value ?? (p.Value?._);\n return v != null ? String(v) : '';\n};\n\nconst tmsNumber = findProp('TMS_NumLine truncated
|
||||
},
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
608,
|
||||
320
|
||||
],
|
||||
"id": "d8f20c76-12bd-41d8-8be3-9d02d0a5a440",
|
||||
"name": "Transform europal → Transpas1"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"protocol": "sftp",
|
||||
"operation": "list",
|
||||
"path": "/production/out/",
|
||||
"options": {
|
||||
"timeout": 10000
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.ftp",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
-560,
|
||||
272
|
||||
],
|
||||
"id": "0a82fd07-1d4d-4096-9473-f809f35b5283",
|
||||
"name": "FTP VOS",
|
||||
"credentials": {
|
||||
"sftp": {
|
||||
"id": "av3OQ74HR6RQnbMe",
|
||||
"name": "Lightmakers - VOS"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"protocol": "sftp",
|
||||
"path": "={{ $json.path }}",
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.ftp",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
-256,
|
||||
272
|
||||
],
|
||||
"id": "94e9efaf-1be6-42cd-add1-539e9a11ec75",
|
||||
"name": "FTP",
|
||||
"credentials": {
|
||||
"sftp": {
|
||||
"id": "av3OQ74HR6RQnbMe",
|
||||
"name": "Lightmakers - VOS"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"protocol": "sftp",
|
||||
"operation": "delete",
|
||||
"path": "={{ $json.path }}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "8f397a49-1228-4c35-8138-13dc5dea8bd3",
|
||||
"name": "Delete file",
|
||||
"type": "n8n-nodes-base.ftp",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
112,
|
||||
464
|
||||
],
|
||||
"credentials": {
|
||||
"sftp": {
|
||||
"id": "av3OQ74HR6RQnbMe",
|
||||
"name": "Lightmakers - VOS"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"dataTableId": {
|
||||
"__rl": true,
|
||||
"value": "4ueEkfDvi9oNJuEl",
|
||||
"mode": "list",
|
||||
"cachedResultName": "Lightmakers",
|
||||
"cachedResultUrl": "/projects/G8Z9HFBaKElWGUCs/datatables/4ueEkfDvi9oNJuEl"
|
||||
},
|
||||
"columns": {
|
||||
"mappingMode": "defineBelow",
|
||||
"value": {
|
||||
"bestandsnaam": "={{ $('FTP').item.json.name }}"
|
||||
},
|
||||
"matchingColumns": [],
|
||||
"schema": [
|
||||
{
|
||||
"id": "Order_nummer",
|
||||
"displayName": "Order_nummer",
|
||||
"required": false,
|
||||
"defaultMatch": false,
|
||||
"display": true,
|
||||
"type": "string",
|
||||
"readOnly": false,
|
||||
"removed": false
|
||||
},
|
||||
{
|
||||
"id": "bestandsnaam",
|
||||
"displayName": "bestandsnaam",
|
||||
"required": false,
|
||||
"defaultMatch": false,
|
||||
"display": true,
|
||||
"type": "string",
|
||||
"readOnly": false,
|
||||
"removed": false
|
||||
}
|
||||
],
|
||||
"attemptToConvertTypes": false,
|
||||
"convertFieldsToString": false
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.dataTable",
|
||||
"typeVersion": 1.1,
|
||||
"position": [
|
||||
480,
|
||||
128
|
||||
],
|
||||
"id": "861faf00-e1c1-41e4-bbee-f0da04f0a7e1",
|
||||
"name": "Insert row",
|
||||
"disabled": true
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"protocol": "sftp",
|
||||
"operation": "upload",
|
||||
"path": "=/dewit/verwerkt/{{ $json.name }}",
|
||||
"options": {}
|
||||
},
|
||||
"type": "n8n-nodes-base.ftp",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
96,
|
||||
80
|
||||
],
|
||||
"id": "a371618e-03c8-43da-98fb-3d8df66f6622",
|
||||
"name": "Save file in Verwerkt",
|
||||
"credentials": {
|
||||
"sftp": {
|
||||
"id": "uKyzg5cSXQqXOuHI",
|
||||
"name": "SFTP n8n"
|
||||
}
|
||||
},
|
||||
"disabled": true
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"mode": "runOnceForEachItem",
|
||||
"jsCode": "// n8n Code node: NYCE.LOGIC CustomerOrderDelivery -> Transpas XML\n\n// ---------- helpers ----------\nconst AMP_FIX_RE = /&(?!amp;|lt;|gt;|quot;|apos;|#\\d+;|#x[0-9A-Fa-f]+;)/g;\n\n/**\n * Escapet tekst veilig voor XML (zonder bestaande entities dubbel te escapen)\n */\nconst xmlEsc = (s) =>\n String(s ?? '')\n // eerst ampersand, maar NIET als het al een geldige entity is\n .replace(AMP_FIX_RE, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n\n/**\n * Vangnet: repareert overgebleven losse & in de complete XML-output\n * (bijv. vaste tekst of een veld dat per ongeluk niet door xmlEsc ging)\n */\nconst repairXml = (xml) => String(xml ?? '').replace(AMP_FIX_RE, '&');\n\n\nconst ensureArray = (v) =>\n v == null ? [] : Array.isArray(v) ? v : [v];\n\nconst joinLines = (s) =>\n Array.isArray(s) ? s.join(' ') : (s ?? '');\n\nconst get = (obj, path) =>\n path.split('.').reduce((acc, key) => (acc && acc[key] != null ? acc[key] : undefined), obj);\n\n// zoek in hele objectboom op een key-fragment (ongeacht namespace/prefix)\nfunction findNodeRecursive(obj, fragment) {\n if (!obj || typeof obj !== 'object') return null;\n const frag = fragment.toLowerCase();\n const stack = [obj];\n\n while (stack.length) {\n const cur = stack.pop();\n if (!cur || typeof cur !== 'object') continue;\n\n for (const [k, v] of Object.entries(cur)) {\n if (k.toLowerCase().includes(frag)) return v;\n if (v && typeof v === 'object') stack.push(v);\n }\n }\n return null;\n}\n\n// zoek directe child met key-fragment\nfunction child(obj, fragment) {\n if (!obj || typeof obj !== 'object') return undefined;\n const frag = fragment.toLowerCase();\n for (const [k, v] of Object.entries(obj)) {\n if (k.toLowerCase().includes(frag)) return v;\n }\n return undefined;\n}\n\n// \"vandaag\" als yyyy-mm-dd in een timezone (Amsterdam)\nfunction todayYMD(tz = 'Europe/Amsterdam') {\n const parts = new Intl.DateTimeFormat('en-CA', {\n timeZone: tz,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n }).formatToParts(new Date());\n\n const m = {};\n for (const p of parts) if (p.type !== 'literal') m[p.type] = p.value;\n return `${m.year}-${m.month}-${m.day}`; // yyyy-mm-dd\n}\n\n// datum naar yyyy-mm-dd\nfunction fmtDate(raw) {\n if (!raw) return '';\n let d = String(raw).trim();\n\n // ISO: 2025-11-17T09:58:26\n const iso = d.match(/^(\\d{4})-(\\d{2})-(\\d{2})/);\n if (iso) return `${iso[1]}-${iso[2]}-${iso[3]}`;\n\n d = d.replace(/\\./g, '-').replace(/\\//g, '-');\n\n const m = d.match(/^(\\d{1,2})-(\\d{1,2})-(\\d{2,4})$/);\n if (m) {\n let day = m[1].padStart(2, '0');\n let month = m[2].padStart(2, '0');\n let year = m[3];\n if (year.length === 2) year = '20' + year;\n return `${year}-${month}-${day}`;\n }\n\n const n = d.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n if (n) return d;\n\n const dt = new Date(d);\n if (!isNaN(dt.getTime())) return dt.toISOString().substring(0, 10);\n\n return d;\n}\n\n// yyyy-mm-dd -> eerstvolgende werkdag (ma-vr), altijd minimaal +1 dag\nfunction nextWorkdayYMD(ymd) {\n if (!ymd || !/^\\d{4}-\\d{2}-\\d{2}$/.test(ymd)) return ymd;\n\n const [Y, M, D] = ymd.split('-').map(Number);\n const dt = new Date(Date.UTC(Y, M - 1, D));\n\n dt.setUTCDate(dt.getUTCDate() + 1);\n\n while (dt.getUTCDay() === 0 || dt.getUTCDay() === 6) {\n dt.setUTCDate(dt.getUTCDate() + 1);\n }\n\n return dt.toISOString().slice(0, 10);\n}\n\nfunction fmtTimeFromIso(raw) {\n if (!raw) return '';\n const m = String(raw).match(/T(\\d{2}:\\d{2})(:\\d{2})?/);\n return m ? m[1] : '';\n}\n\nconst normDec = (s) =>\n s ? String(s).replace(',', '.') : '';\n\nconst toNumber = (s) => {\n const n = parseFloat(String(s ?? '0').replace(',', '.'));\n return isNaN(n) ? 0 : n;\n};\n\n// ---------- juiste bron-node pakken ----------\n\n// Soms zit alles onder één top-key (bijv. \"NYCE.LOGIC\")\nlet root = $json;\nconst rootKeys = Object.keys(root);\nif (rootKeys.length === 1 && typeof root[rootKeys[0]] === 'object') {\n root = root[rootKeys[0]];\n}\n\n// zoek CustomerOrderDelivery in de boom\nconst cod = findNodeRecursive(root, 'CustomerOrderDelivery') || root;\nif (!cod || typeof cod !== 'object') {\n throw new Error('CustomerOrderDelivery niet gevonden in XML-JSON. Check de output van de XML-node.');\n}\n\n// ---------- CustomProperties (voor TMS_Number, etc.) ----------\nconst customPropsContainer =\n child(cod, 'CustomProperties') || {};\n\nconst propsRaw =\n child(customPropsContainer, 'CustomerOrderDeliveryCustomProperty') || [];\n\nconst props = ensureArray(propsRaw);\n\nconst findProp = (name) => {\n const p = props.find(p =>\n (p.Name ?? p.name ?? (p.Name?._) ?? '').toString() === name\n );\n if (!p) return '';\n const v = p.Value ?? p.value ?? (p.Value?._);\n return v != null ? String(v) : '';\n};\n\nconst tmsNumber = findProp('TMS_NumLine truncated
|
||||
},
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
800,
|
||||
144
|
||||
],
|
||||
"id": "67f2ac6b-7469-4eeb-80ac-2bcb4b1c962b",
|
||||
"name": "Transform europal → Transpas"
|
||||
}
|
||||
],
|
||||
"pinData": {},
|
||||
"connections": {
|
||||
"Extract from File1": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Parse XML to JSON",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"FTP Upload1": {
|
||||
"main": [
|
||||
[],
|
||||
[]
|
||||
]
|
||||
},
|
||||
"Parse XML to JSON": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Transform europal → Transpas1",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "Insert row",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Check FTP Every 15 Minutes": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "FTP VOS",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Transform europal → Transpas1": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "FTP Upload1",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"FTP VOS": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "FTP",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"FTP": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Extract from File1",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "Delete file",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "Save file in Verwerkt",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Delete file": {
|
||||
"main": [
|
||||
[]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": true,
|
||||
"settings": {
|
||||
"executionOrder": "v1",
|
||||
"binaryMode": "separate",
|
||||
"timeSavedMode": "fixed",
|
||||
"errorWorkflow": "1Ps5lukDf2sgcGL7",
|
||||
"callerPolicy": "workflowsFromSameOwner",
|
||||
"availableInMCP": false
|
||||
},
|
||||
"versionId": "ce653f7b-0083-488a-b3c4-db7062904ed4",
|
||||
"meta": {
|
||||
"templateCredsSetupCompleted": true,
|
||||
"instanceId": "bef8d409866a58c0777dfe7cca1b9c2400fd051c056d361501393ab423006b5f"
|
||||
},
|
||||
"nodeGroups": [],
|
||||
"id": "cQHDrzPhT9jeViFR",
|
||||
"tags": []
|
||||
}
|
||||
Reference in new issue
Block a user