test: add test cases for BOM Stock Calculated report
diff --git a/erpnext/manufacturing/report/bom_stock_calculated/test_bom_stock_calculated.py b/erpnext/manufacturing/report/bom_stock_calculated/test_bom_stock_calculated.py
new file mode 100644
index 0000000..8ad980f
--- /dev/null
+++ b/erpnext/manufacturing/report/bom_stock_calculated/test_bom_stock_calculated.py
@@ -0,0 +1,115 @@
+# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from frappe.tests.utils import FrappeTestCase
+
+from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
+from erpnext.manufacturing.report.bom_stock_calculated.bom_stock_calculated import (
+ execute as bom_stock_calculated_report,
+)
+from erpnext.stock.doctype.item.test_item import make_item
+
+
+class TestBOMStockCalculated(FrappeTestCase):
+ def setUp(self):
+ self.fg_item, self.rm_items = create_items()
+ self.boms = create_boms(self.fg_item, self.rm_items)
+
+ def test_bom_stock_calculated(self):
+ qty_to_make = 10
+
+ # Case 1: When Item(s) Qty and Stock Qty are equal.
+ data = bom_stock_calculated_report(
+ filters={
+ "qty_to_make": qty_to_make,
+ "bom": self.boms[0].name,
+ }
+ )[1]
+ expected_data = get_expected_data(self.boms[0], qty_to_make)
+ self.assertSetEqual(set(tuple(x) for x in data), set(tuple(x) for x in expected_data))
+
+ # Case 2: When Item(s) Qty and Stock Qty are different and BOM Qty is 1.
+ data = bom_stock_calculated_report(
+ filters={
+ "qty_to_make": qty_to_make,
+ "bom": self.boms[1].name,
+ }
+ )[1]
+ expected_data = get_expected_data(self.boms[1], qty_to_make)
+ self.assertSetEqual(set(tuple(x) for x in data), set(tuple(x) for x in expected_data))
+
+ # Case 3: When Item(s) Qty and Stock Qty are different and BOM Qty is greater than 1.
+ data = bom_stock_calculated_report(
+ filters={
+ "qty_to_make": qty_to_make,
+ "bom": self.boms[2].name,
+ }
+ )[1]
+ expected_data = get_expected_data(self.boms[2], qty_to_make)
+ self.assertSetEqual(set(tuple(x) for x in data), set(tuple(x) for x in expected_data))
+
+
+def create_items():
+ fg_item = make_item(properties={"is_stock_item": 1}).name
+ rm_item1 = make_item(
+ properties={
+ "is_stock_item": 1,
+ "standard_rate": 100,
+ "opening_stock": 100,
+ "last_purchase_rate": 100,
+ }
+ ).name
+ rm_item2 = make_item(
+ properties={
+ "is_stock_item": 1,
+ "standard_rate": 200,
+ "opening_stock": 200,
+ "last_purchase_rate": 200,
+ }
+ ).name
+
+ return fg_item, [rm_item1, rm_item2]
+
+
+def create_boms(fg_item, rm_items):
+ def update_bom_items(bom, uom, conversion_factor):
+ for item in bom.items:
+ item.uom = uom
+ item.conversion_factor = conversion_factor
+
+ return bom
+
+ bom1 = make_bom(item=fg_item, quantity=1, raw_materials=rm_items, rm_qty=10)
+
+ bom2 = make_bom(item=fg_item, quantity=1, raw_materials=rm_items, rm_qty=10, do_not_submit=True)
+ bom2 = update_bom_items(bom2, "Box", 10)
+ bom2.save()
+ bom2.submit()
+
+ bom3 = make_bom(item=fg_item, quantity=2, raw_materials=rm_items, rm_qty=10, do_not_submit=True)
+ bom3 = update_bom_items(bom3, "Box", 10)
+ bom3.save()
+ bom3.submit()
+
+ return [bom1, bom2, bom3]
+
+
+def get_expected_data(bom, qty_to_make):
+ expected_data = []
+
+ for idx in range(len(bom.items)):
+ expected_data.append(
+ [
+ bom.items[idx].item_code,
+ bom.items[idx].item_code,
+ "",
+ "",
+ float(bom.items[idx].stock_qty / bom.quantity),
+ float(100 * (idx + 1)),
+ float(qty_to_make * (bom.items[idx].stock_qty / bom.quantity)),
+ float((100 * (idx + 1)) - (qty_to_make * (bom.items[idx].stock_qty / bom.quantity))),
+ float(100 * (idx + 1)),
+ ]
+ )
+
+ return expected_data