* 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
This commit is contained in:
@@ -162,5 +162,54 @@
|
|||||||
"item": "_Test Variant Item",
|
"item": "_Test Variant Item",
|
||||||
"quantity": 1.0,
|
"quantity": 1.0,
|
||||||
"with_operations": 1
|
"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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"col_break1",
|
"col_break1",
|
||||||
"workstation",
|
"workstation",
|
||||||
"time_in_mins",
|
"time_in_mins",
|
||||||
|
"fixed_time",
|
||||||
"costing_section",
|
"costing_section",
|
||||||
"hour_rate",
|
"hour_rate",
|
||||||
"base_hour_rate",
|
"base_hour_rate",
|
||||||
@@ -80,6 +81,14 @@
|
|||||||
"oldfieldtype": "Currency",
|
"oldfieldtype": "Currency",
|
||||||
"reqd": 1
|
"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",
|
"fieldname": "operating_cost",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
@@ -177,7 +186,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-04-08 01:18:33.547481",
|
"modified": "2022-08-22 01:18:33.547481",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "BOM Operation",
|
"name": "BOM Operation",
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class TestWorkOrder(FrappeTestCase):
|
|||||||
|
|
||||||
def test_planned_operating_cost(self):
|
def test_planned_operating_cost(self):
|
||||||
wo_order = make_wo_order_test_record(
|
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()
|
wo_order.set_work_order_operations()
|
||||||
cost = wo_order.planned_operating_cost
|
cost = wo_order.planned_operating_cost
|
||||||
@@ -1001,6 +1001,49 @@ class TestWorkOrder(FrappeTestCase):
|
|||||||
close_work_order(wo_order, "Closed")
|
close_work_order(wo_order, "Closed")
|
||||||
self.assertEqual(wo_order.get("status"), "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):
|
def test_partial_manufacture_entries(self):
|
||||||
cancel_stock_entry = []
|
cancel_stock_entry = []
|
||||||
|
|
||||||
@@ -1015,7 +1058,6 @@ class TestWorkOrder(FrappeTestCase):
|
|||||||
ste1 = test_stock_entry.make_stock_entry(
|
ste1 = test_stock_entry.make_stock_entry(
|
||||||
item_code="_Test Item", target="_Test Warehouse - _TC", qty=120, basic_rate=5000.0
|
item_code="_Test Item", target="_Test Warehouse - _TC", qty=120, basic_rate=5000.0
|
||||||
)
|
)
|
||||||
|
|
||||||
ste2 = test_stock_entry.make_stock_entry(
|
ste2 = test_stock_entry.make_stock_entry(
|
||||||
item_code="_Test Item Home Desktop 100",
|
item_code="_Test Item Home Desktop 100",
|
||||||
target="_Test Warehouse - _TC",
|
target="_Test Warehouse - _TC",
|
||||||
|
|||||||
@@ -653,20 +653,31 @@ class WorkOrder(Document):
|
|||||||
"""Fetch operations from BOM and set in 'Work Order'"""
|
"""Fetch operations from BOM and set in 'Work Order'"""
|
||||||
|
|
||||||
def _get_operations(bom_no, qty=1):
|
def _get_operations(bom_no, qty=1):
|
||||||
return frappe.db.sql(
|
data = frappe.get_all(
|
||||||
f"""select
|
"BOM Operation",
|
||||||
operation, description, workstation, idx,
|
filters={"parent": bom_no},
|
||||||
base_hour_rate as hour_rate, time_in_mins * {qty} as time_in_mins,
|
fields=[
|
||||||
"Pending" as status, parent as bom, batch_size, sequence_id
|
"operation",
|
||||||
from
|
"description",
|
||||||
`tabBOM Operation`
|
"workstation",
|
||||||
where
|
"idx",
|
||||||
parent = %s order by idx
|
"base_hour_rate as hour_rate",
|
||||||
""",
|
"time_in_mins",
|
||||||
bom_no,
|
"parent as bom",
|
||||||
as_dict=1,
|
"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", [])
|
self.set("operations", [])
|
||||||
if not self.bom_no or not frappe.get_cached_value("BOM", self.bom_no, "with_operations"):
|
if not self.bom_no or not frappe.get_cached_value("BOM", self.bom_no, "with_operations"):
|
||||||
return
|
return
|
||||||
@@ -692,6 +703,7 @@ class WorkOrder(Document):
|
|||||||
|
|
||||||
def calculate_time(self):
|
def calculate_time(self):
|
||||||
for d in self.get("operations"):
|
for d in self.get("operations"):
|
||||||
|
if not d.fixed_time:
|
||||||
d.time_in_mins = flt(d.time_in_mins) * (flt(self.qty) / flt(d.batch_size))
|
d.time_in_mins = flt(d.time_in_mins) * (flt(self.qty) / flt(d.batch_size))
|
||||||
|
|
||||||
self.calculate_operating_cost()
|
self.calculate_operating_cost()
|
||||||
|
|||||||
@@ -272,6 +272,28 @@
|
|||||||
"income_account": "Sales - _TC"
|
"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",
|
"description": "_Test Variant Item 12",
|
||||||
"doctype": "Item",
|
"doctype": "Item",
|
||||||
|
|||||||
Reference in New Issue
Block a user