From e2964088b76bbd6dbbd6c016d4dad4850d33b322 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 29 Dec 2022 12:34:18 +0530 Subject: [PATCH 1/2] fix: consider child nodes while getting bin details (cherry picked from commit c716dcc01e1b29779dac28b4d531b3fa3ee27143) --- erpnext/controllers/selling_controller.py | 2 +- erpnext/public/js/controllers/buying.js | 3 +- erpnext/stock/get_item_details.py | 38 ++++++++++++++++------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 0ebc8d4b4de7..dec3b750ebc2 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -26,7 +26,7 @@ def onload(self): super(SellingController, self).onload() if self.doctype in ("Sales Order", "Delivery Note", "Sales Invoice"): for item in self.get("items"): - item.update(get_bin_details(item.item_code, item.warehouse)) + item.update(get_bin_details(item.item_code, item.warehouse, include_child_warehouses=True)) def validate(self): super(SellingController, self).validate() diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js index 09779d89ec13..b0e08cc6f265 100644 --- a/erpnext/public/js/controllers/buying.js +++ b/erpnext/public/js/controllers/buying.js @@ -225,7 +225,8 @@ erpnext.buying.BuyingController = class BuyingController extends erpnext.Transac args: { item_code: item.item_code, warehouse: item.warehouse, - company: doc.company + company: doc.company, + include_child_warehouses: true } }); } diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 1741d654601f..dc00999b4631 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -102,9 +102,11 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru elif out.get("warehouse"): if doc and doc.get("doctype") == "Purchase Order": # calculate company_total_stock only for po - bin_details = get_bin_details(args.item_code, out.warehouse, args.company) + bin_details = get_bin_details( + args.item_code, out.warehouse, args.company, include_child_warehouses=True + ) else: - bin_details = get_bin_details(args.item_code, out.warehouse) + bin_details = get_bin_details(args.item_code, out.warehouse, include_child_warehouses=True) out.update(bin_details) @@ -1060,7 +1062,9 @@ def get_pos_profile_item_details(company, args, pos_profile=None, update_data=Fa res[fieldname] = pos_profile.get(fieldname) if res.get("warehouse"): - res.actual_qty = get_bin_details(args.item_code, res.warehouse).get("actual_qty") + res.actual_qty = get_bin_details( + args.item_code, res.warehouse, include_child_warehouses=True + ).get("actual_qty") return res @@ -1171,14 +1175,26 @@ def get_projected_qty(item_code, warehouse): @frappe.whitelist() -def get_bin_details(item_code, warehouse, company=None): - bin_details = frappe.db.get_value( - "Bin", - {"item_code": item_code, "warehouse": warehouse}, - ["projected_qty", "actual_qty", "reserved_qty"], - as_dict=True, - cache=True, - ) or {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0} +def get_bin_details(item_code, warehouse, company=None, include_child_warehouses=False): + bin_details = {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0} + + if warehouse: + from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses + + warehouses = get_child_warehouses(warehouse) if include_child_warehouses else [warehouse] + bin_details = frappe.db.get_value( + "Bin", + filters={"item_code": item_code, "warehouse": ["in", warehouses]}, + fieldname=[ + "sum(projected_qty) as projected_qty", + "sum(actual_qty) as actual_qty", + "sum(reserved_qty) as reserved_qty", + ], + as_dict=True, + cache=True, + ) + bin_details = {k: 0 if not v else v for k, v in bin_details.items()} + if company: bin_details["company_total_stock"] = get_company_total_stock(item_code, company) return bin_details From ec538b27fe89df5828aef8dae056c88c7d47b0ce Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 29 Dec 2022 16:38:08 +0530 Subject: [PATCH 2/2] chore: use `frappe.qb` instead of `frappe.db.get_value` (cherry picked from commit c3911a592a51a390c0b426707f7ec777686cb621) --- erpnext/stock/get_item_details.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index dc00999b4631..615288098574 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -1179,21 +1179,22 @@ def get_bin_details(item_code, warehouse, company=None, include_child_warehouses bin_details = {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0} if warehouse: + from frappe.query_builder.functions import Coalesce, Sum + from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses warehouses = get_child_warehouses(warehouse) if include_child_warehouses else [warehouse] - bin_details = frappe.db.get_value( - "Bin", - filters={"item_code": item_code, "warehouse": ["in", warehouses]}, - fieldname=[ - "sum(projected_qty) as projected_qty", - "sum(actual_qty) as actual_qty", - "sum(reserved_qty) as reserved_qty", - ], - as_dict=True, - cache=True, - ) - bin_details = {k: 0 if not v else v for k, v in bin_details.items()} + + bin = frappe.qb.DocType("Bin") + bin_details = ( + frappe.qb.from_(bin) + .select( + Coalesce(Sum(bin.projected_qty), 0).as_("projected_qty"), + Coalesce(Sum(bin.actual_qty), 0).as_("actual_qty"), + Coalesce(Sum(bin.reserved_qty), 0).as_("reserved_qty"), + ) + .where((bin.item_code == item_code) & (bin.warehouse.isin(warehouses))) + ).run(as_dict=True)[0] if company: bin_details["company_total_stock"] = get_company_total_stock(item_code, company)