Merge pull request #33347 from vishdha/fb_based_operating_cost
feat: Add operating cost based on bom quanity without creating job card
This commit is contained in:
commit
20fe1875e7
@ -65,7 +65,13 @@ frappe.ui.form.on("BOM", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onload_post_render(frm) {
|
validate: function(frm) {
|
||||||
|
if (frm.doc.fg_based_operating_cost && frm.doc.with_operations) {
|
||||||
|
frappe.throw({message: __("Please check either with operations or FG Based Operating Cost."), title: __("Mandatory")});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onload_post_render: function(frm) {
|
||||||
frm.get_field("items").grid.set_multiple_add("item_code", "qty");
|
frm.get_field("items").grid.set_multiple_add("item_code", "qty");
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -536,6 +542,7 @@ erpnext.bom.calculate_op_cost = function(doc) {
|
|||||||
doc.operating_cost = 0.0;
|
doc.operating_cost = 0.0;
|
||||||
doc.base_operating_cost = 0.0;
|
doc.base_operating_cost = 0.0;
|
||||||
|
|
||||||
|
if(doc.with_operations) {
|
||||||
for(var i=0;i<op.length;i++) {
|
for(var i=0;i<op.length;i++) {
|
||||||
var operating_cost = flt(flt(op[i].hour_rate) * flt(op[i].time_in_mins) / 60, 2);
|
var operating_cost = flt(flt(op[i].hour_rate) * flt(op[i].time_in_mins) / 60, 2);
|
||||||
var base_operating_cost = flt(operating_cost * doc.conversion_rate, 2);
|
var base_operating_cost = flt(operating_cost * doc.conversion_rate, 2);
|
||||||
@ -545,6 +552,11 @@ erpnext.bom.calculate_op_cost = function(doc) {
|
|||||||
doc.operating_cost += operating_cost;
|
doc.operating_cost += operating_cost;
|
||||||
doc.base_operating_cost += base_operating_cost;
|
doc.base_operating_cost += base_operating_cost;
|
||||||
}
|
}
|
||||||
|
} else if(doc.fg_based_operating_cost) {
|
||||||
|
let total_operating_cost = doc.quantity * flt(doc.operating_cost_per_bom_quantity);
|
||||||
|
doc.operating_cost = total_operating_cost;
|
||||||
|
doc.base_operating_cost = flt(total_operating_cost * doc.conversion_rate, 2);
|
||||||
|
}
|
||||||
refresh_field(['operating_cost', 'base_operating_cost']);
|
refresh_field(['operating_cost', 'base_operating_cost']);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,6 +33,9 @@
|
|||||||
"column_break_23",
|
"column_break_23",
|
||||||
"transfer_material_against",
|
"transfer_material_against",
|
||||||
"routing",
|
"routing",
|
||||||
|
"fg_based_operating_cost",
|
||||||
|
"fg_based_section_section",
|
||||||
|
"operating_cost_per_bom_quantity",
|
||||||
"operations_section",
|
"operations_section",
|
||||||
"operations",
|
"operations",
|
||||||
"materials_section",
|
"materials_section",
|
||||||
@ -575,7 +578,26 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "scrap_items_section",
|
"fieldname": "scrap_items_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Scrap Items"
|
"label": "Scrap Items",
|
||||||
|
"hide_border": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "fg_based_operating_cost",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "FG based Operating Cost"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "fg_based_operating_cost",
|
||||||
|
"fieldname": "fg_based_section_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "FG Based Operating Cost Section"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "fg_based_operating_cost",
|
||||||
|
"fieldname": "operating_cost_per_bom_quantity",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Operating Cost Per BOM Quantity"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-sitemap",
|
"icon": "fa fa-sitemap",
|
||||||
|
@ -614,6 +614,7 @@ class BOM(WebsiteGenerator):
|
|||||||
"""Update workstation rate and calculates totals"""
|
"""Update workstation rate and calculates totals"""
|
||||||
self.operating_cost = 0
|
self.operating_cost = 0
|
||||||
self.base_operating_cost = 0
|
self.base_operating_cost = 0
|
||||||
|
if self.get("with_operations"):
|
||||||
for d in self.get("operations"):
|
for d in self.get("operations"):
|
||||||
if d.workstation:
|
if d.workstation:
|
||||||
self.update_rate_and_time(d, update_hour_rate)
|
self.update_rate_and_time(d, update_hour_rate)
|
||||||
@ -627,6 +628,13 @@ class BOM(WebsiteGenerator):
|
|||||||
self.operating_cost += flt(operating_cost)
|
self.operating_cost += flt(operating_cost)
|
||||||
self.base_operating_cost += flt(base_operating_cost)
|
self.base_operating_cost += flt(base_operating_cost)
|
||||||
|
|
||||||
|
elif self.get("fg_based_operating_cost"):
|
||||||
|
total_operating_cost = flt(self.get("quantity")) * flt(
|
||||||
|
self.get("operating_cost_per_bom_quantity")
|
||||||
|
)
|
||||||
|
self.operating_cost = total_operating_cost
|
||||||
|
self.base_operating_cost = flt(total_operating_cost * self.conversion_rate, 2)
|
||||||
|
|
||||||
def update_rate_and_time(self, row, update_hour_rate=False):
|
def update_rate_and_time(self, row, update_hour_rate=False):
|
||||||
if not row.hour_rate or update_hour_rate:
|
if not row.hour_rate or update_hour_rate:
|
||||||
hour_rate = flt(frappe.get_cached_value("Workstation", row.workstation, "hour_rate"))
|
hour_rate = flt(frappe.get_cached_value("Workstation", row.workstation, "hour_rate"))
|
||||||
|
@ -202,6 +202,33 @@ class TestBOM(FrappeTestCase):
|
|||||||
|
|
||||||
self.assertEqual(bom.items[0].rate, 20)
|
self.assertEqual(bom.items[0].rate, 20)
|
||||||
|
|
||||||
|
def test_bom_cost_with_fg_based_operating_cost(self):
|
||||||
|
bom = frappe.copy_doc(test_records[4])
|
||||||
|
bom.insert()
|
||||||
|
|
||||||
|
raw_material_cost = 0.0
|
||||||
|
op_cost = 0.0
|
||||||
|
|
||||||
|
op_cost = bom.quantity * bom.operating_cost_per_bom_quantity
|
||||||
|
|
||||||
|
for row in bom.items:
|
||||||
|
raw_material_cost += row.amount
|
||||||
|
|
||||||
|
base_raw_material_cost = raw_material_cost * flt(
|
||||||
|
bom.conversion_rate, bom.precision("conversion_rate")
|
||||||
|
)
|
||||||
|
base_op_cost = op_cost * flt(bom.conversion_rate, bom.precision("conversion_rate"))
|
||||||
|
|
||||||
|
# test amounts in selected currency, almostEqual checks for 7 digits by default
|
||||||
|
self.assertAlmostEqual(bom.operating_cost, op_cost)
|
||||||
|
self.assertAlmostEqual(bom.raw_material_cost, raw_material_cost)
|
||||||
|
self.assertAlmostEqual(bom.total_cost, raw_material_cost + op_cost)
|
||||||
|
|
||||||
|
# test amounts in selected currency
|
||||||
|
self.assertAlmostEqual(bom.base_operating_cost, base_op_cost)
|
||||||
|
self.assertAlmostEqual(bom.base_raw_material_cost, base_raw_material_cost)
|
||||||
|
self.assertAlmostEqual(bom.base_total_cost, base_raw_material_cost + base_op_cost)
|
||||||
|
|
||||||
def test_subcontractor_sourced_item(self):
|
def test_subcontractor_sourced_item(self):
|
||||||
item_code = "_Test Subcontracted FG Item 1"
|
item_code = "_Test Subcontracted FG Item 1"
|
||||||
set_backflush_based_on("Material Transferred for Subcontract")
|
set_backflush_based_on("Material Transferred for Subcontract")
|
||||||
|
@ -162,5 +162,31 @@
|
|||||||
"item": "_Test Variant Item",
|
"item": "_Test Variant Item",
|
||||||
"quantity": 1.0,
|
"quantity": 1.0,
|
||||||
"with_operations": 1
|
"with_operations": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"amount": 5000.0,
|
||||||
|
"doctype": "BOM Item",
|
||||||
|
"item_code": "_Test Item",
|
||||||
|
"parentfield": "items",
|
||||||
|
"qty": 2.0,
|
||||||
|
"rate": 3000.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",
|
||||||
|
"item": "_Test Variant Item",
|
||||||
|
"quantity": 1.0,
|
||||||
|
"with_operations": 0,
|
||||||
|
"fg_based_operating_cost": 1,
|
||||||
|
"operating_cost_per_bom_quantity": 140
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user