mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-18 00:48:42 +00:00
test: add coverage for Work Order Consumed Materials report
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.utils import add_days, nowdate
|
||||
|
||||
from erpnext.manufacturing.doctype.work_order.mapper import make_stock_entry
|
||||
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
|
||||
from erpnext.manufacturing.report.work_order_consumed_materials.work_order_consumed_materials import execute
|
||||
from erpnext.stock.doctype.stock_entry import test_stock_entry
|
||||
from erpnext.tests.utils import ERPNextTestSuite
|
||||
|
||||
|
||||
class TestWorkOrderConsumedMaterials(ERPNextTestSuite):
|
||||
def run_report(self, **extra):
|
||||
filters = frappe._dict(
|
||||
{
|
||||
"company": "_Test Company",
|
||||
"from_date": add_days(nowdate(), -1),
|
||||
"to_date": add_days(nowdate(), 1),
|
||||
}
|
||||
)
|
||||
filters.update(extra)
|
||||
return execute(filters)[1]
|
||||
|
||||
def make_manufactured_work_order(self, qty=2):
|
||||
"""Create a submitted WO, stock its raw materials, transfer and fully manufacture it."""
|
||||
wo = make_wo_order_test_record(production_item="_Test FG Item", qty=qty, company="_Test Company")
|
||||
|
||||
for item in wo.required_items:
|
||||
test_stock_entry.make_stock_entry(
|
||||
item_code=item.item_code,
|
||||
target=wo.wip_warehouse,
|
||||
qty=item.required_qty,
|
||||
basic_rate=100,
|
||||
)
|
||||
|
||||
transfer = frappe.get_doc(make_stock_entry(wo.name, "Material Transfer for Manufacture", qty))
|
||||
transfer.insert()
|
||||
transfer.submit()
|
||||
|
||||
manufacture = frappe.get_doc(make_stock_entry(wo.name, "Manufacture", qty))
|
||||
manufacture.insert()
|
||||
manufacture.submit()
|
||||
|
||||
wo.reload()
|
||||
return wo
|
||||
|
||||
def get_wo_rows(self, data, work_order):
|
||||
"""The report blanks parent fields after the first raw-material row, so match by raw
|
||||
material's parent work order instead of the (blanked) `name` column."""
|
||||
return [row for row in data if row.get("parent") == work_order]
|
||||
|
||||
def test_consumed_materials_reported_after_manufacture(self):
|
||||
wo = self.make_manufactured_work_order(qty=2)
|
||||
|
||||
# fully producing the WO consumes exactly the required quantity of each raw material
|
||||
self.assertEqual(wo.produced_qty, 2)
|
||||
|
||||
data = self.run_report()
|
||||
rows = self.get_wo_rows(data, wo.name)
|
||||
|
||||
self.assertEqual(len(rows), len(wo.required_items))
|
||||
|
||||
reported = {row["raw_material_item_code"]: row for row in rows}
|
||||
for item in wo.required_items:
|
||||
row = reported[item.item_code]
|
||||
self.assertEqual(row["required_qty"], item.required_qty)
|
||||
self.assertEqual(row["transferred_qty"], item.required_qty)
|
||||
self.assertEqual(row["consumed_qty"], item.required_qty)
|
||||
# no over-consumption in a clean full manufacture
|
||||
self.assertEqual(row["extra_consumed_qty"], 0.0)
|
||||
self.assertEqual(row["returned_qty"], 0.0)
|
||||
|
||||
# parent columns are populated on the first row only
|
||||
first = rows[0]
|
||||
self.assertEqual(first["status"], wo.status)
|
||||
self.assertEqual(first["production_item"], "_Test FG Item")
|
||||
self.assertEqual(first["qty"], 2)
|
||||
self.assertEqual(first["produced_qty"], 2)
|
||||
|
||||
def test_work_order_filter_scopes_output(self):
|
||||
wo = self.make_manufactured_work_order(qty=1)
|
||||
|
||||
data = self.run_report(name=wo.name)
|
||||
|
||||
parents = {row.get("parent") for row in data}
|
||||
self.assertEqual(parents, {wo.name})
|
||||
self.assertTrue(data)
|
||||
|
||||
def test_draft_work_order_is_excluded(self):
|
||||
# report only lists WOs in status In Process / Completed / Stopped
|
||||
draft = make_wo_order_test_record(
|
||||
production_item="_Test FG Item", qty=1, company="_Test Company", do_not_submit=True
|
||||
)
|
||||
|
||||
data = self.run_report()
|
||||
self.assertNotIn(draft.name, {row.get("parent") for row in data})
|
||||
|
||||
def test_date_range_filter_excludes_work_order(self):
|
||||
wo = self.make_manufactured_work_order(qty=1)
|
||||
|
||||
# a window that ends before the WO was created must not include it
|
||||
data = self.run_report(from_date=add_days(nowdate(), -10), to_date=add_days(nowdate(), -5))
|
||||
self.assertNotIn(wo.name, {row.get("parent") for row in data})
|
||||
Reference in New Issue
Block a user