diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py index 3c7f8b0ccca..5fb1ee468cd 100644 --- a/erpnext/controllers/subcontracting_controller.py +++ b/erpnext/controllers/subcontracting_controller.py @@ -561,11 +561,11 @@ class SubcontractingController(StockController): use_serial_batch_fields = frappe.db.get_single_value("Stock Settings", "use_serial_batch_fields") if self.doctype == self.subcontract_data.order_doctype: - rm_obj.required_qty = qty - rm_obj.amount = rm_obj.required_qty * rm_obj.rate + rm_obj.required_qty = flt(qty, rm_obj.precision("required_qty")) + rm_obj.amount = flt(rm_obj.required_qty * rm_obj.rate, rm_obj.precision("amount")) else: - rm_obj.consumed_qty = qty - rm_obj.required_qty = bom_item.required_qty or qty + rm_obj.consumed_qty = flt(qty, rm_obj.precision("consumed_qty")) + rm_obj.required_qty = flt(bom_item.required_qty or qty, rm_obj.precision("required_qty")) rm_obj.serial_and_batch_bundle = None setattr( rm_obj, self.subcontract_data.order_field, item_row.get(self.subcontract_data.order_field) @@ -664,8 +664,8 @@ class SubcontractingController(StockController): self.__set_serial_nos(item_row, rm_obj) def __set_consumed_qty(self, rm_obj, consumed_qty, required_qty=0): - rm_obj.required_qty = required_qty - rm_obj.consumed_qty = consumed_qty + rm_obj.required_qty = flt(required_qty, rm_obj.precision("required_qty")) + rm_obj.consumed_qty = flt(consumed_qty, rm_obj.precision("consumed_qty")) def __set_serial_nos(self, item_row, rm_obj): key = (rm_obj.rm_item_code, item_row.item_code, item_row.get(self.subcontract_data.order_field)) diff --git a/erpnext/controllers/tests/test_subcontracting_controller.py b/erpnext/controllers/tests/test_subcontracting_controller.py index 84f7e057dea..6530ee9a52f 100644 --- a/erpnext/controllers/tests/test_subcontracting_controller.py +++ b/erpnext/controllers/tests/test_subcontracting_controller.py @@ -1234,6 +1234,7 @@ def make_subcontracted_items(): "Subcontracted Item SA6": {}, "Subcontracted Item SA7": {}, "Subcontracted Item SA8": {}, + "Subcontracted Item SA9": {"stock_uom": "Litre"}, } for item, properties in sub_contracted_items.items(): @@ -1254,6 +1255,7 @@ def make_raw_materials(): "Subcontracted SRM Item 4": {"has_serial_no": 1, "serial_no_series": "SRII.####"}, "Subcontracted SRM Item 5": {"has_serial_no": 1, "serial_no_series": "SRIID.####"}, "Subcontracted SRM Item 8": {}, + "Subcontracted SRM Item 9": {"stock_uom": "Litre"}, } for item, properties in raw_materials.items(): @@ -1280,6 +1282,7 @@ def make_service_items(): "Subcontracted Service Item 6": {}, "Subcontracted Service Item 7": {}, "Subcontracted Service Item 8": {}, + "Subcontracted Service Item 9": {}, } for item, properties in service_items.items(): diff --git a/erpnext/manufacturing/report/test_reports.py b/erpnext/manufacturing/report/test_reports.py index afe3f0890e6..e69de29bb2d 100644 --- a/erpnext/manufacturing/report/test_reports.py +++ b/erpnext/manufacturing/report/test_reports.py @@ -1,65 +0,0 @@ -import unittest - -import frappe -from frappe.tests import IntegrationTestCase - -from erpnext.tests.utils import ReportFilters, ReportName, execute_script_report - -DEFAULT_FILTERS = { - "company": "_Test Company", - "from_date": "2010-01-01", - "to_date": "2030-01-01", - "warehouse": "_Test Warehouse - _TC", -} - - -REPORT_FILTER_TEST_CASES: list[tuple[ReportName, ReportFilters]] = [ - ("BOM Explorer", {"bom": frappe.get_last_doc("BOM").name}), - ("BOM Operations Time", {}), - ("BOM Stock Calculated", {"bom": frappe.get_last_doc("BOM").name, "qty_to_make": 2}), - ("BOM Stock Report", {"bom": frappe.get_last_doc("BOM").name, "qty_to_produce": 2}), - ("Cost of Poor Quality Report", {"item": "_Test Item", "serial_no": "00"}), - ("Downtime Analysis", {}), - ( - "Exponential Smoothing Forecasting", - { - "based_on_document": "Sales Order", - "based_on_field": "Qty", - "no_of_years": 3, - "periodicity": "Yearly", - "smoothing_constant": 0.3, - }, - ), - ("Job Card Summary", {"fiscal_year": "2021-2022"}), - ("Production Analytics", {"range": "Monthly"}), - ("Quality Inspection Summary", {}), - ("Process Loss Report", {}), - ("Work Order Stock Report", {}), - ("Work Order Summary", {"fiscal_year": "2021-2022", "age": 0}), -] - - -if frappe.db.a_row_exists("Production Plan"): - REPORT_FILTER_TEST_CASES.append( - ("Production Plan Summary", {"production_plan": frappe.get_last_doc("Production Plan").name}) - ) - -OPTIONAL_FILTERS = { - "warehouse": "_Test Warehouse - _TC", - "item": "_Test Item", - "item_group": "_Test Item Group", -} - - -class TestManufacturingReports(IntegrationTestCase): - def test_execute_all_manufacturing_reports(self): - """Test that all script report in manufacturing modules are executable with supported filters""" - for report, filter in REPORT_FILTER_TEST_CASES: - with self.subTest(report=report): - execute_script_report( - report_name=report, - module="Manufacturing", - filters=filter, - default_filters=DEFAULT_FILTERS, - optional_filters=OPTIONAL_FILTERS if filter.get("_optional") else None, - ) diff --git a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py index aca315e00d1..69e53d9bb01 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py +++ b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py @@ -25,6 +25,7 @@ from erpnext.controllers.tests.test_subcontracting_controller import ( make_subcontracted_items, set_backflush_based_on, ) +from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import ( @@ -692,6 +693,28 @@ class TestSubcontractingOrder(IntegrationTestCase): self.assertEqual(requested_qty, new_requested_qty) + def test_subcontracting_order_rm_required_items_for_precision(self): + item_code = "Subcontracted Item SA9" + raw_materials = ["Subcontracted SRM Item 9"] + if not frappe.db.exists("BOM", {"item": item_code}): + make_bom(item=item_code, raw_materials=raw_materials, rate=100, rm_qty=1.04) + + service_items = [ + { + "warehouse": "_Test Warehouse - _TC", + "item_code": "Subcontracted Service Item 9", + "qty": 1, # 202.0656, + "rate": 100, + "fg_item": "Subcontracted Item SA9", + "fg_item_qty": 202.0656, + }, + ] + + sco = get_subcontracting_order(service_items=service_items) + sco.reload() + + self.assertEqual(sco.supplied_items[0].required_qty, 210.149) + def create_subcontracting_order(**args): args = frappe._dict(args)