test: test cases for process loss
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 31f7396..53af28d 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -193,6 +193,7 @@
self.update_exploded_items(save=False)
self.update_stock_qty()
self.update_cost(update_parent=False, from_child_bom=True, update_hour_rate=False, save=False)
+ self.set_process_loss_qty()
self.validate_scrap_items()
def get_context(self, context):
@@ -877,6 +878,10 @@
"""Get a complete tree representation preserving order of child items."""
return BOMTree(self.name)
+ def set_process_loss_qty(self):
+ if self.process_loss_percentage:
+ self.process_loss_qty = flt(self.quantity) * flt(self.process_loss_percentage) / 100
+
def validate_scrap_items(self):
must_be_whole_number = frappe.get_value("UOM", self.uom, "must_be_whole_number")
diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py
index 9898617..16f5c79 100644
--- a/erpnext/manufacturing/doctype/bom/test_bom.py
+++ b/erpnext/manufacturing/doctype/bom/test_bom.py
@@ -384,36 +384,16 @@
def test_bom_with_process_loss_item(self):
fg_item_non_whole, fg_item_whole, bom_item = create_process_loss_bom_items()
- if not frappe.db.exists("BOM", f"BOM-{fg_item_non_whole.item_code}-001"):
- bom_doc = create_bom_with_process_loss_item(
- fg_item_non_whole, bom_item, scrap_qty=0.25, scrap_rate=0, fg_qty=1
- )
- bom_doc.submit()
-
bom_doc = create_bom_with_process_loss_item(
- fg_item_non_whole, bom_item, scrap_qty=2, scrap_rate=0
+ fg_item_non_whole, bom_item, scrap_qty=2, scrap_rate=0, process_loss_percentage=110
)
- # PL Item qty can't be >= FG Item qty
+ # PL can't be > 100
self.assertRaises(frappe.ValidationError, bom_doc.submit)
- bom_doc = create_bom_with_process_loss_item(
- fg_item_non_whole, bom_item, scrap_qty=1, scrap_rate=100
- )
- # PL Item rate has to be 0
- self.assertRaises(frappe.ValidationError, bom_doc.submit)
-
- bom_doc = create_bom_with_process_loss_item(
- fg_item_whole, bom_item, scrap_qty=0.25, scrap_rate=0
- )
+ bom_doc = create_bom_with_process_loss_item(fg_item_whole, bom_item, process_loss_percentage=20)
# Items with whole UOMs can't be PL Items
self.assertRaises(frappe.ValidationError, bom_doc.submit)
- bom_doc = create_bom_with_process_loss_item(
- fg_item_non_whole, bom_item, scrap_qty=0.25, scrap_rate=0
- )
- # FG Items in Scrap/Loss Table should have Is Process Loss set
- self.assertRaises(frappe.ValidationError, bom_doc.submit)
-
def test_bom_item_query(self):
query = partial(
item_query,
@@ -743,7 +723,9 @@
create_stock_reconciliation(item_code=item_code, warehouse=warehouse, qty=qty, rate=rate)
-def create_bom_with_process_loss_item(fg_item, bom_item, scrap_qty, scrap_rate, fg_qty=2):
+def create_bom_with_process_loss_item(
+ fg_item, bom_item, scrap_qty=0, scrap_rate=0, fg_qty=2, process_loss_percentage=0
+):
bom_doc = frappe.new_doc("BOM")
bom_doc.item = fg_item.item_code
bom_doc.quantity = fg_qty
@@ -757,18 +739,22 @@
"rate": 100.0,
},
)
- bom_doc.append(
- "scrap_items",
- {
- "item_code": fg_item.item_code,
- "qty": scrap_qty,
- "stock_qty": scrap_qty,
- "uom": fg_item.stock_uom,
- "stock_uom": fg_item.stock_uom,
- "rate": scrap_rate,
- },
- )
+
+ if scrap_qty:
+ bom_doc.append(
+ "scrap_items",
+ {
+ "item_code": fg_item.item_code,
+ "qty": scrap_qty,
+ "stock_qty": scrap_qty,
+ "uom": fg_item.stock_uom,
+ "stock_uom": fg_item.stock_uom,
+ "rate": scrap_rate,
+ },
+ )
+
bom_doc.currency = "INR"
+ bom_doc.process_loss_percentage = process_loss_percentage
return bom_doc
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index 6c7483c..76040b2 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -846,20 +846,20 @@
create_process_loss_bom_items,
)
- qty = 4
+ qty = 10
scrap_qty = 0.25 # bom item qty = 1, consider as 25% of FG
source_warehouse = "Stores - _TC"
wip_warehouse = "_Test Warehouse - _TC"
fg_item_non_whole, _, bom_item = create_process_loss_bom_items()
test_stock_entry.make_stock_entry(
- item_code=bom_item.item_code, target=source_warehouse, qty=4, basic_rate=100
+ item_code=bom_item.item_code, target=source_warehouse, qty=qty, basic_rate=100
)
bom_no = f"BOM-{fg_item_non_whole.item_code}-001"
if not frappe.db.exists("BOM", bom_no):
bom_doc = create_bom_with_process_loss_item(
- fg_item_non_whole, bom_item, scrap_qty=scrap_qty, scrap_rate=0, fg_qty=1
+ fg_item_non_whole, bom_item, fg_qty=1, process_loss_percentage=10
)
bom_doc.submit()
@@ -883,19 +883,12 @@
# Testing stock entry values
items = se.get("items")
- self.assertEqual(len(items), 3, "There should be 3 items including process loss.")
+ self.assertEqual(len(items), 2, "There should be 3 items including process loss.")
+ fg_item = items[1]
- source_item, fg_item, pl_item = items
-
- total_pl_qty = qty * scrap_qty
- actual_fg_qty = qty - total_pl_qty
-
- self.assertEqual(pl_item.qty, total_pl_qty)
- self.assertEqual(fg_item.qty, actual_fg_qty)
-
- # Testing Work Order values
- self.assertEqual(frappe.db.get_value("Work Order", wo.name, "produced_qty"), qty)
- self.assertEqual(frappe.db.get_value("Work Order", wo.name, "process_loss_qty"), total_pl_qty)
+ self.assertEqual(fg_item.qty, qty - 1)
+ self.assertEqual(se.process_loss_percentage, 10)
+ self.assertEqual(se.process_loss_qty, 1)
@timeout(seconds=60)
def test_job_card_scrap_item(self):