From 0d9ace7ab87d5198aa8dfc3874b6f82920dc88ae 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. (cherry picked from commit ab30bab6cbdc0981ece3f0ecbc7cf87329b9a416) --- 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 d1d5d77f285..72a8d25af3b 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 05c61bbb4d5..7cbe369c720 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -307,10 +307,9 @@ def update_bin_details(ctx: ItemDetailsCtx, out: ItemDetails, 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 77cca4464d6baf61b0549ea49df6ec62d770df8b 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. (cherry picked from commit 4e5e1f659648005e1f9e7c1ab8767a4b48ccd595) --- 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 fdc563064ec..99d94008221 100644 --- a/erpnext/stock/tests/test_get_item_details.py +++ b/erpnext/stock/tests/test_get_item_details.py @@ -27,6 +27,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