fix: add v15 compatibility for scrap item

This commit is contained in:
Smit Vora
2026-04-07 15:43:43 +05:30
parent 904ac62830
commit 652bd396d4
2 changed files with 19 additions and 32 deletions

View File

@@ -2519,13 +2519,11 @@ class TestWorkOrder(FrappeTestCase):
scrap_item = make_item("Test Scrap for Multi Batch Disassembly", {"is_stock_item": 1}).name
fg_item = make_item("Test FG for Multi Batch Disassembly", {"is_stock_item": 1}).name
bom = make_bom(
item=fg_item,
quantity=1,
raw_materials=[raw_item1, raw_item2],
rm_qty=2,
scrap_items=[scrap_item],
scrap_qty=10,
item=fg_item, quantity=1, raw_materials=[raw_item1, raw_item2], rm_qty=2, do_not_submit=True
)
# add scrap item
bom.append("scrap_items", {"item_code": scrap_item, "stock_qty": 10})
bom.submit()
# Create WO
wo = make_wo_order_test_record(production_item=fg_item, qty=10, bom_no=bom.name, status="Not Started")
@@ -2611,16 +2609,15 @@ class TestWorkOrder(FrappeTestCase):
fg_item_row = next((i for i in stock_entry.items if i.item_code == fg_item), None)
self.assertEqual(fg_item_row.qty, disassemble_qty)
# Secondary/Scrap item: should be taken from scrap warehouse in disassembly
# Scrap item: should be taken from scrap warehouse in disassembly
scrap_row = next((i for i in stock_entry.items if i.item_code == scrap_item), None)
self.assertIsNotNone(scrap_row)
self.assertEqual(scrap_row.type, "Scrap")
self.assertEqual(scrap_row.is_scrap_item, 1)
self.assertTrue(scrap_row.s_warehouse)
self.assertFalse(scrap_row.t_warehouse)
self.assertEqual(scrap_row.s_warehouse, wo.scrap_warehouse)
# BOM has scrap_qty=10/FG but also process_loss_per=10%, so actual scrap per FG = 9
# Total produced = 9*3 + 9*7 = 90, disassemble 4/10 → 36
self.assertEqual(scrap_row.qty, 36)
# BOM has scrap_qty=10/FG, total produced = 10*10 = 100, disassemble 4/10 → 40
self.assertEqual(scrap_row.qty, 40)
# RM quantities
for bom_item in bom.items:
@@ -2665,11 +2662,11 @@ class TestWorkOrder(FrappeTestCase):
bom_scrap_row = next((i for i in bom_se.items if i.item_code == scrap_item), None)
self.assertIsNotNone(bom_scrap_row, "Scrap item must appear in BOM-path disassembly")
# Without fix 3: qty = 10 * 2 = 20; with fix 3 (process_loss_per=10%): qty = 9 * 2 = 18
# v15: BOM scrap_qty=10/FG, no process_loss_per field → qty = 10 * 2 = 20
self.assertEqual(
bom_scrap_row.qty,
18,
f"BOM-path disassembly must apply process_loss_per; expected 18, got {bom_scrap_row.qty}",
20,
f"BOM-path disassembly scrap qty mismatch; expected 20, got {bom_scrap_row.qty}",
)
def test_disassembly_with_additional_rm_not_in_bom(self):

View File

@@ -784,7 +784,7 @@ class StockEntry(StockController):
if self.purpose == "Disassemble":
if has_bom:
if d.is_finished_item or d.type or d.is_legacy_scrap_item:
if d.is_finished_item or d.is_scrap_item:
d.t_warehouse = None
if not d.s_warehouse:
frappe.throw(_("Source warehouse is mandatory for row {0}").format(d.idx))
@@ -2136,9 +2136,7 @@ class StockEntry(StockController):
"s_warehouse": s_warehouse,
"t_warehouse": t_warehouse,
"is_finished_item": source_row.is_finished_item,
"type": source_row.type,
"is_legacy_scrap_item": source_row.is_legacy_scrap_item,
"bom_secondary_item": source_row.bom_secondary_item,
"is_scrap_item": source_row.is_scrap_item,
"bom_no": source_row.bom_no,
# batch and serial bundles built on submit
"use_serial_batch_fields": 1 if (source_row.batch_no or source_row.serial_no) else 0,
@@ -2168,9 +2166,9 @@ class StockEntry(StockController):
self.add_to_stock_entry_detail(item_dict)
# Secondary/Scrap items (reverse of what set_secondary_items does for Manufacture)
secondary_items = self.get_secondary_items(self.fg_completed_qty)
if secondary_items:
# Scrap items (reverse: take scrap FROM scrap warehouse instead of producing TO it)
scrap_items = self.get_bom_scrap_material(self.fg_completed_qty)
if scrap_items:
scrap_warehouse = self.from_warehouse
if self.work_order:
wo_values = frappe.db.get_value(
@@ -2178,18 +2176,12 @@ class StockEntry(StockController):
)
scrap_warehouse = wo_values.scrap_warehouse or scrap_warehouse or wo_values.fg_warehouse
for item in secondary_items.values():
for item in scrap_items.values():
item["from_warehouse"] = scrap_warehouse
item["to_warehouse"] = ""
item["is_finished_item"] = 0
if item.get("process_loss_per"):
item["qty"] -= flt(
item["qty"] * (item["process_loss_per"] / 100),
self.precision("fg_completed_qty"),
)
self.add_to_stock_entry_detail(secondary_items, bom_no=self.bom_no)
self.add_to_stock_entry_detail(scrap_items, bom_no=self.bom_no)
# Finished goods
self.load_items_from_bom()
@@ -2208,9 +2200,7 @@ class StockEntry(StockController):
SED.basic_rate,
SED.conversion_factor,
SED.is_finished_item,
SED.type,
SED.is_legacy_scrap_item,
SED.bom_secondary_item,
SED.is_scrap_item,
SED.batch_no,
SED.serial_no,
SED.use_serial_batch_fields,