Upload files to "palletways"

voeg zendingen toe die wij moeten uitleveren aan de database
This commit is contained in:
adminjeroen committed 2026-07-02 21:57:58 +02:00
1 parent e14003d64b
commit 3a1163d5a7
1 file changed
+289
+289
View File
@@ -0,0 +1,289 @@
{
"name": "Palletways BI - Leveringen",
"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": [
480,
-144
],
"id": "08c5aa91-9a51-49f7-ab05-c103ab5c53f4",
"name": "Last workday1"
},
{
"parameters": {
"jsCode": "const xmlData = items[0]?.json?.data;\nconst listDate = (() => {\n try { return $items('Last workday1')?.[0]?.json?.lastWorkday || null; } catch (e) { return null; }\n})();\n\nif (typeof xmlData !== 'string') {\n throw new Error('Expected an XML string in $input.first().json.data');\n}\n\nconst out = [];\nconst seen = new Set();\nconst regex = /<TrackingID>([\\s\\S]*?)<\\/TrackingID>/gi;\nlet match;\n\nwhile ((match = regex.exec(xmlData)) !== null) {\n const trackingid = String(match[1] || '').trim().toUpperCase();\n if (!trackingid || seen.has(trackingid)) continue;\n seen.add(trackingid);\n\n out.push({\n json: {\n trackingid,\n source_name: 'PW_DELIVERY_LIST',\n delivery_list_date: listDate,\n },\n });\n}\n\nreturn out;"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
960,
-144
],
"id": "b6a0bffa-2e63-40d0-b91f-d9e3c330546b",
"name": "Extract TrackingIDs"
},
{
"parameters": {
"url": "=https://api.palletways.com/getconsignment/{{ $json.trackingid }}?apikey=SXJaM7PLjZDqfsnXSDP8Y9wDY6crxJySBg705MQEPus%3D",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1440,
-144
],
"id": "094aa988-beee-448f-9aad-d14e69c55ee7",
"name": "Get Consignment"
},
{
"parameters": {
"options": {}
},
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 3,
"position": [
1200,
-144
],
"id": "0df72e64-9034-4643-b984-4f0ee5396ada",
"name": "Loop Over Items"
},
{
"parameters": {
"amount": 0.5
},
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
2160,
-144
],
"id": "537e024d-1ec6-43cc-92fe-22a7347f3306",
"name": "Wait",
"webhookId": "b17f739d-d020-4810-b669-e01b2df86c08"
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 21 * * 1-5"
}
]
}
},
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
240,
-144
],
"id": "ec8c08dc-9dcb-424c-b194-f99a5e43c3d3",
"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": [
720,
-144
],
"id": "29d07f3e-bb03-404e-9de0-96c77d15f472",
"name": "Get Obman delivery list"
},
{
"parameters": {
"jsCode": "const OUR_DEPOT = 464;\nconst out = [];\n\nconst asArray = (v) => {\n if (v === undefined || v === null || v === '') return [];\n return Array.isArray(v) ? v : [v];\n};\n\nconst text = (v) => {\n if (v === undefined || v === null) return null;\n const s = String(v).trim();\n return s === '' ? null : s;\n};\n\nconst num = (v) => {\n const s = text(v);\n if (s === null) return null;\n const n = Number(String(s).replace(',', '.'));\n return Number.isFinite(n) ? n : null;\n};\n\nconst intVal = (v) => {\n const n = num(v);\n return n === null ? null : Math.trunc(n);\n};\n\nconst yesNoBool = (v) => {\n const s = String(v ?? '').trim().toLowerCase();\n if (['yes', 'true', '1', 'ja', 'y', 'on'].includes(s)) return true;\n if (['no', 'false', '0', 'nee', 'n', 'off'].includes(s)) return false;\n return null;\n};\n\nconst normalizeCountry = (v) => {\n const s = text(v);\n if (!s) return null;\n const u = s.toUpperCase();\n return u === 'UK' ? 'GB' : u;\n};\n\nconst decodeXml = (s) => String(s ?? '')\n .replace(/&amp;/g, '&')\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&apos;/g, \"'\");\n\nconst tag = (xml, name) => {\n if (!xml) return null;\n const re = new RegExp(`<${name}(?:\\\\s[^>]*)?>([\\\\s\\\\S]*?)<\\\\/${name}>`, 'i');\n const m = String(xml).match(re);\n return m ? text(decodeXml(m[1])) : null;\n};\n\nconst blocks = (xml, name) => {\n if (!xml) return [];\n const re = new RegExp(`<${name}(?:\\\\s[^>]*)?>([\\\\s\\\\S]*?)<\\\\/${name}>`, 'gi');\n const result = [];\n let m;\n while ((m = re.exec(String(xml))) !== null) {\n result.push(m[1]);\n }\n return result;\n};\n\nconst firstBlock = (xml, name) => blocks(xml, name)[0] || '';\n\nconst safeNodeItem = (name) => {\n try {\n return $(name).item.json || {};\n } catch (e) {\n try {\n return $items(name)?.[0]?.json || {};\n } catch (e2) {\n return {};\n }\n }\n};\n\nconst makeDateTime = (dateValue, timeValue) => {\n const d = text(dateValue);\n const t = text(timeValue);\n if (!d) return null;\n\n // Already datetime\n if (d.includes('T') || /^\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}/.test(d)) {\n return d.replace(' ', 'T');\n }\n\n return `${d}T${t || '00:00:00'}`;\n};\n\nconst dateOnly = (v) => {\n const s = text(v);\n if (!s) return null;\n return s.substring(0, 10);\n};\n\nconst statusFlags = (statusValue, statusDateTime) => {\n const status = text(statusValue);\n const s = String(status || '').toLowerCase();\n\n const isDelivered =\n s.includes('delivered') ||\n s.includes('afgeleverd') ||\n s.includes('pod');\n\n const isCollected =\n s.includes('collected') ||\n s.includes('picked up') ||\n s.includes('pickup complete') ||\n s.includes('collection complete') ||\n s.includes('opgehaald') ||\n s.includes('afgehaald');\n\n const isDeleted =\n s.includes('deleted') ||\n s.includes('removed') ||\n s.includes('cancelled') ||\n s.includes('canceled') ||\n s.includes('verwijderd') ||\n s.includes('geannuleerd');\n\n return {\n current_status: status,\n current_status_at: status ? statusDateTime : null,\n is_delivered: isDelivered,\n delivered_at: isDelivered ? statusDateTime : null,\n is_collected: isCollected,\n collected_at: isCollected ? statusDateTime : null,\n is_deleted: isDeleted,\n deleted_at: isDeleted ? statusDateTime : null,\n status_source: status ? 'PALLETWAYS_API' : null,\n };\n};\n\nfunction addressFromXml(consignmentXml, type) {\n const addressBlocks = blocks(consignmentXml, 'Address');\n const wanted = addressBlocks.find(a => String(tag(a, 'Type') || '').toLowerCase() === type.toLowerCase()) || '';\n return {\n contact: tag(wanted, 'ContactName'),\n company: tag(wanted, 'CompanyName'),\n addr1: tag(wanted, 'Addr1'),\n addr2: tag(wanted, 'Addr2'),\n addr3: tag(wanted, 'Addr3'),\n addr4: tag(wanted, 'Addr4'),\n town: tag(wanted, 'Town'),\n county: tag(wanted, 'County'),\n country: normalizeCountry(tag(wanted, 'Country')),\n postcode: tag(wanted, 'PostCode'),\n };\n}\n\nfunction getAddressFromJson(consignment, type) {\n const addresses = asArray(consignment.Address);\n return addresses.find(a => String(a.Type || '').toLowerCase() === type.toLowerCase()) || {};\n}\n\nfunction getServiceFromXml(consignmentXml, type) {\n const serviceBlocks = blocks(consignmentXml, 'Service');\n return serviceBlocks.find(s => String(tag(s, 'Type') || '').toLowerCase() === type.toLowerCase()) || '';\n}\n\nfunction getServiceFromJson(consignment, type) {\n const services = asArray(consignment.Service);\n return services.find(s => String(s?.Type || '').toLowerCase() === type.toLowerCase()) || {};\n}\n\nfunction countPalletCodesXml(consignmentXml) {\n return blocks(consignmentXml, 'Pallet')\n .map(p => text(decodeXml(p)))\n .filter(Boolean).length;\n}\n\nfunction countPalletCodesJson(palletValue) {\n return asArrLine truncated
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1680,
-144
],
"id": "2c6a7fea-2aeb-457f-b623-daa16e39b620",
"name": "Normalize Palletways Consignment"
},
{
"parameters": {
"operation": "executeQuery",
"query": "insert into palletways_shipments (\n tracking_id,\n consignment_number,\n reference,\n collection_reference,\n manifest_date,\n manifest_time,\n paying_depot,\n collection_depot,\n delivery_depot,\n is_our_paying_depot,\n is_collection_by_us,\n is_delivery_by_us,\n is_manifested,\n account_name,\n account_code,\n consignment_type,\n classification,\n service_type,\n service_code,\n service_surcharge,\n collection_service_code,\n collection_service_surcharge,\n delivery_service_code,\n delivery_service_surcharge,\n due_date,\n due_time,\n planned_collection_date,\n planned_delivery_date,\n delivery_list_date,\n collection_list_date,\n manifested_at,\n lifts,\n weight_kg,\n bill_unit_type,\n bill_unit_amount,\n pallet_count,\n handball,\n tail_lift,\n adr_goods,\n limited_quantity_goods,\n booked_in,\n book_in_request,\n collection_company,\n collection_contact,\n collection_addr1,\n collection_addr2,\n collection_addr3,\n collection_addr4,\n collection_town,\n collection_county,\n collection_country,\n collection_postcode,\n delivery_company,\n delivery_contact,\n delivery_addr1,\n delivery_addr2,\n delivery_addr3,\n delivery_addr4,\n delivery_town,\n delivery_county,\n delivery_country,\n delivery_postcode,\n hub_sequence,\n hub_name,\n current_status,\n current_status_at,\n is_delivered,\n delivered_at,\n is_deleted,\n deleted_at,\n is_collected,\n collected_at,\n status_source,\n source_first_seen,\n source_last_seen,\n first_seen_in_bi_at,\n last_api_seen_at,\n raw_json,\n last_seen_at\n)\nvalues (\n '{{ ($json.tracking_id ?? \"\").replaceAll(\"'\", \"''\") }}',\n '{{ ($json.consignment_number ?? \"\").replaceAll(\"'\", \"''\") }}',\n '{{ ($json.reference ?? \"\").replaceAll(\"'\", \"''\") }}',\n '{{ ($json.collection_reference ?? \"\").replaceAll(\"'\", \"''\") }}',\n\n {{ $json.manifest_date ? \"'\" + $json.manifest_date + \"'\" : \"null\" }},\n {{ $json.manifest_time ? \"'\" + $json.manifest_time + \"'\" : \"null\" }},\n\n {{ $json.paying_depot ?? \"null\" }},\n {{ $json.collection_depot ?? \"null\" }},\n {{ $json.delivery_depot ?? \"null\" }},\n\n {{ $json.is_our_paying_depot ? \"true\" : \"false\" }},\n {{ $json.is_collection_by_us ? \"true\" : \"false\" }},\n {{ $json.is_delivery_by_us ? \"true\" : \"false\" }},\n {{ $json.is_manifested ? \"true\" : \"false\" }},\n\n '{{ ($json.account_name ?? \"\").replaceAll(\"'\", \"''\") }}',\n '{{ ($json.account_code ?? \"\").replaceAll(\"'\", \"''\") }}',\n '{{ ($json.consignment_type ?? \"\").replaceAll(\"'\", \"''\") }}',\n '{{ ($json.classification ?? \"\").replaceAll(\"'\", \"''\") }}',\n\n '{{ ($json.service_type ?? \"\").replaceAll(\"'\", \"''\") }}',\n '{{ ($json.service_code ?? \"\").replaceAll(\"'\", \"''\") }}',\n '{{ ($json.service_surcharge ?? \"\").replaceAll(\"'\", \"''\") }}',\n\n '{{ ($json.collection_service_code ?? \"\").replaceAll(\"'\", \"''\") }}',\n '{{ ($json.collection_service_surcharge ?? \"\").replaceAll(\"'\", \"''\") }}',\n '{{ ($json.delivery_service_code ?? \"\").replaceAll(\"'\", \"''\") }}',\n '{{ ($json.delivery_service_surcharge ?? \"\").replaceAll(\"'\", \"''\") }}',\n\n {{ $json.due_date ? \"'\" + $json.due_date + \"'\" : \"null\" }},\n {{ $json.due_time ? \"'\" + $json.due_time + \"'\" : \"null\" }},\n\n {{ $json.planned_collection_date ? \"'\" + $json.planned_collection_date + \"'\" : \"null\" }},\n {{ $json.planned_delivery_date ? \"'\" + $json.planned_delivery_date + \"'\" : \"null\" }},\n {{ $json.delivery_list_date ? \"'\" + $json.delivery_list_date + \"'\" : \"null\" }},\n {{ $json.collection_list_date ? \"'\" + $json.collection_list_date + \"'\" : \"null\" }},\n {{ $json.manifested_at ? \"'\" + $json.manifested_at + \"'\" : \"null\" }},\n\n {{ $json.lifts ?? \"null\" }},\n {{ $json.weight_kg ?? \"null\" }},\n '{{ ($json.bill_unit_type ?? \"\").replaceAll(\"'\", \"''\") }}',\n {{ $json.bill_unit_amount ?? \"null\" }},\n {{ $json.pallet_count ?? \"null\" }},\n\n {{ $json.handball === null || $json.handball === undefined ? \"null\" : ($json.handball ? \"true\" : \"false\") }},\n {{ $json.tail_lift === null || $json.tail_lift === undefined ? \"null\" : ($json.tail_lift ? \"true\" : \"false\") }},\n {{ $json.adr_goods === null || $json.adr_goods === undefined ? \"null\" : ($json.adr_goods ? \"true\" : \"false\") }},\n {{ $json.limited_quantity_goods === null || $json.limited_quantity_goods === undefined ? \"null\" : ($json.limited_quantity_goods ? \"true\" : \"false\") }},\n {{ $json.booked_in === null || $json.booked_in === undefined ? \"null\" : ($json.booked_in ? \"true\" : \"false\") }},\n {{ $json.book_in_request === null || $json.book_in_reLine truncated
"options": {}
},
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.6,
"position": [
1920,
-144
],
"id": "c679ba46-3029-41fc-a066-e1c243dcf358",
"name": "Upsert Palletways BI",
"credentials": {
"postgres": {
"id": "a0jnANQ89VLSby0b",
"name": "Palletways DB"
}
}
}
],
"pinData": {},
"connections": {
"Schedule Trigger": {
"main": [
[
{
"node": "Last workday1",
"type": "main",
"index": 0
}
]
]
},
"Last workday1": {
"main": [
[
{
"node": "Get Obman delivery list",
"type": "main",
"index": 0
}
]
]
},
"Get Obman delivery list": {
"main": [
[
{
"node": "Extract TrackingIDs",
"type": "main",
"index": 0
}
]
]
},
"Extract TrackingIDs": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "Get Consignment",
"type": "main",
"index": 0
}
]
]
},
"Get Consignment": {
"main": [
[
{
"node": "Normalize Palletways Consignment",
"type": "main",
"index": 0
}
]
]
},
"Normalize Palletways Consignment": {
"main": [
[
{
"node": "Upsert Palletways BI",
"type": "main",
"index": 0
}
]
]
},
"Upsert Palletways BI": {
"main": [
[
{
"node": "Wait",
"type": "main",
"index": 0
}
]
]
},
"Wait": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1",
"binaryMode": "separate",
"timezone": "Europe/Amsterdam",
"callerPolicy": "workflowsFromSameOwner",
"availableInMCP": false
},
"versionId": "a07a812c-8e82-4922-933d-587ad44e0c9e",
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "bef8d409866a58c0777dfe7cca1b9c2400fd051c056d361501393ab423006b5f"
},
"nodeGroups": [],
"id": "AREbn3cNh6zN9R9w",
"tags": [
{
"updatedAt": "2025-11-11T04:59:39.416Z",
"createdAt": "2025-11-11T04:59:39.416Z",
"id": "ClOZrAjJKoGLFvaO",
"name": "Palletways"
},
{
"updatedAt": "2025-11-09T14:44:19.471Z",
"createdAt": "2025-11-09T14:44:19.471Z",
"id": "DHSMO2U01lFZRZ27",
"name": "Productie"
}
]
}