This workflow corresponds to n8n.io template #13944 — we link there as the canonical source.
This workflow follows the Agent → Datatable recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "e16ae93c-6dc9-4c4c-86f6-4e25c1569e9d",
"name": "Aggregate by Week",
"type": "n8n-nodes-base.code",
"notes": "Groups shipments by ISO week and computes KPIs per week.",
"position": [
3648,
4288
],
"parameters": {
"jsCode": "// ============================================\n// OTIF Scorecard: Aggregate Shipments by Week\n// ============================================\n// Input: raw shipment records with on-time flags and lead times\n// Output: one item per week with aggregated KPIs\n\nconst shipments = $input.all().map(i => i.json);\n\nif (shipments.length === 0) {\n return [{ json: { error: 'No shipments found', count: 0 } }];\n}\n\n// Group by ISO week (Monday start)\nconst byWeek = {};\nfor (const s of shipments) {\n const dt = new Date(s.Order_Time);\n const day = dt.getDay();\n const monday = new Date(dt);\n monday.setDate(dt.getDate() - ((day + 6) % 7));\n const weekKey = monday.toISOString().slice(0, 10);\n\n if (!byWeek[weekKey]) byWeek[weekKey] = [];\n byWeek[weekKey].push(s);\n}\n\n// Compute KPIs per week\nconst results = [];\nfor (const [weekStart, rows] of Object.entries(byWeek)) {\n const n = rows.length;\n const onTime = rows.filter(r => r.Delivery_OnTime === true).length;\n\n // Week end (Sunday)\n const monday = new Date(weekStart);\n const sunday = new Date(monday);\n sunday.setDate(monday.getDate() + 6);\n const weekEnd = sunday.toISOString().slice(0, 10);\n\n // ISO week number\n const d = new Date(weekStart);\n d.setDate(d.getDate() + 3 - ((d.getDay() + 6) % 7));\n const yearStart = new Date(d.getFullYear(), 0, 1);\n const weekNum = Math.ceil((((d - yearStart) / 86400000) + 1) / 7);\n\n results.push({\n json: {\n Name: `Week ${weekNum}`,\n weekStart: weekStart,\n weekEnd: weekEnd,\n totalShipments: n,\n onTimeDeliveries: onTime,\n avgLeadTimeDays: Math.round(rows.reduce((s, r) => s + (r.LT_Days || 0), 0) / n * 10) / 10,\n avgLeadTimeHrs: Math.round(rows.reduce((s, r) => s + (r.LT_Hours || 0), 0) / n * 10) / 10,\n transmissionOnTime: Math.round(rows.filter(r => r.Transmission_OnTime === true).length / n * 1000) / 10,\n loadingOnTime: Math.round(rows.filter(r => r.Loading_OnTime === true).length / n * 1000) / 10,\n airportOnTime: Math.round(rows.filter(r => r.Airport_OnTime === true).length / n * 1000) / 10,\n landingOnTime: Math.round(rows.filter(r => r.Landing_OnTime === true).length / n * 1000) / 10,\n deliveryOnTime: Math.round(onTime / n * 1000) / 10,\n lateShipments: n - onTime\n }\n });\n}\n\n// Sort by weekStart ascending\nresults.sort((a, b) => a.json.weekStart.localeCompare(b.json.weekStart));\n\nreturn results;"
},
"typeVersion": 2
},
{
"id": "7b996737-2b66-491b-a693-2b14f80e6b0e",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
4064,
3824
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "gpt-4o-mini"
},
"options": {
"maxTokens": 300,
"temperature": 0.3
}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "d98ec9fd-979b-45b2-9d3b-299d6f752914",
"name": "Fill the report",
"type": "n8n-nodes-base.notion",
"position": [
4464,
3744
],
"parameters": {
"title": "={{ $('Aggregate by Week').item.json.Name }}",
"simple": false,
"options": {
"icon": "\ud83d\ude9a",
"iconType": "emoji"
},
"resource": "databasePage",
"databaseId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "Daily OTIF Summary"
},
"propertiesUi": {
"propertyValues": [
{
"key": "Name|title",
"title": "={{ $('Aggregate by Week').item.json.Name }}"
},
{
"key": "Airport On-Time %|number",
"numberValue": "={{ $('Aggregate by Week').item.json.airportOnTime }}"
},
{
"key": "Avg Lead Time (days)|number",
"numberValue": "={{ $('Aggregate by Week').item.json.avgLeadTimeDays }}"
},
{
"key": "Avg Lead Time (hrs)|number",
"numberValue": "={{ $('Aggregate by Week').item.json.avgLeadTimeHrs }}"
},
{
"key": "Date|date",
"range": true,
"dateEnd": "={{ $('Aggregate by Week').item.json.weekEnd }}",
"dateStart": "={{ $('Aggregate by Week').item.json.weekStart }}"
},
{
"key": "Delivery On-Time %|number",
"numberValue": "={{ $('Aggregate by Week').item.json.deliveryOnTime }}"
},
{
"key": "Landing On-Time %|number",
"numberValue": "={{ $('Aggregate by Week').item.json.landingOnTime }}"
},
{
"key": "Late Shipments|number",
"numberValue": "={{ $('Aggregate by Week').item.json.lateShipments }}"
},
{
"key": "Loading On-Time %|number",
"numberValue": "={{ $('Aggregate by Week').item.json.loadingOnTime }}"
},
{
"key": "On-Time Deliveries|number",
"numberValue": "={{ $('Aggregate by Week').item.json.onTimeDeliveries }}"
},
{
"key": "Total Shipments|number",
"numberValue": "={{ $('Aggregate by Week').item.json.totalShipments }}"
},
{
"key": "Transmission On-Time %|number",
"numberValue": "={{ $('Aggregate by Week').item.json.transmissionOnTime }}"
},
{
"key": "AI Analysis|rich_text"
}
]
}
},
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"notesInFlow": true,
"typeVersion": 2.2
},
{
"id": "e76bc2e5-43d5-4d64-a2de-8d02240742a2",
"name": "OpenAI Chat Model Global",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
4048,
4304
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "gpt-4o-mini"
},
"options": {
"maxTokens": 600,
"temperature": 0.3
}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "c00ba339-60ef-4736-8305-36202e2ae857",
"name": "Collect Shipments from TMS & WMS",
"type": "n8n-nodes-base.dataTable",
"position": [
3456,
4288
],
"parameters": {
"operation": "get",
"returnAll": true,
"dataTableId": {
"__rl": true,
"mode": "",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
}
},
"typeVersion": 1.1
},
{
"id": "56fce52f-074b-46b3-a4e0-eae75c07fcc2",
"name": "AI Agent Weekly Performance Summary",
"type": "@n8n/n8n-nodes-langchain.agent",
"notes": "AI Agent that generates a per-week analysis comment.",
"position": [
4048,
3680
],
"parameters": {
"text": "=Analyse this weekly OTIF scorecard for retail logistics ({{ $json.Name }}, {{ $json.weekStart }} to {{ $json.weekEnd }}):\n\n- Total Shipments: {{ $json.totalShipments }}\n- On-Time Deliveries: {{ $json.onTimeDeliveries }}\n- Late Shipments: {{ $json.lateShipments }}\n- OTIF Rate: {{ Math.round($json.onTimeDeliveries / $json.totalShipments * 1000) / 10 }}%\n- Avg Lead Time: {{ $json.avgLeadTimeDays }} days ({{ $json.avgLeadTimeHrs }} hours)\n\nCheckpoint On-Time Rates:\n- Transmission: {{ $json.transmissionOnTime }}%\n- Loading: {{ $json.loadingOnTime }}%\n- Airport: {{ $json.airportOnTime }}%\n- Landing: {{ $json.landingOnTime }}%\n- Delivery: {{ $json.deliveryOnTime }}%\n\nProvide a brief analysis (3-4 sentences) highlighting: overall performance assessment, the weakest checkpoint causing most delays, and one specific recommendation for improvement. Be concise and data-driven.",
"options": {
"systemMessage": "You are a supply chain performance analyst specialising in retail logistics OTIF (On-Time In-Full) analysis. Provide concise, actionable insights. Use British spelling."
},
"promptType": "define"
},
"typeVersion": 1.7
},
{
"id": "b1dfca97-d910-48f4-887d-573e2702556e",
"name": "AI Agent Global Performance Summary",
"type": "@n8n/n8n-nodes-langchain.agent",
"notes": "AI Agent that generates a global analysis across all weeks.",
"position": [
4064,
4144
],
"parameters": {
"text": "={{ $json.globalPrompt }}\n\nProvide a comprehensive analysis (5-7 sentences) covering:\n1. Overall trend across weeks (improving, declining, or stable)\n2. The most consistent bottleneck checkpoint\n3. Best and worst performing weeks with reasons\n4. Two specific, actionable recommendations\n5. A brief outlook\n\nFormat with bullet points. Be concise and data-driven.",
"options": {
"systemMessage": "You are a supply chain performance analyst specialising in retail logistics OTIF analysis. Provide a global weekly summary for management review. Use British spelling. Do not use markdown headers, only bullet points and plain text."
},
"promptType": "define"
},
"typeVersion": 1.7
},
{
"id": "880cd90b-78c9-4fbd-a85f-c1e8a8915cfa",
"name": "Update Global Performance Summary",
"type": "n8n-nodes-base.notion",
"position": [
4496,
3984
],
"parameters": {
"pageId": {
"__rl": true,
"mode": "id",
"value": ""
},
"simple": false,
"options": {},
"resource": "databasePage",
"operation": "update",
"propertiesUi": {
"propertyValues": [
{
"key": "Name|title",
"title": "Overall Performance Summary"
},
{
"key": "Weekly Analysis|rich_text",
"textContent": "={{ $json.output }}"
},
{
"key": "Type|select",
"selectValue": "Global Summary"
},
{
"key": "Updated|date",
"includeTime": false
}
]
}
},
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"notesInFlow": true,
"typeVersion": 2.2
},
{
"id": "9f330093-11f0-4037-80ee-a8ba81262152",
"name": "Create Weekly Performance Card",
"type": "n8n-nodes-base.notion",
"position": [
4656,
3680
],
"parameters": {
"title": "={{ $('Aggregate by Week').item.json.Name }}",
"simple": false,
"options": {
"icon": "\ud83d\udcca",
"iconType": "emoji"
},
"resource": "databasePage",
"databaseId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "AI Analysis"
},
"propertiesUi": {
"propertyValues": [
{
"key": "Name|title",
"title": "={{ $('Aggregate by Week').item.json.Name }}"
},
{
"key": "Weekly Analysis|rich_text",
"textContent": "={{ $json.output }}"
},
{
"key": "Type|select",
"selectValue": "Weekly Analysis"
},
{
"key": "Updated|date",
"includeTime": false
}
]
}
},
"credentials": {
"notionApi": {
"name": "<your credential>"
}
},
"notesInFlow": true,
"typeVersion": 2.2
},
{
"id": "32dd552a-cecd-4602-8497-d92d1a59c8f9",
"name": "Prepare Global Summary Prompt with Indicators",
"type": "n8n-nodes-base.code",
"notes": "Aggregates all weekly KPIs into a single prompt for the global AI summary.",
"position": [
3824,
4288
],
"parameters": {
"jsCode": "// ============================================\n// Prepare Global Summary Prompt\n// ============================================\n// Collects all weekly KPIs into a single prompt for the global AI analysis\n\nconst items = $input.all();\nconst weeks = items.map(i => i.json);\n\nweeks.sort((a, b) => a.weekStart.localeCompare(b.weekStart));\n\nlet summary = 'Here are the weekly OTIF scorecards for retail logistics:\\n\\n';\nfor (const w of weeks) {\n const otif = Math.round(w.onTimeDeliveries / w.totalShipments * 1000) / 10;\n summary += `${w.Name} (${w.weekStart} to ${w.weekEnd}):\\n`;\n summary += ` Shipments: ${w.totalShipments}, On-Time: ${w.onTimeDeliveries}, Late: ${w.lateShipments}, OTIF: ${otif}%\\n`;\n summary += ` Avg Lead Time: ${w.avgLeadTimeDays} days\\n`;\n summary += ` Checkpoints: Transmission ${w.transmissionOnTime}%, Loading ${w.loadingOnTime}%, Airport ${w.airportOnTime}%, Landing ${w.landingOnTime}%, Delivery ${w.deliveryOnTime}%\\n\\n`;\n}\n\nreturn [{ json: { globalPrompt: summary } }];"
},
"typeVersion": 2
},
{
"id": "7390e7a0-b8b4-4a01-921c-c88b14a743be",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
3264,
3584
],
"parameters": {
"width": 704,
"height": 596,
"content": "## Supply Chain OTIF Performance Scorecard for Retail Logistics\n\nAutomatically aggregate shipment data, compute weekly OTIF KPIs, generate AI-powered performance analysis, and push everything to a Notion dashboard.\n\n### How it Works\n1. **Collect** raw shipment records from your TMS/WMS data source.\n2. **Aggregate** shipments by ISO week and compute KPIs (OTIF rate, lead times, checkpoint on-time rates).\n3. **AI Weekly Analysis** generates a per-week performance comment using an AI Agent.\n4. **Push to Notion** creates one row per week in the OTIF Summary database and one card per week in the AI Analysis database.\n5. **AI Global Analysis** generates a cross-week summary with trends and recommendations.\n6. **Update Global Card** pushes the overall summary to a dedicated Notion database row.\n\n### Setup\n- [ ] Connect your **data source** (DataTable, database, or API) to the \"Collect Shipments\" node\n- [ ] Add your **OpenAI API Key** to both OpenAI Chat Model nodes\n- [ ] Add your **Notion API credentials** to all Notion nodes\n- [ ] Verify the **Notion database IDs** match your workspace\n\n### Customisation\n- Adjust the AI prompts to change the analysis style or language\n- Modify the Aggregate by Week code to add custom KPI\n"
},
"typeVersion": 1
},
{
"id": "048fe5f8-7fc0-4d3a-950b-f1246f23b344",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
3264,
4192
],
"parameters": {
"color": 7,
"width": 340,
"height": 252,
"content": "## 1. Trigger and collect shipment records"
},
"typeVersion": 1
},
{
"id": "08031ce3-58b4-407a-bc25-773375a71b26",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
3616,
4192
],
"parameters": {
"color": 7,
"width": 348,
"height": 252,
"content": "## 2. Aggregate shipments and compute KPIs"
},
"typeVersion": 1
},
{
"id": "8d801606-75aa-466d-a13a-4bd60fdbb56a",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
3984,
3584
],
"parameters": {
"color": 7,
"width": 372,
"height": 412,
"content": "## 3. AI Agent generates a per-week performance analysis"
},
"typeVersion": 1
},
{
"id": "a7a3a19c-43a4-46b4-81aa-bd2ef3558422",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
4368,
3584
],
"parameters": {
"color": 7,
"width": 472,
"height": 316,
"content": "## 4. Push weekly KPIs and AI analysis cards to Notion"
},
"typeVersion": 1
},
{
"id": "eeedc70d-7b24-4d2d-ac4c-99234ec9b53b",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
3984,
4000
],
"parameters": {
"color": 7,
"width": 372,
"height": 452,
"content": "## 5. AI Agent generates a global cross-week performance summary"
},
"typeVersion": 1
},
{
"id": "bcca7e93-e8d2-4a94-8b47-09709c745427",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
4368,
3904
],
"parameters": {
"color": 7,
"width": 476,
"height": 220,
"content": "## 6. Update the global performance summary card in Notion"
},
"typeVersion": 1
},
{
"id": "acbf456d-dadf-4663-98ca-21895de8ffe5",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
4368,
4144
],
"parameters": {
"width": 480,
"height": 304,
"content": "## [Tutorial](https://www.youtube.com/watch?v=tOT8XhQ7eB8)\n@[youtube](tOT8XhQ7eB8)"
},
"typeVersion": 1
},
{
"id": "cf03fa28-3cf7-42db-a649-9ec75db6fa3c",
"name": "Weekly Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
3280,
4288
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks"
}
]
}
},
"typeVersion": 1.3
}
],
"connections": {
"Weekly Trigger": {
"main": [
[
{
"node": "Collect Shipments from TMS & WMS",
"type": "main",
"index": 0
}
]
]
},
"Aggregate by Week": {
"main": [
[
{
"node": "AI Agent Weekly Performance Summary",
"type": "main",
"index": 0
},
{
"node": "Prepare Global Summary Prompt with Indicators",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent Weekly Performance Summary",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"OpenAI Chat Model Global": {
"ai_languageModel": [
[
{
"node": "AI Agent Global Performance Summary",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Collect Shipments from TMS & WMS": {
"main": [
[
{
"node": "Aggregate by Week",
"type": "main",
"index": 0
}
]
]
},
"AI Agent Global Performance Summary": {
"main": [
[
{
"node": "Update Global Performance Summary",
"type": "main",
"index": 0
}
]
]
},
"AI Agent Weekly Performance Summary": {
"main": [
[
{
"node": "Fill the report",
"type": "main",
"index": 0
},
{
"node": "Create Weekly Performance Card",
"type": "main",
"index": 0
}
]
]
},
"Prepare Global Summary Prompt with Indicators": {
"main": [
[
{
"node": "AI Agent Global Performance Summary",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
notionApiopenAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Tags: Logistics, Supply Chain, OTIF, KPI Tracking, Performance Management, AI Analysis, Notion
Source: https://n8n.io/workflows/13944/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This n8n template helps you turn inbound messages into a clean, deduped queue of actionable tickets.
This template is built for content creators, founders, solopreneurs, content marketers, and agencies who want to publish consistent, research-backed content across 4 social platforms without writing,
This workflow automates customer outreach for marketing campaigns, including customer prioritization, AI-generated emails, automated sending, reply tracking, and meeting scheduling. Data Synchronizati
V2 (2026) available! An intelligent, fully automated news aggregation system that collects articles from multiple sources (RSS feeds + Google Search), uses AI to classify and summarize the most import
This workflow automates your daily social media content creation by generating unique, on-brand posts based on specific themes stored in Notion. It creates images using Fal.ai, writes captions with Op