From ab30bab6cbdc0981ece3f0ecbc7cf87329b9a416 Mon Sep 17 00:00:00 2001 From: Sudharsanan11 Date: Mon, 13 Jul 2026 13:33:37 +0530 Subject: [PATCH 1/2] fix(stock): show qty (company) and qty (warehouse) in sales transactions company was passed to get_bin_details only for purchase order, so company_total_stock was never returned for sales order, quotation, sales invoice and delivery note and the qty (company) column always read zero. pass ctx.company for every doctype, which also drops the dependency on doc being supplied. on the client, set_actual_qty copied only actual_qty out of the response, so qty (company) never refreshed on a warehouse change. use frm.call with child so every bin field is applied, pass include_child_warehouses to match the server, and include quotation. --- erpnext/public/js/utils/sales_common.js | 12 +++++------- erpnext/stock/get_item_details.py | 7 +++---- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/erpnext/public/js/utils/sales_common.js b/erpnext/public/js/utils/sales_common.js index 3d11b27a3be..5dafc9c61dc 100644 --- a/erpnext/public/js/utils/sales_common.js +++ b/erpnext/public/js/utils/sales_common.js @@ -284,19 +284,17 @@ erpnext.sales_common = { set_actual_qty(doc, cdt, cdn) { let row = locals[cdt][cdn]; - let sales_doctypes = ["Sales Invoice", "Delivery Note", "Sales Order"]; + let sales_doctypes = ["Sales Invoice", "Delivery Note", "Sales Order", "Quotation"]; if (row.item_code && row.warehouse && sales_doctypes.includes(doc.doctype)) { - frappe.call({ + return this.frm.call({ method: "erpnext.stock.get_item_details.get_bin_details", + child: row, args: { item_code: row.item_code, warehouse: row.warehouse, - }, - callback(r) { - if (r.message) { - frappe.model.set_value(cdt, cdn, "actual_qty", r.message.actual_qty); - } + company: doc.company, + include_child_warehouses: true, }, }); } diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 2ed89e5d640..9b6c6117398 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -323,10 +323,9 @@ def update_bin_details(ctx: frappe._dict, out: frappe._dict, doc): out.update(get_bin_details(ctx.item_code, ctx.from_warehouse)) elif out.get("warehouse"): - company = ctx.company if (doc and doc.get("doctype") == "Purchase Order") else None - - # calculate company_total_stock only for po - bin_details = get_bin_details(ctx.item_code, out.warehouse, company, include_child_warehouses=True) + bin_details = get_bin_details( + ctx.item_code, out.warehouse, ctx.company, include_child_warehouses=True + ) out.update(bin_details) From 4e5e1f659648005e1f9e7c1ab8767a4b48ccd595 Mon Sep 17 00:00:00 2001 From: Sudharsanan11 Date: Mon, 13 Jul 2026 13:34:13 +0530 Subject: [PATCH 2/2] test(stock): assert qty (company) and qty (warehouse) on item details covers sales order, quotation, sales invoice, delivery note and purchase order, asserting actual_qty from the row warehouse and company_total_stock across all warehouses of the company. --- erpnext/stock/tests/test_get_item_details.py | 34 ++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/erpnext/stock/tests/test_get_item_details.py b/erpnext/stock/tests/test_get_item_details.py index c1026eb9b65..f9513fb5743 100644 --- a/erpnext/stock/tests/test_get_item_details.py +++ b/erpnext/stock/tests/test_get_item_details.py @@ -28,6 +28,40 @@ class TestGetItemDetail(ERPNextTestSuite): details = get_item_details(args) self.assertEqual(details.get("price_list_rate"), 100) + def test_bin_details_for_selling_doctypes(self): + from erpnext.stock.doctype.item.test_item import make_item + from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt + + item_code = make_item(properties={"is_stock_item": 1}).name + + make_purchase_receipt(item_code=item_code, warehouse="_Test Warehouse - _TC", qty=100, rate=100) + make_purchase_receipt(item_code=item_code, warehouse="_Test Warehouse 1 - _TC", qty=50, rate=100) + + args = frappe._dict( + { + "item_code": item_code, + "warehouse": "_Test Warehouse - _TC", + "company": "_Test Company", + "customer": "_Test Customer", + "currency": "INR", + "conversion_rate": 1.0, + "price_list": "_Test Price List", + "price_list_currency": "INR", + "plc_conversion_rate": 1.0, + "transaction_date": None, + "name": None, + "ignore_pricing_rule": 1, + "qty": 1, + } + ) + + for doctype in ("Sales Order", "Quotation", "Sales Invoice", "Delivery Note", "Purchase Order"): + with self.subTest(doctype=doctype): + details = get_item_details(args.copy().update({"doctype": doctype})) + + self.assertEqual(details.get("actual_qty"), 100) + self.assertEqual(details.get("company_total_stock"), 150) + # making this test in get_item_details test file as feat/fix is present in that method def test_fetch_price_from_list_rate_on_doc_save(self): # create item