From 7af3c3d0b6b779a4e7937d233da39bdac28915c0 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 17 Jul 2023 15:21:48 +0530 Subject: [PATCH] fix: incorrect Reserved Qty for Production Plan in BIN for multi-uom case (cherry picked from commit 2f632d031aa53e1e03763623449e7cde7dca3c55) --- .../production_plan/production_plan.py | 2 +- .../production_plan/test_production_plan.py | 48 +++++++++++++++++++ .../material_request/material_request.py | 12 +++-- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index a988badd74..d8cc8f6d39 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -1539,7 +1539,7 @@ def get_reserved_qty_for_production_plan(item_code, warehouse): frappe.qb.from_(table) .inner_join(child) .on(table.name == child.parent) - .select(Sum(child.required_bom_qty * IfNull(child.conversion_factor, 1.0))) + .select(Sum(child.quantity * IfNull(child.conversion_factor, 1.0))) .where( (table.docstatus == 1) & (child.item_code == item_code) diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py index fcfba7fca5..f60dbfc3f5 100644 --- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py @@ -933,6 +933,54 @@ class TestProductionPlan(FrappeTestCase): self.assertEqual(after_qty, before_qty) + def test_resered_qty_for_production_plan_for_material_requests_with_multi_UOM(self): + from erpnext.stock.utils import get_or_make_bin + + fg_item = make_item(properties={"is_stock_item": 1, "stock_uom": "_Test UOM 1"}).name + bom_item = make_item( + properties={"is_stock_item": 1, "stock_uom": "_Test UOM 1", "purchase_uom": "Nos"} + ).name + + if not frappe.db.exists("UOM Conversion Detail", {"parent": bom_item, "uom": "Nos"}): + doc = frappe.get_doc("Item", bom_item) + doc.append("uoms", {"uom": "Nos", "conversion_factor": 25}) + doc.save() + + make_bom(item=fg_item, raw_materials=[bom_item], source_warehouse="_Test Warehouse - _TC") + + bin_name = get_or_make_bin(bom_item, "_Test Warehouse - _TC") + before_qty = flt(frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan")) + + pln = create_production_plan( + item_code=fg_item, planned_qty=100, ignore_existing_ordered_qty=1, stock_uom="_Test UOM 1" + ) + + for row in pln.mr_items: + self.assertEqual(row.uom, "Nos") + self.assertEqual(row.quantity, 4) + + reserved_qty = flt(frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan")) + self.assertEqual(reserved_qty - before_qty, 100.0) + + pln.submit_material_request = 1 + pln.make_work_order() + + for work_order in frappe.get_all( + "Work Order", + fields=["name"], + filters={"production_plan": pln.name}, + ): + wo_doc = frappe.get_doc("Work Order", work_order.name) + wo_doc.source_warehouse = "_Test Warehouse - _TC" + wo_doc.wip_warehouse = "_Test Warehouse 1 - _TC" + wo_doc.fg_warehouse = "_Test Warehouse - _TC" + wo_doc.submit() + + reserved_qty_after_mr = flt( + frappe.db.get_value("Bin", bin_name, "reserved_qty_for_production_plan") + ) + self.assertEqual(reserved_qty_after_mr, before_qty) + def test_skip_available_qty_for_sub_assembly_items(self): from erpnext.manufacturing.doctype.bom.test_bom import create_nested_bom diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index ee247fd093..00b1b20f3f 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -118,8 +118,8 @@ class MaterialRequest(BuyingController): self.title = _("{0} Request for {1}").format(_(self.material_request_type), items)[:100] def on_submit(self): - self.update_requested_qty() self.update_requested_qty_in_production_plan() + self.update_requested_qty() if self.material_request_type == "Purchase": self.validate_budget() @@ -178,8 +178,8 @@ class MaterialRequest(BuyingController): ) def on_cancel(self): - self.update_requested_qty() self.update_requested_qty_in_production_plan() + self.update_requested_qty() def get_mr_items_ordered_qty(self, mr_items): mr_items_ordered_qty = {} @@ -270,7 +270,13 @@ class MaterialRequest(BuyingController): item_wh_list.append([d.item_code, d.warehouse]) for item_code, warehouse in item_wh_list: - update_bin_qty(item_code, warehouse, {"indented_qty": get_indented_qty(item_code, warehouse)}) + update_bin_qty( + item_code, + warehouse, + { + "indented_qty": get_indented_qty(item_code, warehouse), + }, + ) def update_requested_qty_in_production_plan(self): production_plans = []