From ba17fdd07221177c9f94023304a0c070377b26b6 Mon Sep 17 00:00:00 2001 From: Sudharsanan11 Date: Sun, 1 Feb 2026 10:42:33 +0530 Subject: [PATCH 1/2] fix(stock): include subcontracting order qty while calculating the bin qty (cherry picked from commit de8f8ef9f4d882f75bfb35aff4331a8e14e8746c) # Conflicts: # erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py --- erpnext/stock/stock_balance.py | 70 ++++++++++++++++--- .../subcontracting_order.py | 33 +++------ 2 files changed, 69 insertions(+), 34 deletions(-) diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py index 6a2f818f7ae..c3f5086fbc5 100644 --- a/erpnext/stock/stock_balance.py +++ b/erpnext/stock/stock_balance.py @@ -3,6 +3,7 @@ import frappe +from frappe.query_builder.functions import Coalesce, Sum from frappe.utils import cstr, flt, now, nowdate, nowtime from erpnext.controllers.stock_controller import create_repost_item_valuation_entry @@ -182,18 +183,67 @@ def get_indented_qty(item_code, warehouse): def get_ordered_qty(item_code, warehouse): - ordered_qty = frappe.db.sql( - """ - select sum((po_item.qty - po_item.received_qty)*po_item.conversion_factor) - from `tabPurchase Order Item` po_item, `tabPurchase Order` po - where po_item.item_code=%s and po_item.warehouse=%s - and po_item.qty > po_item.received_qty and po_item.parent=po.name - and po.status not in ('Closed', 'Delivered') and po.docstatus=1 - and po_item.delivered_by_supplier = 0""", - (item_code, warehouse), + """Return total pending ordered quantity for an item in a warehouse. + Includes outstanding quantities from Purchase Orders and Subcontracting Orders""" + + purchase_order_qty = get_purchase_order_qty(item_code, warehouse) + subcontracting_order_qty = get_subcontracting_order_qty(item_code, warehouse) + + return flt(purchase_order_qty) + flt(subcontracting_order_qty) + + +def get_purchase_order_qty(item_code, warehouse): + PurchaseOrder = frappe.qb.DocType("Purchase Order") + PurchaseOrderItem = frappe.qb.DocType("Purchase Order Item") + + purchase_order_qty = ( + frappe.qb.from_(PurchaseOrderItem) + .join(PurchaseOrder) + .on(PurchaseOrderItem.parent == PurchaseOrder.name) + .select( + Sum( + (PurchaseOrderItem.qty - PurchaseOrderItem.received_qty) * PurchaseOrderItem.conversion_factor + ) + ) + .where( + (PurchaseOrderItem.item_code == item_code) + & (PurchaseOrderItem.warehouse == warehouse) + & (PurchaseOrderItem.qty > PurchaseOrderItem.received_qty) + & (PurchaseOrder.status.notin(["Closed", "Delivered"])) + & (PurchaseOrder.docstatus == 1) + & (Coalesce(PurchaseOrderItem.delivered_by_supplier, 0) == 0) + ) + .run() ) - return flt(ordered_qty[0][0]) if ordered_qty else 0 + return purchase_order_qty[0][0] if purchase_order_qty else 0 + + +def get_subcontracting_order_qty(item_code, warehouse): + SubcontractingOrder = frappe.qb.DocType("Subcontracting Order") + SubcontractingOrderItem = frappe.qb.DocType("Subcontracting Order Item") + + subcontracting_order_qty = ( + frappe.qb.from_(SubcontractingOrderItem) + .join(SubcontractingOrder) + .on(SubcontractingOrderItem.parent == SubcontractingOrder.name) + .select( + Sum( + (SubcontractingOrderItem.qty - SubcontractingOrderItem.received_qty) + * SubcontractingOrderItem.conversion_factor + ) + ) + .where( + (SubcontractingOrderItem.item_code == item_code) + & (SubcontractingOrderItem.warehouse == warehouse) + & (SubcontractingOrderItem.qty > SubcontractingOrderItem.received_qty) + & (SubcontractingOrder.status.notin(["Closed", "Completed"])) + & (SubcontractingOrder.docstatus == 1) + ) + .run() + ) + + return subcontracting_order_qty[0][0] if subcontracting_order_qty else 0 def get_planned_qty(item_code, warehouse): diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py index 4f87e695dfc..4a4462ce764 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py @@ -8,7 +8,15 @@ from frappe.utils import flt from erpnext.buying.utils import check_on_hold_or_closed_status from erpnext.controllers.subcontracting_controller import SubcontractingController +<<<<<<< HEAD from erpnext.stock.stock_balance import update_bin_qty +======= +from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( + StockReservation, + has_reserved_stock, +) +from erpnext.stock.stock_balance import get_ordered_qty, update_bin_qty +>>>>>>> de8f8ef9f4 (fix(stock): include subcontracting order qty while calculating the bin qty) from erpnext.stock.utils import get_bin @@ -211,30 +219,7 @@ class SubcontractingOrder(SubcontractingController): ): item_wh_list.append([item.item_code, item.warehouse]) for item_code, warehouse in item_wh_list: - update_bin_qty(item_code, warehouse, {"ordered_qty": self.get_ordered_qty(item_code, warehouse)}) - - @staticmethod - def get_ordered_qty(item_code, warehouse): - table = frappe.qb.DocType("Subcontracting Order") - child = frappe.qb.DocType("Subcontracting Order Item") - - query = ( - frappe.qb.from_(table) - .inner_join(child) - .on(table.name == child.parent) - .select((child.qty - child.received_qty) * child.conversion_factor) - .where( - (table.docstatus == 1) - & (child.item_code == item_code) - & (child.warehouse == warehouse) - & (child.qty > child.received_qty) - & (table.status != "Completed") - ) - ) - - query = query.run() - - return flt(query[0][0]) if query else 0 + update_bin_qty(item_code, warehouse, {"ordered_qty": get_ordered_qty(item_code, warehouse)}) def update_reserved_qty_for_subcontracting(self, sco_item_rows=None): for item in self.supplied_items: From c0116bcde5e070eade22b50b4f55b4dae6f80779 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Tue, 3 Feb 2026 20:30:40 +0530 Subject: [PATCH 2/2] chore: resolve conflicts --- .../doctype/subcontracting_order/subcontracting_order.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py index 4a4462ce764..f764329e338 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py @@ -8,15 +8,7 @@ from frappe.utils import flt from erpnext.buying.utils import check_on_hold_or_closed_status from erpnext.controllers.subcontracting_controller import SubcontractingController -<<<<<<< HEAD -from erpnext.stock.stock_balance import update_bin_qty -======= -from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import ( - StockReservation, - has_reserved_stock, -) from erpnext.stock.stock_balance import get_ordered_qty, update_bin_qty ->>>>>>> de8f8ef9f4 (fix(stock): include subcontracting order qty while calculating the bin qty) from erpnext.stock.utils import get_bin