diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index ea12542402c..ef40ccc3cdc 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -2364,6 +2364,105 @@ class TestWorkOrder(IntegrationTestCase): stock_entry.submit() + def test_disassembly_order_with_qty_behavior(self): + # Create raw material and FG item + raw_item = make_item("Test Raw for Disassembly", {"is_stock_item": 1}).name + fg_item = make_item("Test FG for Disassembly", {"is_stock_item": 1}).name + bom = make_bom(item=fg_item, quantity=10, raw_materials=[raw_item], rm_qty=5) + + # Create and submit a Work Order for 10 qty + wo = make_wo_order_test_record(production_item=fg_item, qty=10, bom_no=bom.name, status="Not Started") + + # create material receipt stock entry for raw material + from erpnext.stock.doctype.stock_entry.test_stock_entry import ( + make_stock_entry as make_stock_entry_test_record, + ) + + make_stock_entry_test_record( + item_code=raw_item, + purpose="Material Receipt", + target=wo.wip_warehouse, + qty=10, + basic_rate=100, + ) + make_stock_entry_test_record( + item_code=raw_item, + purpose="Material Receipt", + target=wo.fg_warehouse, + qty=10, + basic_rate=100, + ) + + # create material transfer for manufacture stock entry + se_for_material_tranfer_mfr = frappe.get_doc( + make_stock_entry(wo.name, "Material Transfer for Manufacture", wo.qty) + ) + se_for_material_tranfer_mfr.items[0].s_warehouse = wo.wip_warehouse + se_for_material_tranfer_mfr.save() + se_for_material_tranfer_mfr.submit() + + se_for_manufacture = frappe.get_doc(make_stock_entry(wo.name, "Manufacture", wo.qty)) + se_for_manufacture.submit() + + # Simulate a disassembly stock entry + disassemble_qty = 4 + stock_entry = frappe.get_doc(make_stock_entry(wo.name, "Disassemble", disassemble_qty)) + stock_entry.append( + "items", + { + "item_code": fg_item, + "qty": disassemble_qty, + "s_warehouse": wo.fg_warehouse, + }, + ) + + for bom_item in bom.items: + stock_entry.append( + "items", + { + "item_code": bom_item.item_code, + "qty": (bom_item.qty / bom.quantity) * disassemble_qty, + "t_warehouse": wo.source_warehouse, + }, + ) + + wo.reload() + stock_entry.save() + stock_entry.submit() + + # Assert FG item is present with correct qty + finished_good_entry = next((item for item in stock_entry.items if item.item_code == fg_item), None) + self.assertIsNotNone(finished_good_entry, "Finished good item missing from stock entry") + self.assertEqual( + finished_good_entry.qty, + disassemble_qty, + f"Expected FG qty {disassemble_qty}, found {finished_good_entry.qty}", + ) + + # Assert raw materials + for item in stock_entry.items: + if item.item_code == fg_item: + continue + bom_item = next((i for i in bom.items if i.item_code == item.item_code), None) + if bom_item: + expected_qty = (bom_item.qty / bom.quantity) * disassemble_qty + self.assertAlmostEqual( + item.qty, + expected_qty, + places=3, + msg=f"Raw item {item.item_code} qty mismatch: expected {expected_qty}, got {item.qty}", + ) + else: + self.fail(f"Unexpected item {item.item_code} found in stock entry") + + wo.reload() + # Assert disassembled_qty field updated in Work Order + self.assertEqual( + wo.disassembled_qty, + disassemble_qty, + f"Work Order disassembled_qty mismatch: expected {disassemble_qty}, got {wo.disassembled_qty}", + ) + def test_components_alternate_item_for_bom_based_manufacture_entry(self): frappe.db.set_single_value("Manufacturing Settings", "backflush_raw_materials_based_on", "BOM") frappe.db.set_single_value("Manufacturing Settings", "validate_components_quantities_per_bom", 1) @@ -3296,6 +3395,7 @@ def make_wo_order_test_record(**args): wo_order.transfer_material_against = args.transfer_material_against or "Work Order" wo_order.from_wip_warehouse = args.from_wip_warehouse or 0 wo_order.batch_size = args.batch_size or 0 + wo_order.status = args.status or "Draft" if args.source_warehouse: wo_order.source_warehouse = args.source_warehouse