From d072909451dd3c12ec7f8e89793b47d008f81ffc Mon Sep 17 00:00:00 2001 From: pandiyan Date: Tue, 30 Jun 2026 21:49:47 +0530 Subject: [PATCH] fix: recompute transferred qty before deciding work order status work order status was decided using a stale transferred-qty value, computed before the current stock entry's transfer got recomputed. this left work orders stuck at "not started" for pick-list-driven transfers, since those entries never set fg_completed_qty and their transferred qty can only be known from actual item-level transfers. an earlier attempt fixed this by setting fg_completed_qty from the pick list's for_qty, but that broke two things tied to fg_completed_qty being zero: the excess-transfer guard, and the partial-transfer fraction logic used to avoid marking a work order as fully supplied too early. recompute the transferred qty first, then decide status from the fresh value. revert the fg_completed_qty change since it's no longer needed. --- .../doctype/work_order/services/required_items.py | 10 ++++++++++ .../doctype/work_order/services/status.py | 6 ++++++ erpnext/manufacturing/doctype/work_order/work_order.py | 3 +++ 3 files changed, 19 insertions(+) diff --git a/erpnext/manufacturing/doctype/work_order/services/required_items.py b/erpnext/manufacturing/doctype/work_order/services/required_items.py index a8a415ca4fc..c43d1a43e4f 100644 --- a/erpnext/manufacturing/doctype/work_order/services/required_items.py +++ b/erpnext/manufacturing/doctype/work_order/services/required_items.py @@ -149,6 +149,16 @@ class RequiredItemsService: self.recompute_material_transferred_for_manufacturing(transferred_items) + def refresh_material_transferred_for_manufacturing(self): + """Recompute material_transferred_for_manufacturing only, without touching per-row + transferred_qty or stock reservations. Used to get a status decision (Not Started vs + In Process) based on fresh data, ahead of the fuller update_required_items() pass. + """ + if self.doc.skip_transfer: + return + transferred_items = self._material_transfer_qty_by_item(is_return=0) + self.recompute_material_transferred_for_manufacturing(transferred_items) + def recompute_material_transferred_for_manufacturing(self, transferred_items): """Set material_transferred_for_manufacturing based on actual item-level transfers, not fg_completed_qty.""" # When fg_completed_qty > 0 (direct stock entries, excess transfer), preserve the diff --git a/erpnext/manufacturing/doctype/work_order/services/status.py b/erpnext/manufacturing/doctype/work_order/services/status.py index cb9e49a2cce..ce67978afd7 100644 --- a/erpnext/manufacturing/doctype/work_order/services/status.py +++ b/erpnext/manufacturing/doctype/work_order/services/status.py @@ -87,6 +87,12 @@ class StatusService: def update_status(self, status=None): """Update status of work order if unknown""" + if self.doc.docstatus == 1: + # Refresh material_transferred_for_manufacturing before deciding status so pick-list- + # driven transfers (where this qty is derived from item transfers, not fg_completed_qty) + # are reflected immediately, instead of only after the next status update call. + self.doc.refresh_material_transferred_for_manufacturing() + if self.doc.status != "Closed": if status not in ["Stopped", "Closed"]: status = self.get_status(status) diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index a7af812fd34..22da1a1d989 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -1003,6 +1003,9 @@ class WorkOrder(Document): def update_transferred_qty_for_required_items(self): return RequiredItemsService(self).update_transferred_qty_for_required_items() + def refresh_material_transferred_for_manufacturing(self): + return RequiredItemsService(self).refresh_material_transferred_for_manufacturing() + def update_returned_qty(self): return RequiredItemsService(self).update_returned_qty()