From c2b8d1bd9acea306894e02df9c3146f1fb993f09 Mon Sep 17 00:00:00 2001 From: HENRY Florian Date: Thu, 25 Aug 2022 07:44:35 +0200 Subject: [PATCH] feat: In BOM, Operation time can be fix (backport #27063) (#31923) * feat: In BOM Operation time can be fix (backport #27063) * chore: only changes necessary for feature * chore: add test * chore: linter * chore: linter * chore: linter * chore: fix date in json * chore: fix test order * chore: revert test from version-13 not develop * chore: make test ok --- .../doctype/bom/test_records.json | 49 +++++++++++++++++++ .../doctype/bom_operation/bom_operation.json | 13 ++++- .../doctype/work_order/test_work_order.py | 46 ++++++++++++++++- .../doctype/work_order/work_order.py | 38 +++++++++----- erpnext/stock/doctype/item/test_records.json | 22 +++++++++ 5 files changed, 151 insertions(+), 17 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/test_records.json b/erpnext/manufacturing/doctype/bom/test_records.json index 507d319b515..a79ccfc8ce4 100644 --- a/erpnext/manufacturing/doctype/bom/test_records.json +++ b/erpnext/manufacturing/doctype/bom/test_records.json @@ -162,5 +162,54 @@ "item": "_Test Variant Item", "quantity": 1.0, "with_operations": 1 + }, + { + "operations": [ + { + "operation": "_Test Operation 1", + "description": "_Test", + "workstation": "_Test Workstation 1", + "hour_rate": 100, + "time_in_mins": 60, + "operating_cost": 100 + } + ], + "items": [ + { + "amount": 5000.0, + "doctype": "BOM Item", + "item_code": "_Test Item", + "parentfield": "items", + "qty": 1.0, + "rate": 5000.0, + "uom": "_Test UOM", + "stock_uom": "_Test UOM", + "source_warehouse": "_Test Warehouse - _TC", + "include_item_in_manufacturing": 1 + }, + { + "amount": 3000.0, + "bom_no": "BOM-_Test Item Home Desktop Manufactured-001", + "doctype": "BOM Item", + "item_code": "_Test Item Home Desktop Manufactured", + "parentfield": "items", + "qty": 3.0, + "rate": 1000.0, + "uom": "_Test UOM", + "stock_uom": "_Test UOM", + "source_warehouse": "_Test Warehouse - _TC", + "include_item_in_manufacturing": 1 + } + ], + "docstatus": 1, + "doctype": "BOM", + "is_active": 1, + "is_default": 1, + "currency": "USD", + "conversion_rate": 60, + "company": "_Test Company", + "item": "_Test FG Item 3", + "quantity": 1.0, + "with_operations": 1 } ] diff --git a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json index 210c0ea6a72..6bd64594202 100644 --- a/erpnext/manufacturing/doctype/bom_operation/bom_operation.json +++ b/erpnext/manufacturing/doctype/bom_operation/bom_operation.json @@ -11,6 +11,7 @@ "col_break1", "workstation", "time_in_mins", + "fixed_time", "costing_section", "hour_rate", "base_hour_rate", @@ -80,6 +81,14 @@ "oldfieldtype": "Currency", "reqd": 1 }, + { + "default": "0", + "description": "Operation time does not depend on quantity to produce", + "fieldname": "fixed_time", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Fixed Time" + }, { "fieldname": "operating_cost", "fieldtype": "Currency", @@ -177,7 +186,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2022-04-08 01:18:33.547481", + "modified": "2022-08-22 01:18:33.547481", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Operation", @@ -185,4 +194,4 @@ "permissions": [], "sort_field": "modified", "sort_order": "DESC" -} \ No newline at end of file +} diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index 1e629b2fbfa..cfba0fff15e 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -95,7 +95,7 @@ class TestWorkOrder(FrappeTestCase): def test_planned_operating_cost(self): wo_order = make_wo_order_test_record( - item="_Test FG Item 2", planned_start_date=now(), qty=1, do_not_save=True + item="_Test FG Item 3", planned_start_date=now(), qty=1, do_not_save=True ) wo_order.set_work_order_operations() cost = wo_order.planned_operating_cost @@ -1001,6 +1001,49 @@ class TestWorkOrder(FrappeTestCase): close_work_order(wo_order, "Closed") self.assertEqual(wo_order.get("status"), "Closed") + def test_fix_time_operations(self): + bom = frappe.get_doc( + { + "doctype": "BOM", + "item": "_Test FG Item 2", + "is_active": 1, + "is_default": 1, + "quantity": 1.0, + "with_operations": 1, + "operations": [ + { + "operation": "_Test Operation 1", + "description": "_Test", + "workstation": "_Test Workstation 1", + "time_in_mins": 60, + "operating_cost": 140, + "fixed_time": 1, + } + ], + "items": [ + { + "amount": 5000.0, + "doctype": "BOM Item", + "item_code": "_Test Item", + "parentfield": "items", + "qty": 1.0, + "rate": 5000.0, + }, + ], + } + ) + bom.save() + bom.submit() + + wo1 = make_wo_order_test_record( + item=bom.item, bom_no=bom.name, qty=1, skip_transfer=1, do_not_submit=1 + ) + wo2 = make_wo_order_test_record( + item=bom.item, bom_no=bom.name, qty=2, skip_transfer=1, do_not_submit=1 + ) + + self.assertEqual(wo1.operations[0].time_in_mins, wo2.operations[0].time_in_mins) + def test_partial_manufacture_entries(self): cancel_stock_entry = [] @@ -1015,7 +1058,6 @@ class TestWorkOrder(FrappeTestCase): ste1 = test_stock_entry.make_stock_entry( item_code="_Test Item", target="_Test Warehouse - _TC", qty=120, basic_rate=5000.0 ) - ste2 = test_stock_entry.make_stock_entry( item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC", diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py index dc553c15ad5..2802310250b 100644 --- a/erpnext/manufacturing/doctype/work_order/work_order.py +++ b/erpnext/manufacturing/doctype/work_order/work_order.py @@ -653,20 +653,31 @@ class WorkOrder(Document): """Fetch operations from BOM and set in 'Work Order'""" def _get_operations(bom_no, qty=1): - return frappe.db.sql( - f"""select - operation, description, workstation, idx, - base_hour_rate as hour_rate, time_in_mins * {qty} as time_in_mins, - "Pending" as status, parent as bom, batch_size, sequence_id - from - `tabBOM Operation` - where - parent = %s order by idx - """, - bom_no, - as_dict=1, + data = frappe.get_all( + "BOM Operation", + filters={"parent": bom_no}, + fields=[ + "operation", + "description", + "workstation", + "idx", + "base_hour_rate as hour_rate", + "time_in_mins", + "parent as bom", + "batch_size", + "sequence_id", + "fixed_time", + ], + order_by="idx", ) + for d in data: + if not d.fixed_time: + d.time_in_mins = flt(d.time_in_mins) * flt(qty) + d.status = "Pending" + + return data + self.set("operations", []) if not self.bom_no or not frappe.get_cached_value("BOM", self.bom_no, "with_operations"): return @@ -692,7 +703,8 @@ class WorkOrder(Document): def calculate_time(self): for d in self.get("operations"): - d.time_in_mins = flt(d.time_in_mins) * (flt(self.qty) / flt(d.batch_size)) + if not d.fixed_time: + d.time_in_mins = flt(d.time_in_mins) * (flt(self.qty) / flt(d.batch_size)) self.calculate_operating_cost() diff --git a/erpnext/stock/doctype/item/test_records.json b/erpnext/stock/doctype/item/test_records.json index 91c77d51529..c59c6586d21 100644 --- a/erpnext/stock/doctype/item/test_records.json +++ b/erpnext/stock/doctype/item/test_records.json @@ -272,6 +272,28 @@ "income_account": "Sales - _TC" }] }, + { + "description": "_Test FG Item 3 11", + "doctype": "Item", + "has_batch_no": 0, + "has_serial_no": 0, + "inspection_required": 0, + "is_stock_item": 1, + "is_sub_contracted_item": 1, + "item_code": "_Test FG Item 3", + "item_group": "_Test Item Group Desktops", + "item_name": "_Test FG Item 3", + "stock_uom": "_Test UOM", + "gst_hsn_code": "999800", + "item_defaults": [{ + "company": "_Test Company", + "default_warehouse": "_Test Warehouse - _TC", + "expense_account": "_Test Account Cost for Goods Sold - _TC", + "buying_cost_center": "_Test Cost Center - _TC", + "selling_cost_center": "_Test Cost Center - _TC", + "income_account": "Sales - _TC" + }] + }, { "description": "_Test Variant Item 12", "doctype": "Item",