From 1519770cb0263c6e919c1be35f4dbb8b36095ed0 Mon Sep 17 00:00:00 2001 From: Pandiyan P Date: Fri, 14 Aug 2026 19:20:43 +0530 Subject: [PATCH] perf: filter stock projected qty bins by company in sql (#58173) --- .../stock_projected_qty.py | 19 ++++++++++--------- .../test_stock_projected_qty.py | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py index 23737e7c5a1..e02353a8b9b 100644 --- a/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py +++ b/erpnext/stock/report/stock_projected_qty/stock_projected_qty.py @@ -27,7 +27,6 @@ def execute(filters=None): item_groups.append(filters.item_group) item_groups.extend(get_descendants_of("Item Group", filters.item_group)) - warehouse_company = {} data = [] conversion_factors = [] for bin in bin_list: @@ -37,20 +36,12 @@ def execute(filters=None): # likely an item that has reached its end of life continue - # item = item_map.setdefault(bin.item_code, get_item(bin.item_code)) - company = warehouse_company.setdefault( - bin.warehouse, frappe.db.get_value("Warehouse", bin.warehouse, "company") - ) - if filters.brand and filters.brand != item.brand: continue elif item_groups and item.item_group not in item_groups: continue - elif filters.company and filters.company != company: - continue - re_order_level = re_order_qty = 0 for d in item.get("reorder_levels"): @@ -265,6 +256,16 @@ def get_bin_list(filters): if filters.item_code: query = query.where(bin.item_code == filters.item_code) + if filters.company: + wh = frappe.qb.DocType("Warehouse") + query = query.where( + ExistsCriterion( + frappe.qb.from_(wh) + .select(wh.name) + .where((wh.name == bin.warehouse) & (wh.company == filters.company)) + ) + ) + if filters.warehouse: warehouse_details = frappe.db.get_value("Warehouse", filters.warehouse, ["lft", "rgt"], as_dict=1) diff --git a/erpnext/stock/report/stock_projected_qty/test_stock_projected_qty.py b/erpnext/stock/report/stock_projected_qty/test_stock_projected_qty.py index d5c5c5a6587..8a16c99f28f 100644 --- a/erpnext/stock/report/stock_projected_qty/test_stock_projected_qty.py +++ b/erpnext/stock/report/stock_projected_qty/test_stock_projected_qty.py @@ -90,6 +90,21 @@ class TestStockProjectedQty(ERPNextTestSuite): self.assertEqual(row["projected_qty"], 10) self.assertEqual(row["shortage_qty"], 10) # reorder level 20 - projected 10 + def test_company_filter_excludes_other_company_warehouses(self): + item = "_Test Item" + make_stock_entry(item_code=item, qty=5, to_warehouse=WAREHOUSE, basic_rate=100) + make_stock_entry( + item_code=item, + qty=7, + to_warehouse="Stores - _TC1", + company="_Test Company 1", + basic_rate=100, + ) + + warehouses = {row["warehouse"] for row in self.run_report(item)} + self.assertIn(WAREHOUSE, warehouses) + self.assertNotIn("Stores - _TC1", warehouses) + def test_item_filter_returns_only_requested_item(self): item_a = "_Test Item" item_b = "_Test Item 2"