Files
n8n-workflows/palletways/Palletways - mail outbound manifest.json
adminjeroen 11ba200638 Upload files to "palletways"
Mailt een overzicht van de zendingen die wij de volgende dag moeten leveren. 
Data komt van Outbount manifest
2026-07-03 07:14:27 +02:00

403 lines
15 KiB
JSON

{
"name": "Palletways - mail outbound manifest",
"nodes": [
{
"parameters": {
"jsCode": "// Get today's date\nconst today = new Date();\n\n\nconst lastWorkday = new Date(today);\n\n// Format as YYYY-MM-DD\nconst yyyy = lastWorkday.getFullYear();\nconst mm = String(lastWorkday.getMonth() + 1).padStart(2, '0');\nconst dd = String(lastWorkday.getDate()).padStart(2, '0');\nconst formattedDate = `${yyyy}-${mm}-${dd}`;\n\nreturn [\n {\n json: {\n lastWorkday: formattedDate\n }\n }\n];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
224,
96
],
"id": "87cb7b72-7c12-453d-b59a-b250461783b2",
"name": "Last workday1"
},
{
"parameters": {
"options": {}
},
"type": "n8n-nodes-base.xml",
"typeVersion": 1,
"position": [
896,
0
],
"id": "451e0c99-87ad-43db-9c4e-df5ae16a434b",
"name": "XML1"
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 21 * * 1-5"
}
]
}
},
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
0,
96
],
"id": "a20fc8f2-6abf-4394-b838-3fb3ed516bea",
"name": "Schedule Trigger"
},
{
"parameters": {
"url": "=https://portal.palletways.com/api/getObman/{{ $json[\"lastWorkday\"] }}?apikey=&output=xml",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "apikey",
"value": "SXJaM7PLjZDqfsnXSDP8Y9wDY6crxJySBg705MQEPus%3D"
},
{
"name": "date",
"value": "={{ $json[\"lastWorkday\"] }}"
},
{
"name": "output",
"value": "xml"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
448,
96
],
"id": "66d7ad62-59d6-4717-9ba3-9e077e5f9046",
"name": "HTTP Request1"
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"leftValue": "={{ $json.data }}",
"rightValue": "No results found",
"operator": {
"type": "string",
"operation": "notContains"
},
"id": "de688612-45c4-4848-bc4e-a103c8698662"
}
],
"combinator": "and"
}
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "4a99ac98-84cc-4ac7-a6ca-41b2c483b968",
"leftValue": "={{ $json.data }}",
"rightValue": "No results found",
"operator": {
"type": "string",
"operation": "contains"
}
}
],
"combinator": "and"
}
}
]
},
"options": {}
},
"type": "n8n-nodes-base.switch",
"typeVersion": 3.4,
"position": [
672,
96
],
"id": "0289dc6a-3689-4a26-b5d4-c972ffbc94b3",
"name": "Switch"
},
{
"parameters": {
"authentication": "webhook",
"content": "=Helaas vandaag geen zendingen",
"options": {}
},
"type": "n8n-nodes-base.discord",
"typeVersion": 2,
"position": [
896,
192
],
"id": "2f225c34-5c28-4fb9-83bb-db7a5aa447da",
"name": "Discord1",
"webhookId": "a58fdc48-676c-4c66-83cc-08d51fe6162e",
"credentials": {
"discordWebhookApi": {
"id": "VYa8b5qqxdFRsDTN",
"name": "Discord Webhook account"
}
}
},
{
"parameters": {
"jsCode": "const dataArray = $input.first().json.results.result || [];\nconst arr = Array.isArray(dataArray) ? dataArray : [dataArray];\nreturn arr.map(item => ({ json: item }));"
},
"id": "7cb6c1fb-82ab-4697-a87b-1071ee749f82",
"name": "Splits items",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1120,
0
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "04c98403-7693-44ad-b62a-f0f59263da38",
"name": "TrackingID",
"value": "={{ $json.TrackingID }}",
"type": "string"
},
{
"id": "aa60dff2-1dbf-4b90-b3fe-075bf4f67e4c",
"name": "Lifts",
"value": "={{ $json.Lifts }}",
"type": "string"
},
{
"id": "156a7b15-f318-46b2-a3ef-a52b323dddfd",
"name": "del_company",
"value": "={{ $json.del_company }}",
"type": "string"
},
{
"id": "a581e643-2a9f-42d6-93e5-37550fd150e5",
"name": "del_addr1",
"value": "={{ $json.del_addr1 }}",
"type": "string"
},
{
"id": "936c0d1e-5aff-4efb-9796-62b82cf926ef",
"name": "del_town",
"value": "={{ $json.del_town }}",
"type": "string"
},
{
"id": "fb9d6c9f-fa6f-4fc7-8a6b-ddd77b71cd12",
"name": "l_binrequest",
"value": "={{ $json.l_binrequest }}",
"type": "string"
},
{
"id": "d42734cc-5864-4155-b7e6-337a34d09f34",
"name": "del_postcode",
"value": "={{ $json.del_postcode }}",
"type": "string"
},
{
"id": "f95601e7-de43-4b6f-9dc2-318b2ddcd510",
"name": "",
"value": "",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
1344,
0
],
"id": "b6a4ecba-a5ef-48fc-bfd2-ad67f4a626a5",
"name": "Edit Fields"
},
{
"parameters": {
"jsCode": "// n8n Code node (JavaScript)\n// Input: meerdere items met velden zoals TrackingID, Lifts, del_company, del_addr1, del_town, del_postcode, l_binrequest\n// Output: 1 item met { html, subject, totals... }\n\nfunction escapeHtml(value) {\n const s = String(value ?? '');\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\nfunction norm(val) {\n return String(val ?? '').trim();\n}\n\nfunction isYes(val) {\n const v = norm(val).toLowerCase();\n return v === 'yes' || v === 'true' || v === '1' || v === 'ja';\n}\n\n\nconst rows = $input.all().map(i => i.json);\n\n// sorteer op postcode (laag -> hoog), spaties eruit zodat \"3454 PT\" goed sorteert\nrows.sort((a, b) => {\n const pa = String(a?.del_postcode ?? '').toUpperCase().replace(/\\s+/g, '');\n const pb = String(b?.del_postcode ?? '').toUpperCase().replace(/\\s+/g, '');\n return pa.localeCompare(pb, 'nl-NL', { numeric: true, sensitivity: 'base' });\n});\n\n\n\n\n// totalen\nconst totalStops = rows.length;\nconst totalLifts = rows.reduce((sum, r) => sum + (parseInt(r.Lifts, 10) || 0), 0);\nconst bookInYes = rows.reduce((sum, r) => sum + (isYes(r.l_binrequest) ? 1 : 0), 0);\n\n// datum/tijd (Amsterdam)\nconst now = new Date();\nconst ts = new Intl.DateTimeFormat('nl-NL', {\n timeZone: 'Europe/Amsterdam',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit'\n}).format(now);\n\nconst subject = `Overzicht zendingen (${totalStops} stops / ${totalLifts} lifts) - ${ts}`;\n\nconst headerHtml = `\n <div style=\"font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #111; line-height: 1.4;\">\n <div style=\"font-size: 18px; font-weight: 700; margin: 0 0 6px 0;\">Overzicht zendingen</div>\n <div style=\"margin: 0 0 14px 0; color: #444;\">\n Gemaakt: <b>${escapeHtml(ts)}</b><br/>\n Stops: <b>${escapeHtml(totalStops)}</b> &nbsp;|&nbsp;\n Lifts: <b>${escapeHtml(totalLifts)}</b> &nbsp;|&nbsp;\n Book-in: <b>${escapeHtml(bookInYes)}</b>\n </div>\n`;\n\n// tabel header\nconst tableHead = `\n <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"border-collapse: collapse; width: 100%; font-family: Arial, Helvetica, sans-serif; font-size: 13px;\">\n <thead>\n <tr>\n <th align=\"left\" style=\"padding: 10px 8px; border-bottom: 2px solid #ddd; background: #f5f5f5;\">TrackingID</th>\n <th align=\"right\" style=\"padding: 10px 8px; border-bottom: 2px solid #ddd; background: #f5f5f5;\">Lifts</th>\n <th align=\"left\" style=\"padding: 10px 8px; border-bottom: 2px solid #ddd; background: #f5f5f5;\">Ontvanger</th>\n <th align=\"left\" style=\"padding: 10px 8px; border-bottom: 2px solid #ddd; background: #f5f5f5;\">Adres</th>\n <th align=\"left\" style=\"padding: 10px 8px; border-bottom: 2px solid #ddd; background: #f5f5f5;\">Postcode</th>\n <th align=\"left\" style=\"padding: 10px 8px; border-bottom: 2px solid #ddd; background: #f5f5f5;\">Plaats</th>\n <th align=\"center\" style=\"padding: 10px 8px; border-bottom: 2px solid #ddd; background: #f5f5f5;\">Book-in</th>\n </tr>\n </thead>\n <tbody>\n`;\n\n// rijen\nconst tableRows = rows.map((r, idx) => {\n const tracking = escapeHtml(norm(r.TrackingID));\n const liftsNum = parseInt(r.Lifts, 10) || 0;\n\n const company = escapeHtml(norm(r.del_company));\n const addr1 = escapeHtml(norm(r.del_addr1));\n const postcode = escapeHtml(norm(r.del_postcode));\n const town = escapeHtml(norm(r.del_town));\n\n const bookIn = isYes(r.l_binrequest);\n const bookInLabel = bookIn ? 'YES' : 'NO';\n\n // zebra + highlight book-in\n const baseBg = (idx % 2 === 0) ? '#ffffff' : '#fafafa';\n const rowBg = bookIn ? '#fff3cd' : baseBg; // licht geel bij book-in\n const rowBorder = '1px solid #eee';\n\n return `\n <tr style=\"background: ${rowBg};\">\n <td style=\"padding: 9px 8px; border-bottom: ${rowBorder}; white-space: nowrap;\">${tracking}</td>\n <td align=\"right\" style=\"padding: 9px 8px; border-bottom: ${rowBorder}; white-space: nowrap;\">${escapeHtml(liftsNum)}</td>\n <td style=\"padding: 9px 8px; border-bottom: ${rowBorder};\">${company}</td>\n <td style=\"padding: 9px 8px; border-bottom: ${rowBorder};\">${addr1}</td>\n <td style=\"padding: 9px 8px; border-bottom: ${rowBorder}; white-space: nowrap;\">${postcode}</td>\n <td style=\"padding: 9px 8px; border-bottom: ${rowBorder};\">${town}</td>\n <td align=\"center\" style=\"padding: 9px 8px; border-bottom: ${rowBorder}; font-weight: ${bookIn ? '700' : '400'};\">\n ${escapeHtml(bookInLabel)}\n </td>\n </tr>\n `;\n}).join('');\n\n// tabel footer + afsluiting\nconst footerHtml = `\n </tbody>\n </table>\n\n <div style=\"margin-top: 14px; color: #666; font-size: 12px;\">\n Dit is een automatische mail.\n </div>\n</div>\n`;\n\nconst html = headerHtml + tableHead + tableRows + footerHtml;\n\n// Output als 1 item (handig voor Email node)\nreturn [\n {\n json: {\n subject,\n html,\n totalStops,\n totalLifts,\n bookInYes,\n generatedAt: ts\n }\n }\n];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1568,
0
],
"id": "7f7d3f6d-2f14-4577-b17c-e152b84c6673",
"name": "Code in JavaScript"
},
{
"parameters": {
"toRecipients": "jeroen@dmsmail.nl",
"subject": "={{$json.subject}}",
"bodyContent": "={{$json.html}}",
"additionalFields": {
"ccRecipients": "p.vanderzaag@dewittransport.nl",
"bodyContentType": "html"
}
},
"type": "n8n-nodes-base.microsoftOutlook",
"typeVersion": 2,
"position": [
1792,
0
],
"id": "564694a0-eb48-4719-8206-7d1af11102e3",
"name": "Send a message1",
"webhookId": "e5bafec1-3fc5-47e6-b233-ceb72cc129eb",
"credentials": {
"microsoftOutlookOAuth2Api": {
"id": "PGANiL6y4sGEEvao",
"name": "Microsoft Outlook Palletways"
}
}
}
],
"pinData": {},
"connections": {
"Last workday1": {
"main": [
[
{
"node": "HTTP Request1",
"type": "main",
"index": 0
}
]
]
},
"XML1": {
"main": [
[
{
"node": "Splits items",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Last workday1",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request1": {
"main": [
[
{
"node": "Switch",
"type": "main",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "XML1",
"type": "main",
"index": 0
}
],
[
{
"node": "Discord1",
"type": "main",
"index": 0
}
]
]
},
"Splits items": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "Code in JavaScript",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript": {
"main": [
[
{
"node": "Send a message1",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1",
"binaryMode": "separate",
"timezone": "Europe/Amsterdam",
"callerPolicy": "workflowsFromSameOwner",
"availableInMCP": false
},
"versionId": "7f7d66d3-e2ef-4f24-b01b-457d58f9a32e",
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "bef8d409866a58c0777dfe7cca1b9c2400fd051c056d361501393ab423006b5f"
},
"nodeGroups": [],
"id": "DlRwcKdGRgo0GfJ2",
"tags": [
{
"updatedAt": "2025-11-11T04:59:39.416Z",
"createdAt": "2025-11-11T04:59:39.416Z",
"id": "ClOZrAjJKoGLFvaO",
"name": "Palletways"
}
]
}