diff --git a/Archief/Systematic.json b/Archief/Systematic.json
new file mode 100644
index 0000000..123ebb9
--- /dev/null
+++ b/Archief/Systematic.json
@@ -0,0 +1,135 @@
+{
+ "name": "Systematic",
+ "nodes": [
+ {
+ "parameters": {
+ "formTitle": "Systematic File upload",
+ "formFields": {
+ "values": [
+ {
+ "fieldLabel": "Upload file",
+ "fieldType": "file",
+ "fieldName": "uploadFile"
+ }
+ ]
+ },
+ "options": {}
+ },
+ "type": "n8n-nodes-base.formTrigger",
+ "typeVersion": 2.5,
+ "position": [
+ -64,
+ 0
+ ],
+ "id": "441716c7-ed61-47db-aff7-dd8ed680c747",
+ "name": "On form submission",
+ "webhookId": "f6c9a170-d2b5-4d4b-8c44-44bff00a6e27"
+ },
+ {
+ "parameters": {
+ "operation": "xlsx",
+ "binaryPropertyName": "=uploadFile",
+ "options": {
+ "headerRow": true,
+ "range": "1"
+ }
+ },
+ "type": "n8n-nodes-base.extractFromFile",
+ "typeVersion": 1,
+ "position": [
+ 96,
+ 0
+ ],
+ "id": "95e801c3-d23f-4bb4-af50-941cdcfbb059",
+ "name": "Extract from File1"
+ },
+ {
+ "parameters": {
+ "jsCode": "// n8n Code node (Run once for all items)\n// Input: items (1 per Excel-rij) OF 1 item met array van rijen\n// Output: meerdere items -> { filename, xml, reference }\n\n// ======= vaste Transpas pickup address_id =======\nconst PICKUP_ADDRESS_ID = \"69110\"; // Systematic BV\n\nconst inItems = $input.all();\nlet rows = [];\n\n// 1) input kan zijn: 1 item met array als .json, of meerdere items met .json per rij\nif (inItems.length === 1 && Array.isArray(inItems[0].json)) {\n rows = inItems[0].json;\n} else {\n rows = inItems.map(i => i.json);\n}\n\n// ---------- helpers ----------\nconst AMP_FIX_RE = /&(?!amp;|lt;|gt;|quot;|apos;|#\\d+;|#x[0-9A-Fa-f]+;)/g;\nfunction xmlEscape(str) {\n return String(str ?? \"\")\n .replace(AMP_FIX_RE, \"&\")\n .replace(//g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction isBlankRow(r) {\n return Object.values(r || {}).every(v => v === null || v === undefined || String(v).trim() === \"\");\n}\n\nfunction isTotalRow(r) {\n const eta = r?.[\"ETD start\"];\n return typeof eta === \"string\" && eta.trim().toLowerCase() === \"totaal\";\n}\n\nfunction isDimsOnlyRow(r) {\n const hasDims = r?.[\"Breedte\"] != null || r?.[\"Hoogte\"] != null || r?.[\"Lengte\"] != null;\n const hasRef = !!getReference(r);\n const hasLos =\n !!(r?.[\"Los naam\"] || r?.[\"Los land\"] || r?.[\"Los postcode\"] || r?.[\"Los plaats\"] || r?.[\"Los adresregel\"]);\n const hasEtaEtd = r?.[\"ETA start\"] != null || r?.[\"ETD start\"] != null;\n return hasDims && !hasRef && !hasLos && !hasEtaEtd;\n}\n\nfunction num(v) {\n const n = parseFloat(String(v ?? \"\").replace(\",\", \".\"));\n return Number.isFinite(n) ? n : null;\n}\n\n// Excel serial (1900 date system) -> YYYY-MM-DD\nfunction excelDateToISO(val) {\n if (typeof val !== \"number\" || !Number.isFinite(val)) return \"\";\n const base = new Date(Date.UTC(1899, 11, 30)); // Excel epoch\n const d = new Date(base.getTime() + val * 86400000);\n return d.toISOString().slice(0, 10);\n}\n\n// Format Date -> YYYY-MM-DD (zonder UTC-dagverschuiving)\nfunction formatDate(d) {\n const yyyy = d.getFullYear();\n const mm = String(d.getMonth() + 1).padStart(2, \"0\");\n const dd = String(d.getDate()).padStart(2, \"0\");\n return `${yyyy}-${mm}-${dd}`;\n}\n\nfunction getNextWorkday(date) {\n const d = new Date(date);\n do {\n d.setDate(d.getDate() + 1);\n } while (d.getDay() === 0 || d.getDay() === 6);\n return d;\n}\n\nfunction pickFirstNonEmpty(...vals) {\n for (const v of vals) {\n if (v !== null && v !== undefined && String(v).trim() !== \"\") return String(v).trim();\n }\n return \"\";\n}\n\nfunction joinAddressLines(...lines) {\n return lines.map(l => String(l ?? \"\").trim()).filter(Boolean).join(\" \");\n}\n\n// >>> BELANGRIJK: jouw input gebruikt \"Nummer\" i.p.v. \"Referentie\"\nfunction getReference(r) {\n return pickFirstNonEmpty(\n r?.[\"Referentie\"],\n r?.[\"Nummer\"], // <-- jouw bestand\n r?.[\"Reference\"],\n r?.[\"Ref\"]\n );\n}\n\n// Pallettype op footprint: Breedte x Lengte\nfunction palletUnitId(width, length) {\n const w = Number(width);\n const l = Number(length);\n if (!Number.isFinite(w) || !Number.isFinite(l)) return \"PW pallet\";\n\n const pair = `${w}x${l}`;\n const pairRev = `${l}x${w}`;\n\n if (pair === \"80x120\" || pairRev === \"80x120\") return \"Euroformaat\";\n if (pair === \"100x120\" || pairRev === \"100x120\") return \"Blokpallet\";\n return \"PW pallet\";\n}\n\nfunction extractDims(r) {\n return {\n width: num(r[\"Breedte\"]),\n height: num(r[\"Hoogte\"]),\n length: num(r[\"Lengte\"]),\n stackable: num(r[\"Stapelbaar\"]) ?? 0\n };\n}\n\n// ---------- 1) schoonmaken + groeperen (dims-only aan vorige koppelen) ----------\nconst shipments = [];\nlet current = null;\n\nfor (const r of rows) {\n if (!r || isBlankRow(r) || isTotalRow(r)) continue;\n\n const ref = getReference(r);\n\n if (ref) {\n current = { main: r, dims: [extractDims(r)], reference: ref };\n shipments.push(current);\n continue;\n }\n\n if (isDimsOnlyRow(r) && current) {\n current.dims.push(extractDims(r));\n continue;\n }\n // overige rommelregels: negeren (zoals \"Aangemaakt op ...\")\n}\n\n// Debug: als er niets overblijft, geef 1 item terug met info ipv \"geen output\"\nif (!shipments.length) {\n return [{\n json: {\n error: \"Geen shipments aangemaakt (geen Referentie/Nummer gevonden).\",\n rowCount: rows.length,\n firstRowKeys: rows[0] ? Object.keys(rows[0]) : []\n }\n }];\n}\n\n// ---------- 2) per shipment -> Transpas XML ----------\nconst CUSTOMER_ID = \"28834\";\nconst DEBTOR_ID = \"28834\";\nconst DEPARTMENT_ID = \"Dep DeWit\";\nconst PLANGROUP_ID = \"2\";\nconst PRODUCT_ID = \"123\";\nconst PRODUCT_DESC = \"General Cargo\";\n\nfunction splitWeight(total, n) {\n const t = Number(total);\n if (!Number.isFinite(t) || n <= 0) return Array(n).fill(\"\");\n if (n === 1) return [String(t)];\n\n const per = Math.round((t / n) * 1000) / 1000;\n const arr = Array(n).fill(per);\n const sum = arr.reduce((a, b) => a + b, 0);\n const diff = Math.round((t - sum) * 1000) / 1000;\n arr[n - 1] = Math.round((arr[n - 1] + diff) * 1000) / 1000;\n return arr.map(x => String(x));\n}\n\nreturn shipments.map(s => {\n const o = s.main;\n\n const reference = s.reference || getReference(o) || \"\";\n\n // ===== DATUMLOGICA AANGEPAST =====\n // Laden = eerstvolgende werkdag (vanaf vandaag)\n // Lossen = werkdag daarna (dus: eerstvolgende werkdag + 1 werkdag)\n const base = new Date();\n base.setHours(12, 0, 0, 0); // voorkomt dagverschuiving door timezone/UTC\n const loadDateObj = getNextWorkday(base);\n const unloadDateObj = getNextWorkday(loadDateObj);\n\n const loadDate = formatDate(loadDateObj);\n const unloadDate = formatDate(unloadDateObj);\n // ================================\n\n // laad info (je input heeft geen laad-adres/plaats/postcode -> blijft leeg behalve naam/land)\n const pickupName = pickFirstNonEmpty(o[\"Laad naam\"]);\n const pickupCountry = pickFirstNonEmpty(o[\"Laad land\"], \"NL\");\n\n // los info\n const deliveryName = pickFirstNonEmpty(o[\"Los naam\"]);\n const deliveryCountry = pickFirstNonEmpty(o[\"Los land\"]);\n const deliveryZip = pickFirstNonEmpty(o[\"Los postcode\"]);\n const deliveryCity = pickFirstNonEmpty(o[\"Los plaats\"]);\n const deliveryAddress1 = joinAddressLines(o[\"Los adresregel\"], o[\"Los adresregel_1\"], o[\"Los adresregel_2\"]);\n\n const deliveryEmail = pickFirstNonEmpty(o[\"Los contact email\"]);\n const deliveryPhone = pickFirstNonEmpty(o[\"Los contact telefoon\"], o[\"Los contact mobiel\"]);\n\n // instructions / book-in (op basis van teksten die er zijn)\n const instructions = [o[\"Los openingstijden\"], o[\"Los opmerking\"]]\n .map(v => String(v ?? \"\").trim())\n .filter(Boolean);\n\n const bookIn = instructions.some(t => /BOOKING|RDV|APPOINTMENT|AFSPRAAK|RENDEZ/i.test(t));\n const instructionsXml = instructions.map(t => ` ${xmlEscape(t)}`).join(\"\\n\");\n\n // cargo totals\n const totalWeight = num(o[\"Totaal brutogewicht\"]) ?? 0;\n const totalColli = Math.max(1, Math.round(num(o[\"Totaal colli\"]) ?? 1));\n const totalLdm = num(o[\"Totaal laadmeter\"]);\n\n // goodslines (dims) -> exact aantal colli\n const dimsList = (s.dims || []).filter(d => d.width || d.length || d.height);\n\n let dimsForLines = dimsList.slice(0, totalColli);\n while (dimsForLines.length < totalColli) {\n dimsForLines.push(dimsForLines[dimsForLines.length - 1] || extractDims(o));\n }\n\n const weightsPerLine = splitWeight(totalWeight, totalColli);\n\n const unitTypes = dimsForLines.map(d => palletUnitId(d.width, d.length));\n const uniqueUnitTypes = [...new Set(unitTypes)];\n const cargoUnitId = uniqueUnitTypes.length === 1 ? uniqueUnitTypes[0] : \"Pallets\";\n\n const goodsLinesXml = dimsForLines.map((d, idx) => {\n const w = d.width ?? \"\";\n const h = d.height ?? \"\";\n const l = d.length ?? \"\";\n\n const vol =\n (d.width && d.height && d.length)\n ? ((d.width / 100) * (d.height / 100) * (d.length / 100)).toFixed(3)\n : \"\";\n\n const unitId = unitTypes[idx] || \"PW pallet\";\n\n return `\n \n ${idx + 1}\n ${xmlEscape(reference)}\n 1\n ${xmlEscape(unitId)}\n ${PRODUCT_ID}\n ${xmlEscape(PRODUCT_DESC)}\n ${xmlEscape(weightsPerLine[idx])}\n \n ${xmlEscape(vol)}\n \n ${xmlEscape(l)}\n ${xmlEscape(w)}\n ${xmlEscape(h)}\n ${xmlEscape(reference)}\n \n \n `;\n }).join(\"\");\n\n const cargoXml = `\n \n ${totalColli}\n ${xmlEscape(cargoUnitId)}\n ${PRODUCT_ID}\n ${xmlEscape(PRODUCT_DESC)}\n ${xmlEscape(totalWeight)}\n // ${totalLdm != null ? xmlEscape(totalLdm) : \"\"}\n true\n true\n \n \n \n \n ${goodsLinesXml}\n \n `;\n\n const xml = `\n\n \n ${xmlEscape(reference)}\n ${xmlEscape(reference)}\n ${CUSTOMER_ID}\n ${DEBTOR_ID}\n ${xmlEscape(DEPARTMENT_ID)}\n \n \n ${xmlEscape(reference)}\n ${xmlEscape(reference)}\n ${PLANGROUP_ID}\n \n \n ${PICKUP_ADDRESS_ID}\n ${xmlEscape(pickupName)}\n \n \n \n ${xmlEscape(pickupCountry)}\n \n \n \n ${xmlEscape(deliveryName)}\n ${xmlEscape(deliveryAddress1)}\n ${xmlEscape(deliveryZip)}\n ${xmlEscape(deliveryCity)}\n ${xmlEscape(deliveryCountry)}\n \n \n ${PICKUP_ADDRESS_ID}\n ${xmlEscape(reference)}\n ${xmlEscape(loadDate)}\n \n ${xmlEscape(loadDate)}\n \n ${xmlEscape(pickupName)}\n \n \n \n ${xmlEscape(pickupCountry)}\n \n \n \n${instructionsXml ? instructionsXml + \"\\n\" : \"\"} \n \n \n \n \n \n ${xmlEscape(reference)}\n ${xmlEscape(unloadDate)}\n \n ${xmlEscape(unloadDate)}\n \n ${xmlEscape(deliveryName)}\n ${xmlEscape(deliveryAddress1)}\n ${xmlEscape(deliveryZip)}\n ${xmlEscape(deliveryCity)}\n ${xmlEscape(deliveryCountry)}\n ${xmlEscape(deliveryName)}\n ${xmlEscape(deliveryEmail)}\n ${xmlEscape(deliveryPhone)}\n \n${instructionsXml ? instructionsXml + \"\\n\" : \"\"} \n \n \n${cargoXml}\n \n \n \n`;\n\n return {\n json: {\n reference,\n filename: `sli_${reference}.xml`,\n xml\n }\n };\n});\n"
+ },
+ "type": "n8n-nodes-base.code",
+ "typeVersion": 2,
+ "position": [
+ 288,
+ 0
+ ],
+ "id": "1b8bf47f-bc47-4169-b11a-21efc1b99248",
+ "name": "Build Transpas XML"
+ },
+ {
+ "parameters": {
+ "operation": "upload",
+ "path": "=/prod/totp/{{ $json.filename }}",
+ "binaryData": false,
+ "fileContent": "={{ $json.xml }}",
+ "options": {}
+ },
+ "type": "n8n-nodes-base.ftp",
+ "typeVersion": 1,
+ "position": [
+ 544,
+ 0
+ ],
+ "id": "179f79c5-8ce3-46e7-802a-ae19b3ea9a64",
+ "name": "FTP1",
+ "credentials": {
+ "ftp": {
+ "id": "oLAZ4OgmkOopMHAq",
+ "name": "FTP De Wit Transport"
+ }
+ }
+ }
+ ],
+ "pinData": {},
+ "connections": {
+ "Extract from File1": {
+ "main": [
+ [
+ {
+ "node": "Build Transpas XML",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "Build Transpas XML": {
+ "main": [
+ [
+ {
+ "node": "FTP1",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ },
+ "On form submission": {
+ "main": [
+ [
+ {
+ "node": "Extract from File1",
+ "type": "main",
+ "index": 0
+ }
+ ]
+ ]
+ }
+ },
+ "active": false,
+ "settings": {
+ "executionOrder": "v1",
+ "binaryMode": "separate",
+ "availableInMCP": false,
+ "timeSavedMode": "fixed",
+ "errorWorkflow": "1Ps5lukDf2sgcGL7",
+ "callerPolicy": "workflowsFromSameOwner"
+ },
+ "versionId": "a5a249df-bb32-4171-afdf-5ae57ecf588e",
+ "meta": {
+ "instanceId": "bef8d409866a58c0777dfe7cca1b9c2400fd051c056d361501393ab423006b5f"
+ },
+ "nodeGroups": [],
+ "id": "JapyhfpdzChol1xDx0_eX",
+ "tags": []
+}
\ No newline at end of file