From ce7dbf309004ca9e24e985bd0c7ab72801d2357f Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Tue, 24 Jun 2025 17:40:41 +0530 Subject: [PATCH] refactor: bom stock report (cherry picked from commit ee4e0c646d5117d7ebf461f125b90232711db95e) --- .../bom_stock_report/bom_stock_report.py | 52 +++++++++---------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py index 96a6822cd11..5fe4d63ccbf 100644 --- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py +++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py @@ -1,12 +1,10 @@ # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors # For license information, please see license.txt - import frappe from frappe import _ from frappe.query_builder.functions import Floor, Sum from frappe.utils import cint -from pypika.terms import ExistsCriterion def execute(filters=None): @@ -20,8 +18,7 @@ def execute(filters=None): def get_columns(): - """return columns""" - columns = [ + return [ _("Item") + ":Link/Item:150", _("Item Name") + "::240", _("Description") + "::300", @@ -32,55 +29,54 @@ def get_columns(): _("Enough Parts to Build") + ":Float:200", ] - return columns - def get_bom_stock(filters): qty_to_produce = filters.get("qty_to_produce") if cint(qty_to_produce) <= 0: frappe.throw(_("Quantity to Produce should be greater than zero.")) - if filters.get("show_exploded_view"): - bom_item_table = "BOM Explosion Item" - else: - bom_item_table = "BOM Item" + bom_item_table = "BOM Explosion Item" if filters.get("show_exploded_view") else "BOM Item" - warehouse_details = frappe.db.get_value("Warehouse", filters.get("warehouse"), ["lft", "rgt"], as_dict=1) + warehouse = filters.get("warehouse") + warehouse_details = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"], as_dict=1) BOM = frappe.qb.DocType("BOM") BOM_ITEM = frappe.qb.DocType(bom_item_table) BIN = frappe.qb.DocType("Bin") WH = frappe.qb.DocType("Warehouse") - CONDITIONS = () if warehouse_details: - CONDITIONS = ExistsCriterion( - frappe.qb.from_(WH) - .select(WH.name) - .where( - (WH.lft >= warehouse_details.lft) - & (WH.rgt <= warehouse_details.rgt) - & (BIN.warehouse == WH.name) - ) + bin_subquery = ( + frappe.qb.from_(BIN) + .join(WH) + .on(BIN.warehouse == WH.name) + .select(BIN.item_code, Sum(BIN.actual_qty).as_("actual_qty")) + .where((WH.lft >= warehouse_details.lft) & (WH.rgt <= warehouse_details.rgt)) + .groupby(BIN.item_code) ) else: - CONDITIONS = BIN.warehouse == filters.get("warehouse") + bin_subquery = ( + frappe.qb.from_(BIN) + .select(BIN.item_code, Sum(BIN.actual_qty).as_("actual_qty")) + .where(BIN.warehouse == warehouse) + .groupby(BIN.item_code) + ) QUERY = ( frappe.qb.from_(BOM) - .inner_join(BOM_ITEM) + .join(BOM_ITEM) .on(BOM.name == BOM_ITEM.parent) - .left_join(BIN) - .on((BOM_ITEM.item_code == BIN.item_code) & (CONDITIONS)) + .left_join(bin_subquery) + .on(BOM_ITEM.item_code == bin_subquery.item_code) .select( BOM_ITEM.item_code, BOM_ITEM.item_name, BOM_ITEM.description, - BOM_ITEM.stock_qty, + Sum(BOM_ITEM.stock_qty), BOM_ITEM.stock_uom, - BOM_ITEM.stock_qty * qty_to_produce / BOM.quantity, - BIN.actual_qty.as_("actual_qty"), - Sum(Floor(BIN.actual_qty / (BOM_ITEM.stock_qty * qty_to_produce / BOM.quantity))), + (Sum(BOM_ITEM.stock_qty) * qty_to_produce) / BOM.quantity, + bin_subquery.actual_qty, + Floor(bin_subquery.actual_qty / ((Sum(BOM_ITEM.stock_qty) * qty_to_produce) / BOM.quantity)), ) .where((BOM_ITEM.parent == filters.get("bom")) & (BOM_ITEM.parenttype == "BOM")) .groupby(BOM_ITEM.item_code)