Files

348 lines
13 KiB
JSON

{
"name": "pw prijzen",
"nodes": [
{
"parameters": {
"formTitle": "Palletways tarief bereken",
"formFields": {
"values": [
{
"fieldLabel": "Van postcode",
"placeholder": "ColPostCode",
"defaultValue": "2181vh"
},
{
"fieldLabel": "ColCountryCode",
"fieldType": "dropdown",
"defaultValue": "NL",
"fieldOptions": {
"values": [
{
"option": "NL"
},
{
"option": "DE"
},
{
"option": "IT"
},
{
"option": "BE"
},
{
"option": "ES"
},
{
"option": "FR"
}
]
}
},
{
"fieldLabel": "Naar postcode",
"placeholder": "DelPostCode",
"defaultValue": "2181VH"
},
{
"fieldLabel": "Naar land",
"fieldType": "dropdown",
"defaultValue": "NL",
"fieldOptions": {
"values": [
{
"option": "NL"
},
{
"option": "DE"
},
{
"option": "BE"
},
{
"option": "IT"
},
{
"option": "ES"
},
{
"option": "FR"
}
]
}
},
{
"fieldLabel": "Lifts",
"fieldType": "number",
"placeholder": "Lifts",
"defaultValue": "1"
},
{
"fieldLabel": "Gewicht",
"fieldType": "number",
"placeholder": "Gewicht",
"defaultValue": "700"
},
{
"fieldLabel": "Mini Quarter Pallet",
"fieldType": "number",
"placeholder": "mqp",
"defaultValue": "0"
},
{
"fieldLabel": "Quarter Pallet",
"fieldType": "number",
"placeholder": "qp",
"defaultValue": "0"
},
{
"fieldLabel": "Half Pallet",
"fieldType": "number",
"placeholder": "hp",
"defaultValue": "0"
},
{
"fieldLabel": "Euro pallet light",
"fieldType": "number",
"placeholder": "epl",
"defaultValue": "0"
},
{
"fieldLabel": "Light Pallet",
"fieldType": "number",
"placeholder": "lp",
"defaultValue": "0"
},
{
"fieldLabel": "Full Pallet",
"fieldType": "number",
"placeholder": "fp",
"defaultValue": "0"
},
{
"fieldLabel": "shuttleCost",
"placeholder": "shuttleCost",
"defaultValue": "20"
},
{
"fieldLabel": "marginPct",
"placeholder": "marginPct",
"defaultValue": "20"
},
{
"fieldLabel": "dotPct",
"placeholder": "dotPct",
"defaultValue": "5"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.formTrigger",
"typeVersion": 2.3,
"position": [
-432,
-96
],
"id": "6fb1d884-a8eb-42e6-9cce-51e52fcb322f",
"name": "On form submission",
"webhookId": "7fbd25a6-977d-4db6-878a-99e53ce33352"
},
{
"parameters": {
"mode": "raw",
"jsonOutput": "={\n \"QuotationRequest\": {\n \"Date\": \"2025-12-21\",\n \"Time\": \"20:50\",\n \"Account\": { \"Code\": \"100000\" },\n \"Consignment\": {\n \"Type\": \"3\",\n \"Classification\": \"B2B\",\n \"ColCountryCode\": \"{{ $json.ColCountryCode }}\",\n \"ColPostCode\": \"{{ $json['Van postcode'] }}\",\n \"DelCountryCode\": \"{{ $json['Naar land'] }}\",\n \"DelPostCode\": \"{{ $json['Naar postcode'] }}\",\n \"Insurance\": \"standard\",\n \"Lifts\": {{ $json.Lifts }},\n \"Weight\": {{ $json.Gewicht }},\n \"BillUnit\": [\n { \"Type\": \"FP\", \"Amount\": {{ $json['Full Pallet'] }} },\n { \"Type\": \"LP\", \"Amount\": {{ $json['Light Pallet'] }} },\n { \"Type\": \"EPL\", \"Amount\": {{ $json['Euro pallet light'] }} },\n { \"Type\": \"QP\", \"Amount\": {{ $json['Quarter Pallet'] }} },\n { \"Type\": \"MQP\", \"Amount\": {{ $json['Mini Quarter Pallet'] }} }\n ],\n \"Return\": [\n { \"Type\": \"EU\", \"Amount\": 0 },\n { \"Type\": \"EG\", \"Amount\": 0 }\n ],\n \"Handball\": false,\n \"TailLift\": false,\n \"BookInRequest\": false\n }\n }\n }\n",
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-192,
-96
],
"id": "23edf830-f280-42c2-b70f-60371afe2a2b",
"name": "Edit Fields"
},
{
"parameters": {
"mode": "jsonToxml",
"options": {}
},
"type": "n8n-nodes-base.xml",
"typeVersion": 1,
"position": [
16,
-96
],
"id": "e9b81be0-73d3-447f-afb4-c09f317e5aeb",
"name": "XML"
},
{
"parameters": {
"method": "POST",
"url": "https://api.palletways.com/getdepotconsignmentquotations?apikey=SXJaM7PLjZDqfsnXSDP8Y9wDY6crxJySBg705MQEPus%3D&inputformat=xml&outputformat=json",
"sendBody": true,
"contentType": "form-urlencoded",
"bodyParameters": {
"parameters": [
{
"name": "data",
"value": "={{ $json.data }}"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
256,
-96
],
"id": "1bd888b1-6c57-4f06-b920-298f3d136ba0",
"name": "HTTP Request1",
"onError": "continueRegularOutput"
},
{
"parameters": {
"operation": "completion",
"respondWith": "showText",
"responseText": "={{ $json.formSubmittedText }}"
},
"type": "n8n-nodes-base.form",
"typeVersion": 2.4,
"position": [
896,
-144
],
"id": "6df73b0d-329a-4a95-9851-3623cb7af4ee",
"name": "Form",
"webhookId": "e1674065-c8d5-4ca3-aae6-9fd2a13ea847"
},
{
"parameters": {
"jsCode": "const root = $input.first().json;\n\nconst quotations =\n root?.Detail?.Data?.[0]?.Hub?.Quotations?.Quotation ?? [];\n\nreturn quotations.map((q) => ({\n json: {\n colSurchargeName: q?.ColService?.SurchargeName ?? null,\n delSurchargeName: q?.DelService?.SurchargeName ?? null,\n chargeTotal: q?.ChargeTotal ?? null,\n chargeCurrency: q?.ChargeCurrency ?? null, // extra handig\n colServiceName: q?.ColService?.ServiceName ?? null, // extra handig\n delServiceName: q?.DelService?.ServiceName ?? null, // extra handig\n },\n}));\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
464,
-96
],
"id": "06814b2e-4508-4995-bacd-683ab7a8472e",
"name": "Code in JavaScript"
},
{
"parameters": {
"jsCode": "const rows = $input.all().map(i => i.json);\n\nconst esc = (s) => String(s ?? '').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n\nlet html = `<b>Offertes</b><br><br>`;\nhtml += `<b>Col surcharge</b> | <b>Del surcharge</b> | <b>Total</b><br>`;\nhtml += `--- | --- | ---<br>`;\n\nhtml += rows\n .map(r =>\n `${esc(r.colSurchargeName)} | ${esc(r.delSurchargeName)} | ${esc(r.chargeTotal)} ${esc(r.chargeCurrency ?? '')}`\n )\n .join('<br>');\n\nreturn [\n {\n json: {\n formSubmittedText: html,\n },\n },\n];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
672,
-96
],
"id": "f5daf975-6102-4c24-8c32-3191e5ab90a8",
"name": "Code in JavaScript1"
},
{
"parameters": {
"jsCode": "const data = $input.first().json;\n\n// Pak de API response (robust: werkt of hij nou op root staat of in body/data)\nconst resp =\n data?.Detail ? data :\n data?.body?.Detail ? data.body :\n data?.data?.Detail ? data.data :\n data;\n\n// Quotations array\nconst quotations =\n resp?.Detail?.Data?.[0]?.Hub?.Quotations?.Quotation ?? [];\n\nconst toNum = (v) => {\n const n = Number(String(v ?? \"\").replace(\",\", \".\"));\n return Number.isFinite(n) ? n : 0;\n};\n\n// pallets = lifts\nconst pallets = Math.max(1, Math.round(toNum(data.lifts ?? data.pallets ?? 1)));\n\n// shuttleCost is PER pallet\nconst shuttlePerPallet = toNum(data.shuttleCost);\n\n// percentages\nconst marginPct = toNum(data.marginPct); // bv 12 = 12%\nconst dotPct = toNum(data.dotPct); // bv 5 = 5%\n\n// goedkoopste quote\nconst cheapest = quotations.reduce((best, q) => {\n if (!best) return q;\n return toNum(q.ChargeTotal) < toNum(best.ChargeTotal) ? q : best;\n}, null);\n\n// basis charge: user override of goedkoopste ChargeTotal\nconst hasChargeOverride =\n data.charge !== undefined && data.charge !== null && String(data.charge).trim() !== \"\";\n\nconst baseCharge = hasChargeOverride\n ? toNum(data.charge)\n : (cheapest ? toNum(cheapest.ChargeTotal) : 0);\n\n// === BEREKENING ===\nconst shuttleTotal = shuttlePerPallet * pallets;\n\nconst costExcl = baseCharge + shuttleTotal;\nconst dotAmount = costExcl * (dotPct / 100);\nconst costInclDot = costExcl + dotAmount;\n\nconst tariff = costInclDot * (1 + marginPct / 100);\nconst marginAmount = tariff - costInclDot;\n\nconst fmt = (n) => n.toFixed(2);\n\nconst esc = (s) =>\n String(s ?? \"\")\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n\nlet html = `<b>Offertes (Palletways)</b><br>`;\n\nif (!quotations.length) {\n html += `Geen quotes gevonden in response.<br>`;\n} else {\n html += `<br><b>Quotes</b><br><pre>`;\n html += `# | Col surcharge | Del surcharge | Total\\n`;\n html += `---+------------------------------+------------------------------+--------\\n`;\n\n quotations.slice(0, 25).forEach((q, idx) => {\n const col = esc(q?.ColService?.SurchargeName ?? \"\");\n const del = esc(q?.DelService?.SurchargeName ?? \"\");\n const total = esc(q?.ChargeTotal ?? \"\");\n const mark = (cheapest === q) ? \"*\" : \" \";\n html += `${mark}${String(idx + 1).padStart(2, \" \")} | ${col.slice(0, 28).padEnd(28)} | ${del.slice(0, 28).padEnd(28)} | ${total}\\n`;\n });\n\n html += `</pre>* = geselecteerd (laagste ChargeTotal)<br>`;\n}\n\nhtml += `<br><b>Berekening</b><br>`;\nhtml += `Lifts/Pallets: ${pallets}<br>`;\nhtml += `Basis charge: € ${fmt(baseCharge)}<br>`;\nhtml += `Shuttle per pallet: € ${fmt(shuttlePerPallet)} → totaal € ${fmt(shuttleTotal)}<br>`;\nhtml += `DOT (${fmt(dotPct)}%): € ${fmt(dotAmount)}<br>`;\nhtml += `Kosten incl. DOT: € ${fmt(costInclDot)}<br>`;\nhtml += `<b>Totaal tarief: € ${fmt(tariff)}</b><br>`;\nhtml += `Marge (wat je overhoudt): € ${fmt(marginAmount)}<br>`;\nhtml += `Tarief per pallet: € ${fmt(tariff / pallets)}<br>`;\n\nreturn [{ json: { formSubmittedText: html } }];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
464,
-320
],
"id": "ff2c8cbf-336c-4bdf-ac49-08fa94b9d566",
"name": "Code in JavaScript2"
}
],
"pinData": {},
"connections": {
"On form submission": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "XML",
"type": "main",
"index": 0
}
]
]
},
"XML": {
"main": [
[
{
"node": "HTTP Request1",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request1": {
"main": [
[
{
"node": "Code in JavaScript2",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript": {
"main": [
[
{
"node": "Code in JavaScript1",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript1": {
"main": [
[]
]
},
"Code in JavaScript2": {
"main": [
[
{
"node": "Form",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1",
"binaryMode": "separate"
},
"versionId": "57bec1f7-e133-4e0d-b04f-f53a492772fe",
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "bef8d409866a58c0777dfe7cca1b9c2400fd051c056d361501393ab423006b5f"
},
"nodeGroups": [],
"id": "JAv6gwnDzNjkHkRz",
"tags": []
}