From 67bdf3162afed8280df3190a6eab9918c1d4a97b Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@gmail.com>
Date: Thu, 3 Apr 2025 11:22:23 +1100
Subject: [PATCH] Update overdue order notification (#9444)

* Update overdue order notification

- Check individual line items too

* Fix typo
---
 src/backend/InvenTree/order/tasks.py | 31 ++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/src/backend/InvenTree/order/tasks.py b/src/backend/InvenTree/order/tasks.py
index 678a57dfc9..467cdc6bd3 100644
--- a/src/backend/InvenTree/order/tasks.py
+++ b/src/backend/InvenTree/order/tasks.py
@@ -4,6 +4,7 @@ from datetime import datetime, timedelta
 
 from django.contrib.auth.models import User
 from django.db import transaction
+from django.db.models import F
 from django.utils.translation import gettext_lazy as _
 
 import structlog
@@ -61,12 +62,28 @@ def check_overdue_purchase_orders():
     """
     yesterday = datetime.now().date() - timedelta(days=1)
 
+    # Check for PurchaseOrder objects that have a target date of yesterday
     overdue_orders = order.models.PurchaseOrder.objects.filter(
         target_date=yesterday, status__in=PurchaseOrderStatusGroups.OPEN
     )
 
+    # Check for individual line items that are overdue
+    overdue_lines = order.models.PurchaseOrderLineItem.objects.filter(
+        target_date=yesterday,
+        order__status__in=PurchaseOrderStatusGroups.OPEN,
+        received__lt=F('quantity'),
+    )
+
+    notified_orders = set()
+
     for po in overdue_orders:
         notify_overdue_purchase_order(po)
+        notified_orders.add(po.pk)
+
+    for line in overdue_lines:
+        if line.order.pk not in notified_orders:
+            notify_overdue_purchase_order(line.order)
+            notified_orders.add(line.order.pk)
 
 
 def notify_overdue_sales_order(so: order.models.SalesOrder):
@@ -114,8 +131,22 @@ def check_overdue_sales_orders():
         target_date=yesterday, status__in=SalesOrderStatusGroups.OPEN
     )
 
+    overdue_lines = order.models.SalesOrderLineItem.objects.filter(
+        target_date=yesterday,
+        order__status__in=SalesOrderStatusGroups.OPEN,
+        shipped__lt=F('quantity'),
+    )
+
+    notified_orders = set()
+
     for po in overdue_orders:
         notify_overdue_sales_order(po)
+        notified_orders.add(po.pk)
+
+    for line in overdue_lines:
+        if line.order.pk not in notified_orders:
+            notify_overdue_sales_order(line.order)
+            notified_orders.add(line.order.pk)
 
 
 def complete_sales_order_shipment(shipment_id: int, user_id: int) -> None: