AutomationFlowsAI & RAG › Generate Weekly Supply Chain OTIF Reports with Notion and GPT-4o

Generate Weekly Supply Chain OTIF Reports with Notion and GPT-4o

Original n8n title: Generate Weekly Supply Chain Otif Reports and AI Analysis with Notion and Gpt-4o

BySamir Saci @samirsaci on n8n.io

Tags: Logistics, Supply Chain, OTIF, KPI Tracking, Performance Management, AI Analysis, Notion

Cron / scheduled trigger★★★★☆ complexityAI-powered19 nodesOpenAI ChatNotionData TableAgent
AI & RAG Trigger: Cron / scheduled Nodes: 19 Complexity: ★★★★☆ AI nodes: yes Added:

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 →

Download .json
{
  "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.

Pro

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 →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

This n8n template helps you turn inbound messages into a clean, deduped queue of actionable tickets.

OpenAI Chat, Output Parser Structured, Slack +5
AI & RAG

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,

Notion, Agent, OpenAI Chat +6
AI & RAG

This workflow automates customer outreach for marketing campaigns, including customer prioritization, AI-generated emails, automated sending, reply tracking, and meeting scheduling. Data Synchronizati

Agent, Data Table, OpenAI Chat +6
AI & RAG

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

N8N Nodes Serpapi, Text Classifier, Output Parser Structured +6
AI & RAG

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

HTTP Request, Google Drive, OpenAI Chat +4