Merge pull request #2174 from neilLasrado/cost-of-production-cycle-magix
Cost of Production cycle
This commit is contained in:
commit
84e08fd534
@ -66,7 +66,10 @@ cur_frm.cscript.workstation = function(doc,dt,dn) {
|
||||
frappe.model.with_doc("Workstation", d.workstation, function(name, r) {
|
||||
d.hour_rate = r.docs[0].hour_rate;
|
||||
refresh_field("hour_rate", dn, "bom_operations");
|
||||
d.fixed_cycle_cost = r.docs[0].fixed_cycle_cost;
|
||||
refresh_field("fixed_cycle_cost", dn, "bom_operations");
|
||||
erpnext.bom.calculate_op_cost(doc);
|
||||
erpnext.bom.calculate_fixed_cost(doc);
|
||||
erpnext.bom.calculate_total(doc);
|
||||
});
|
||||
}
|
||||
@ -74,6 +77,7 @@ cur_frm.cscript.workstation = function(doc,dt,dn) {
|
||||
|
||||
cur_frm.cscript.hour_rate = function(doc, dt, dn) {
|
||||
erpnext.bom.calculate_op_cost(doc);
|
||||
erpnext.bom.calculate_fixed_cost(doc);
|
||||
erpnext.bom.calculate_total(doc);
|
||||
}
|
||||
|
||||
@ -116,7 +120,6 @@ var get_bom_material_detail= function(doc, cdt, cdn) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cur_frm.cscript.qty = function(doc, cdt, cdn) {
|
||||
erpnext.bom.calculate_rm_cost(doc);
|
||||
erpnext.bom.calculate_total(doc);
|
||||
@ -145,6 +148,15 @@ erpnext.bom.calculate_op_cost = function(doc) {
|
||||
refresh_field('operating_cost');
|
||||
}
|
||||
|
||||
erpnext.bom.calculate_fixed_cost = function(doc) {
|
||||
var op = doc.bom_operations || [];
|
||||
var total_fixed_cost = 0;
|
||||
for(var i=0;i<op.length;i++) {
|
||||
total_fixed_cost += flt(op[i].fixed_cycle_cost);
|
||||
}
|
||||
cur_frm.set_value("total_fixed_cost", total_fixed_cost);
|
||||
}
|
||||
|
||||
erpnext.bom.calculate_rm_cost = function(doc) {
|
||||
var rm = doc.bom_materials || [];
|
||||
total_rm_cost = 0;
|
||||
@ -155,14 +167,15 @@ erpnext.bom.calculate_rm_cost = function(doc) {
|
||||
{'qty_consumed_per_unit': flt(rm[i].qty)/flt(doc.quantity)}, 'bom_materials');
|
||||
total_rm_cost += amt;
|
||||
}
|
||||
doc.raw_material_cost = total_rm_cost;
|
||||
refresh_field('raw_material_cost');
|
||||
cur_frm.set_value("raw_material_cost", total_rm_cost);
|
||||
}
|
||||
|
||||
|
||||
// Calculate Total Cost
|
||||
erpnext.bom.calculate_total = function(doc) {
|
||||
doc.total_cost = flt(doc.raw_material_cost) + flt(doc.operating_cost);
|
||||
doc.total_variable_cost = flt(doc.raw_material_cost) + flt(doc.operating_cost) ;
|
||||
refresh_field('total_variable_cost');
|
||||
doc.total_cost = flt(doc.total_fixed_cost) + flt(doc.total_variable_cost);
|
||||
refresh_field('total_cost');
|
||||
}
|
||||
|
||||
@ -204,5 +217,7 @@ cur_frm.fields_dict['bom_materials'].grid.get_field('bom_no').get_query = functi
|
||||
cur_frm.cscript.validate = function(doc, dt, dn) {
|
||||
erpnext.bom.calculate_op_cost(doc);
|
||||
erpnext.bom.calculate_rm_cost(doc);
|
||||
erpnext.bom.calculate_fixed_cost(doc);
|
||||
erpnext.bom.calculate_total(doc);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_attach": 0,
|
||||
"allow_copy": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
"creation": "2013-01-22 15:11:38",
|
||||
@ -86,6 +87,7 @@
|
||||
{
|
||||
"fieldname": "bom_operations",
|
||||
"fieldtype": "Table",
|
||||
"in_list_view": 0,
|
||||
"label": "BOM Operations",
|
||||
"oldfieldname": "bom_operations",
|
||||
"oldfieldtype": "Table",
|
||||
@ -115,19 +117,6 @@
|
||||
"oldfieldtype": "Section Break",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "total_cost",
|
||||
"fieldtype": "Float",
|
||||
"in_list_view": 1,
|
||||
"label": "Total Cost",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "cb1",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "raw_material_cost",
|
||||
"fieldtype": "Float",
|
||||
@ -142,6 +131,33 @@
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "cb1",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "total_variable_cost",
|
||||
"fieldtype": "Float",
|
||||
"in_list_view": 1,
|
||||
"label": "Total Variable Cost",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "total_fixed_cost",
|
||||
"fieldtype": "Float",
|
||||
"label": "Total Fixed Cost",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "total_cost",
|
||||
"fieldtype": "Float",
|
||||
"label": "Total Cost",
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "more_info_section",
|
||||
"fieldtype": "Section Break",
|
||||
@ -232,7 +248,7 @@
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"modified": "2014-05-27 03:49:08.024523",
|
||||
"modified": "2014-09-08 16:30:46.265762",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "BOM",
|
||||
|
@ -127,7 +127,7 @@ class BOM(Document):
|
||||
self.save()
|
||||
|
||||
def get_bom_unitcost(self, bom_no):
|
||||
bom = frappe.db.sql("""select name, total_cost/quantity as unit_cost from `tabBOM`
|
||||
bom = frappe.db.sql("""select name, total_variable_cost/quantity as unit_cost from `tabBOM`
|
||||
where is_active = 1 and name = %s""", bom_no, as_dict=1)
|
||||
return bom and bom[0]['unit_cost'] or 0
|
||||
|
||||
@ -269,7 +269,8 @@ class BOM(Document):
|
||||
"""Calculate bom totals"""
|
||||
self.calculate_op_cost()
|
||||
self.calculate_rm_cost()
|
||||
self.total_cost = self.raw_material_cost + self.operating_cost
|
||||
self.calculate_fixed_cost()
|
||||
self.total_variable_cost = self.raw_material_cost + self.operating_cost
|
||||
|
||||
def calculate_op_cost(self):
|
||||
"""Update workstation rate and calculates totals"""
|
||||
@ -282,6 +283,15 @@ class BOM(Document):
|
||||
total_op_cost += flt(d.operating_cost)
|
||||
self.operating_cost = total_op_cost
|
||||
|
||||
def calculate_fixed_cost(self):
|
||||
"""Update workstation rate and calculates totals"""
|
||||
fixed_cost = 0
|
||||
for d in self.get('bom_operations'):
|
||||
if d.workstation:
|
||||
fixed_cost += flt(frappe.db.get_value("Workstation", d.workstation, "fixed_cycle_cost"))
|
||||
self.total_fixed_cost = fixed_cost
|
||||
|
||||
|
||||
def calculate_rm_cost(self):
|
||||
"""Fetch RM rate as per today's valuation rate and calculate totals"""
|
||||
total_rm_cost = 0
|
||||
|
@ -15,6 +15,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-2 text-right">
|
||||
{%= doc.get_formatted("total_cost") %}
|
||||
{%= doc.get_formatted("total_variable_cost") %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,3 +1,3 @@
|
||||
frappe.listview_settings['BOM'] = {
|
||||
add_fields: ["is_active", "is_default", "total_cost"]
|
||||
add_fields: ["is_active", "is_default", "total_variable_cost"]
|
||||
};
|
||||
|
@ -54,10 +54,20 @@
|
||||
"is_default": 1,
|
||||
"item": "_Test FG Item",
|
||||
"quantity": 1.0
|
||||
},
|
||||
},
|
||||
{
|
||||
"bom_operations": [
|
||||
{
|
||||
"operation_no": "1",
|
||||
"opn_description": "_Test",
|
||||
"workstation": "_Test Workstation 1",
|
||||
"time_in_min": 60,
|
||||
"operating_cost": 100
|
||||
}
|
||||
],
|
||||
"bom_materials": [
|
||||
{
|
||||
"operation_no": 1,
|
||||
"amount": 5000.0,
|
||||
"doctype": "BOM Item",
|
||||
"item_code": "_Test Item",
|
||||
@ -67,6 +77,7 @@
|
||||
"stock_uom": "_Test UOM"
|
||||
},
|
||||
{
|
||||
"operation_no": 1,
|
||||
"amount": 2000.0,
|
||||
"bom_no": "BOM/_Test Item Home Desktop Manufactured/001",
|
||||
"doctype": "BOM Item",
|
||||
@ -82,6 +93,7 @@
|
||||
"is_active": 1,
|
||||
"is_default": 1,
|
||||
"item": "_Test FG Item 2",
|
||||
"quantity": 1.0
|
||||
"quantity": 1.0,
|
||||
"with_operations": 1
|
||||
}
|
||||
]
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"creation": "2013-02-22 01:27:49.000000",
|
||||
"creation": "2013-02-22 01:27:49",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"fields": [
|
||||
@ -69,13 +69,21 @@
|
||||
"oldfieldtype": "Currency",
|
||||
"permlevel": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "fixed_cycle_cost",
|
||||
"fieldtype": "Float",
|
||||
"in_list_view": 0,
|
||||
"label": "Fixed Cycle Cost",
|
||||
"permlevel": 0
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"modified": "2014-02-03 12:53:03.000000",
|
||||
"modified": "2014-09-12 12:03:47.456370",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "BOM Operation",
|
||||
"owner": "Administrator"
|
||||
"owner": "Administrator",
|
||||
"permissions": []
|
||||
}
|
@ -25,7 +25,7 @@ class BOMReplaceTool(Document):
|
||||
frappe.throw(_("Current BOM and New BOM can not be same"))
|
||||
|
||||
def update_new_bom(self):
|
||||
current_bom_unitcost = frappe.db.sql("""select total_cost/quantity
|
||||
current_bom_unitcost = frappe.db.sql("""select total_variable_cost/quantity
|
||||
from `tabBOM` where name = %s""", self.current_bom)
|
||||
current_bom_unitcost = current_bom_unitcost and flt(current_bom_unitcost[0][0]) or 0
|
||||
frappe.db.sql("""update `tabBOM Item` set bom_no=%s,
|
||||
|
@ -123,3 +123,5 @@ cur_frm.set_query("bom_no", function(doc) {
|
||||
}
|
||||
} else msgprint(__("Please enter Production Item first"));
|
||||
});
|
||||
|
||||
cur_frm.add_fetch('bom_no', 'total_fixed_cost', 'total_fixed_cost');
|
@ -101,6 +101,13 @@
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "production_item",
|
||||
"fieldname": "total_fixed_cost",
|
||||
"fieldtype": "Float",
|
||||
"label": "Total Fixed Cost",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.docstatus==1",
|
||||
"description": "Automatically updated via Stock Entry of type Manufacture/Repack",
|
||||
@ -225,7 +232,7 @@
|
||||
"idx": 1,
|
||||
"in_create": 0,
|
||||
"is_submittable": 1,
|
||||
"modified": "2014-06-23 07:55:50.092300",
|
||||
"modified": "2014-09-01 11:45:48.591196",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Production Order",
|
||||
|
@ -24,6 +24,7 @@ class ProductionOrder(Document):
|
||||
self.validate_bom_no()
|
||||
self.validate_sales_order()
|
||||
self.validate_warehouse()
|
||||
self.set_fixed_cost()
|
||||
|
||||
from erpnext.utilities.transaction_base import validate_uom_is_integer
|
||||
validate_uom_is_integer(self, "stock_uom", ["qty", "produced_qty"])
|
||||
@ -55,6 +56,10 @@ class ProductionOrder(Document):
|
||||
for w in [self.fg_warehouse, self.wip_warehouse]:
|
||||
validate_warehouse_company(w, self.company)
|
||||
|
||||
def set_fixed_cost(self):
|
||||
if self.total_fixed_cost==None:
|
||||
self.total_fixed_cost = frappe.db.get_value("BOM", self.bom_no, "total_fixed_cost")
|
||||
|
||||
def validate_production_order_against_so(self):
|
||||
# already ordered qty
|
||||
ordered_qty_against_so = frappe.db.sql("""select sum(qty) from `tabProduction Order`
|
||||
@ -156,11 +161,10 @@ def get_item_details(item):
|
||||
return {}
|
||||
|
||||
res = res[0]
|
||||
bom = frappe.db.sql("""select name from `tabBOM` where item=%s
|
||||
and ifnull(is_default, 0)=1""", item)
|
||||
bom = frappe.db.sql("""select name as bom_no,total_fixed_cost from `tabBOM` where item=%s
|
||||
and ifnull(is_default, 0)=1""", item, as_dict=1)
|
||||
if bom:
|
||||
res.bom_no = bom[0][0]
|
||||
|
||||
res.update(bom[0])
|
||||
return res
|
||||
|
||||
@frappe.whitelist()
|
||||
|
@ -54,5 +54,4 @@ class TestProductionOrder(unittest.TestCase):
|
||||
|
||||
self.assertRaises(StockOverProductionError, s.submit)
|
||||
|
||||
|
||||
test_records = frappe.get_test_records('Production Order')
|
||||
test_records = frappe.get_test_records('Production Order')
|
@ -153,7 +153,6 @@ class ProductionPlanningTool(Document):
|
||||
pi.so_pending_qty = flt(p['pending_qty'])
|
||||
pi.planned_qty = flt(p['pending_qty'])
|
||||
|
||||
|
||||
def validate_data(self):
|
||||
self.validate_company()
|
||||
for d in self.get('pp_details'):
|
||||
|
10
erpnext/manufacturing/doctype/workstation/test_records.json
Normal file
10
erpnext/manufacturing/doctype/workstation/test_records.json
Normal file
@ -0,0 +1,10 @@
|
||||
[
|
||||
{
|
||||
"doctype": "Workstation",
|
||||
"name": "_Test Workstation 1",
|
||||
"workstation_name": "_Test Workstation 1",
|
||||
"warehouse": "_Test warehouse - _TC",
|
||||
"fixed_cycle_cost": 1000,
|
||||
"hour_rate":100
|
||||
}
|
||||
]
|
@ -0,0 +1,12 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors and Contributors
|
||||
# See license.txt
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
|
||||
test_dependencies = ["Warehouse"]
|
||||
test_records = frappe.get_test_records('Workstation')
|
||||
|
||||
|
||||
class TestWorkstation(unittest.TestCase):
|
||||
pass
|
@ -61,6 +61,12 @@
|
||||
"permlevel": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "fixed_cycle_cost",
|
||||
"fieldtype": "Float",
|
||||
"label": "Fixed Cycle Cost",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "hour_rate_labour",
|
||||
"fieldtype": "Float",
|
||||
@ -132,7 +138,7 @@
|
||||
],
|
||||
"icon": "icon-wrench",
|
||||
"idx": 1,
|
||||
"modified": "2014-05-27 03:49:22.635046",
|
||||
"modified": "2014-08-30 10:59:07.960814",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Workstation",
|
||||
|
@ -80,3 +80,4 @@ execute:frappe.delete_doc("DocType", "Landed Cost Wizard")
|
||||
erpnext.patches.v4_2.default_website_style
|
||||
erpnext.patches.v4_2.set_company_country
|
||||
erpnext.patches.v4_2.update_sales_order_invoice_field_name
|
||||
erpnext.patches.v4_2.cost_of_production_cycle
|
9
erpnext/patches/v4_2/cost_of_production_cycle.py
Normal file
9
erpnext/patches/v4_2/cost_of_production_cycle.py
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("manufacturing", "doctype", "bom")
|
||||
frappe.db.sql("""update tabBOM set total_variable_cost = total_cost""")
|
@ -457,3 +457,4 @@ cur_frm.fields_dict.customer.get_query = function(doc, cdt, cdn) {
|
||||
cur_frm.fields_dict.supplier.get_query = function(doc, cdt, cdn) {
|
||||
return { query: "erpnext.controllers.queries.supplier_query" }
|
||||
}
|
||||
cur_frm.add_fetch('production_order', 'total_fixed_cost', 'total_fixed_cost');
|
@ -297,6 +297,14 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.purpose==\"Manufacture/Repack\"",
|
||||
"fieldname": "total_fixed_cost",
|
||||
"fieldtype": "Float",
|
||||
"label": "Total Fixed Cost",
|
||||
"permlevel": 0,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "cb1",
|
||||
"fieldtype": "Column Break",
|
||||
|
@ -243,7 +243,6 @@ class StockEntry(StockController):
|
||||
incoming_rate = flt(self.get_incoming_rate(args), self.precision("incoming_rate", d))
|
||||
if incoming_rate > 0:
|
||||
d.incoming_rate = incoming_rate
|
||||
|
||||
d.amount = flt(d.transfer_qty) * flt(d.incoming_rate)
|
||||
if not d.t_warehouse:
|
||||
raw_material_cost += flt(d.amount)
|
||||
@ -258,7 +257,7 @@ class StockEntry(StockController):
|
||||
if d.bom_no:
|
||||
bom = frappe.db.get_value("BOM", d.bom_no, ["operating_cost", "quantity"], as_dict=1)
|
||||
operation_cost_per_unit = flt(bom.operating_cost) / flt(bom.quantity)
|
||||
d.incoming_rate = operation_cost_per_unit + (raw_material_cost / flt(d.transfer_qty))
|
||||
d.incoming_rate = operation_cost_per_unit + (raw_material_cost + flt(self.total_fixed_cost)) / flt(d.transfer_qty)
|
||||
d.amount = flt(d.transfer_qty) * flt(d.incoming_rate)
|
||||
break
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
"cost_center": "_Test Cost Center - _TC",
|
||||
"doctype": "Stock Entry Detail",
|
||||
"expense_account": "Stock Adjustment - _TC",
|
||||
"incoming_rate": 100,
|
||||
"incoming_rate": 100,
|
||||
"item_code": "_Test Item",
|
||||
"parentfield": "mtn_details",
|
||||
"qty": 50.0,
|
||||
|
@ -10,6 +10,7 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_per
|
||||
from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import StockFreezeError
|
||||
|
||||
class TestStockEntry(unittest.TestCase):
|
||||
|
||||
def tearDown(self):
|
||||
frappe.set_user("Administrator")
|
||||
set_perpetual_inventory(0)
|
||||
@ -26,7 +27,6 @@ class TestStockEntry(unittest.TestCase):
|
||||
st1 = frappe.copy_doc(test_records[0])
|
||||
st1.insert()
|
||||
st1.submit()
|
||||
|
||||
st2 = frappe.copy_doc(test_records[1])
|
||||
st2.insert()
|
||||
st2.submit()
|
||||
@ -821,6 +821,39 @@ class TestStockEntry(unittest.TestCase):
|
||||
se = frappe.copy_doc(test_records[0]).insert()
|
||||
self.assertRaises (StockFreezeError, se.submit)
|
||||
frappe.db.set_value("Stock Settings", None, "stock_frozen_upto_days", 0)
|
||||
|
||||
def test_production_order(self):
|
||||
bom_no = frappe.db.get_value("BOM", {"item": "_Test FG Item 2",
|
||||
"is_default": 1, "docstatus": 1})
|
||||
|
||||
production_order = frappe.new_doc("Production Order")
|
||||
production_order.update({
|
||||
"company": "_Test Company",
|
||||
"fg_warehouse": "_Test Warehouse 1 - _TC",
|
||||
"production_item": "_Test FG Item 2",
|
||||
"bom_no": bom_no,
|
||||
"qty": 1.0,
|
||||
"stock_uom": "Nos",
|
||||
"wip_warehouse": "_Test Warehouse - _TC"
|
||||
})
|
||||
production_order.insert()
|
||||
production_order.submit()
|
||||
|
||||
self._insert_material_receipt()
|
||||
|
||||
stock_entry = frappe.new_doc("Stock Entry")
|
||||
stock_entry.update({
|
||||
"purpose": "Manufacture/Repack",
|
||||
"production_order": production_order.name,
|
||||
"bom_no": bom_no,
|
||||
"fg_completed_qty": "1",
|
||||
"total_fixed_cost": 1000
|
||||
})
|
||||
stock_entry.get_items()
|
||||
fg_rate = [d.amount for d in stock_entry.get("mtn_details") if d.item_code=="_Test FG Item 2"][0]
|
||||
self.assertEqual(fg_rate, 1200.00)
|
||||
fg_rate = [d.amount for d in stock_entry.get("mtn_details") if d.item_code=="_Test Item"][0]
|
||||
self.assertEqual(fg_rate, 100.00)
|
||||
|
||||
def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None):
|
||||
se = frappe.copy_doc(test_records[0])
|
||||
|
@ -114,7 +114,7 @@ def get_item_bom_rate():
|
||||
|
||||
item_bom_map = {}
|
||||
|
||||
for b in frappe.db.sql("""select item, (total_cost/quantity) as bom_rate
|
||||
for b in frappe.db.sql("""select item, (total_variable_cost/quantity) as bom_rate
|
||||
from `tabBOM` where is_active=1 and is_default=1""", as_dict=1):
|
||||
item_bom_map.setdefault(b.item, flt(b.bom_rate))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user