[Enhancement] Currency added in the BOM

This commit is contained in:
Rohit Waghchaure 2016-10-21 19:31:54 +05:30
parent d3344ebcd1
commit b1b328865e
14 changed files with 776 additions and 134 deletions

View File

@ -120,50 +120,21 @@ frappe.ui.form.on('Payment Entry', {
set_dynamic_labels: function(frm) {
var company_currency = frappe.get_doc(":Company", frm.doc.company).default_currency;
var field_label_map = {};
var grid_field_label_map = {};
var setup_field_label_map = function(fields_list, currency, parentfield) {
var doctype = parentfield ? frm.fields_dict[parentfield].grid.doctype : frm.doc.doctype;
$.each(fields_list, function(i, fname) {
var docfield = frappe.meta.docfield_map[doctype][fname];
if(docfield) {
var label = __(docfield.label || "").replace(/\([^\)]*\)/g, "");
if(parentfield) {
grid_field_label_map[doctype + "-" + fname] =
label.trim() + " (" + __(currency) + ")";
} else {
field_label_map[fname] = label.trim() + " (" + currency + ")";
}
}
});
}
setup_field_label_map(["base_paid_amount", "base_received_amount", "base_total_allocated_amount",
frm.set_currency_labels(["base_paid_amount", "base_received_amount", "base_total_allocated_amount",
"difference_amount"], company_currency);
setup_field_label_map(["paid_amount"], frm.doc.paid_from_account_currency);
setup_field_label_map(["received_amount"], frm.doc.paid_to_account_currency);
frm.set_currency_labels(["paid_amount"], frm.doc.paid_from_account_currency);
frm.set_currency_labels(["received_amount"], frm.doc.paid_to_account_currency);
var party_account_currency = frm.doc.payment_type=="Receive" ?
frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency;
setup_field_label_map(["total_allocated_amount", "unallocated_amount"], party_account_currency);
frm.set_currency_labels(["total_allocated_amount", "unallocated_amount"], party_account_currency);
$.each(field_label_map, function(fname, label) {
me.frm.fields_dict[fname].set_label(label);
});
setup_field_label_map(["total_amount", "outstanding_amount", "allocated_amount"],
frm.set_currency_labels(["total_amount", "outstanding_amount", "allocated_amount"],
party_account_currency, "references");
setup_field_label_map(["amount"], company_currency, "deductions");
$.each(grid_field_label_map, function(fname, label) {
fname = fname.split("-");
var df = frappe.meta.get_docfield(fname[0], fname[1], me.frm.doc.name);
if(df) df.label = label;
});
frm.set_currency_labels(["amount"], company_currency, "deductions");
cur_frm.set_df_property("source_exchange_rate", "description",
("1 " + frm.doc.paid_from_account_currency + " = [?] " + company_currency));

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

View File

@ -31,6 +31,11 @@ To make a new BOM:
<img class="screenshot" alt="Update Cost" src="{{docs_base_url}}/assets/img/manufacturing/bom-update-cost.png">
* User can select the currency in the BOM
* System calculates the costing based on the price list currency
<img class="screenshot" alt="Update Cost" src="{{docs_base_url}}/assets/img/manufacturing/price-list-based-currency-bom.png">
### Materials Required(exploded)
This table lists down all the Material required for the Item to be Manufactured.

View File

@ -4,9 +4,19 @@
frappe.provide("erpnext.bom");
frappe.ui.form.on("BOM", {
setup: function(frm) {
frm.add_fetch('buying_price_list', 'currency', 'currency')
frm.fields_dict["items"].grid.get_field("bom_no").get_query = function(doc, cdt, cdn){
return {
filters: {'currency': frm.doc.currency}
}
}
},
onload_post_render: function(frm) {
frm.get_field("items").grid.set_multiple_add("item_code", "qty");
},
refresh: function(frm) {
frm.toggle_enable("item", frm.doc.__islocal);
toggle_operations(frm);
@ -31,6 +41,7 @@ frappe.ui.form.on("BOM", {
});
}
},
update_cost: function(frm) {
return frappe.call({
doc: frm.doc,
@ -43,6 +54,28 @@ frappe.ui.form.on("BOM", {
}
});
erpnext.bom.BomController = erpnext.TransactionController.extend({
conversion_rate: function(doc, cdt, cdn) {
if(this.frm.doc.currency === this.get_company_currency()) {
this.frm.set_value("conversion_rate", 1.0);
} else {
erpnext.bom.update_cost(doc);
}
},
item_code: function(doc, cdt, cdn){
var scrap_items = false;
child = locals[cdt][cdn];
if(child.doctype == 'BOM Scrap Item') {
scrap_items = true;
}
get_bom_material_detail(doc, cdt, cdn, scrap_items);
},
})
$.extend(cur_frm.cscript, new erpnext.bom.BomController({frm: cur_frm}));
cur_frm.add_fetch("item", "description", "description");
cur_frm.add_fetch("item", "image", "image");
cur_frm.add_fetch("item", "item_name", "item_name");
@ -56,19 +89,15 @@ cur_frm.cscript.hour_rate = function(doc, dt, dn) {
cur_frm.cscript.time_in_mins = cur_frm.cscript.hour_rate;
cur_frm.cscript.item_code = function(doc, cdt, cdn) {
get_bom_material_detail(doc, cdt, cdn);
}
cur_frm.cscript.bom_no = function(doc, cdt, cdn) {
get_bom_material_detail(doc, cdt, cdn);
get_bom_material_detail(doc, cdt, cdn, false);
}
cur_frm.cscript.is_default = function(doc) {
if (doc.is_default) cur_frm.set_value("is_active", 1);
}
var get_bom_material_detail= function(doc, cdt, cdn) {
var get_bom_material_detail= function(doc, cdt, cdn, scrap_items) {
var d = locals[cdt][cdn];
if (d.item_code) {
return frappe.call({
@ -77,6 +106,7 @@ var get_bom_material_detail= function(doc, cdt, cdn) {
args: {
'item_code': d.item_code,
'bom_no': d.bom_no != null ? d.bom_no: '',
"scrap_items": scrap_items,
'qty': d.qty
},
callback: function(r) {
@ -96,60 +126,99 @@ 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_scrap_materials_cost(doc);
erpnext.bom.calculate_total(doc);
}
cur_frm.cscript.rate = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
var scrap_items = false;
if(child.doctype == 'BOM Scrap Item') {
scrap_items = true;
}
if (d.bom_no) {
msgprint(__("You can not change rate if BOM mentioned agianst any item"));
get_bom_material_detail(doc, cdt, cdn);
get_bom_material_detail(doc, cdt, cdn, scrap_items);
} else {
erpnext.bom.calculate_rm_cost(doc);
erpnext.bom.calculate_scrap_materials_cost(doc);
erpnext.bom.calculate_total(doc);
}
}
erpnext.bom.update_cost = function(doc) {
erpnext.bom.calculate_op_cost(doc);
erpnext.bom.calculate_rm_cost(doc);
erpnext.bom.calculate_scrap_materials_cost(doc);
erpnext.bom.calculate_total(doc);
}
erpnext.bom.calculate_op_cost = function(doc) {
var op = doc.operations || [];
doc.operating_cost = 0.0;
doc.base_operating_cost = 0.0;
for(var i=0;i<op.length;i++) {
operating_cost = flt(flt(op[i].hour_rate) * flt(op[i].time_in_mins) / 60, 2);
base_operating_cost = flt(flt(op[i].base_hour_rate) * flt(op[i].time_in_mins) / 60, 2);
frappe.model.set_value('BOM Operation',op[i].name, "operating_cost", operating_cost);
frappe.model.set_value('BOM Operation',op[i].name, "base_operating_cost", base_operating_cost);
doc.operating_cost += operating_cost;
doc.base_operating_cost += base_operating_cost;
}
refresh_field('operating_cost');
refresh_field(['operating_cost', 'base_operating_cost']);
}
// rm : raw material
erpnext.bom.calculate_rm_cost = function(doc) {
var rm = doc.items || [];
total_rm_cost = 0;
base_total_rm_cost = 0;
for(var i=0;i<rm.length;i++) {
amt = flt(rm[i].rate) * flt(rm[i].qty);
set_multiple('BOM Item',rm[i].name, {'amount': amt}, 'items');
set_multiple('BOM Item',rm[i].name,
{'qty_consumed_per_unit': flt(rm[i].qty)/flt(doc.quantity)}, 'items');
total_rm_cost += amt;
amount = flt(rm[i].rate) * flt(rm[i].qty);
base_amount = flt(rm[i].rate) * flt(doc.conversion_rate) * flt(rm[i].qty);
frappe.model.set_value('BOM Item', rm[i].name, 'base_rate', flt(rm[i].rate) * flt(doc.conversion_rate))
frappe.model.set_value('BOM Item', rm[i].name, 'amount', amount)
frappe.model.set_value('BOM Item', rm[i].name, 'qty_consumed_per_unit', flt(rm[i].qty)/flt(doc.quantity))
frappe.model.set_value('BOM Item', rm[i].name, 'base_amount', base_amount)
total_rm_cost += amount;
base_total_rm_cost += base_amount;
}
cur_frm.set_value("raw_material_cost", total_rm_cost);
cur_frm.set_value("base_raw_material_cost", base_total_rm_cost);
}
//sm : scrap material
erpnext.bom.calculate_scrap_materials_cost = function(doc) {
var sm = doc.scrap_items || [];
total_sm_cost = 0;
base_total_sm_cost = 0;
for(var i=0;i<sm.length;i++) {
amt = flt(sm[i].rate) * flt(sm[i].qty);
set_multiple('BOM Scrap Item',sm[i].name, {'amount': amt}, 'scrap_items');
base_rate = flt(sm[i].rate) * flt(doc.conversion_rate);
amount = flt(sm[i].rate) * flt(sm[i].qty);
base_amount = flt(sm[i].rate) * flt(sm[i].qty) * flt(doc.conversion_rate);
frappe.model.set_value('BOM Scrap Item',sm[i].name, 'base_rate', base_rate);
frappe.model.set_value('BOM Scrap Item',sm[i].name, 'amount', amount);
frappe.model.set_value('BOM Scrap Item',sm[i].name, 'base_amount', base_amount);
total_sm_cost += amount;
base_total_sm_cost += base_amount;
}
cur_frm.set_value("scrap_material_cost", total_sm_cost);
cur_frm.set_value("base_scrap_material_cost", base_total_sm_cost);
}
// Calculate Total Cost
erpnext.bom.calculate_total = function(doc) {
total_cost = flt(doc.operating_cost) + flt(doc.raw_material_cost);
frappe.model.set_value(doc.doctype, doc.name, "total_cost", total_cost);
total_cost = flt(doc.operating_cost) + flt(doc.raw_material_cost) - flt(doc.scrap_material_cost);
base_total_cost = flt(doc.base_operating_cost) + flt(doc.base_raw_material_cost) - flt(doc.base_scrap_material_cost);
cur_frm.set_value("total_cost", total_cost);
cur_frm.set_value("base_total_cost", base_total_cost);
}
@ -186,10 +255,7 @@ cur_frm.fields_dict['items'].grid.get_field('bom_no').get_query = function(doc,
}
cur_frm.cscript.validate = function(doc, dt, dn) {
erpnext.bom.calculate_op_cost(doc);
erpnext.bom.calculate_rm_cost(doc);
erpnext.bom.calculate_scrap_materials_cost(doc);
erpnext.bom.calculate_total(doc);
erpnext.bom.update_cost(doc)
}
frappe.ui.form.on("BOM Operation", "operation", function(frm, cdt, cdn) {
@ -225,6 +291,7 @@ frappe.ui.form.on("BOM Operation", "workstation", function(frm, cdt, cdn) {
},
callback: function (data) {
frappe.model.set_value(d.doctype, d.name, "hour_rate", data.message.hour_rate);
frappe.model.set_value(d.doctype, d.name, "base_hour_rate", flt(data.message.hour_rate) * flt(frm.doc.conversion_rate));
erpnext.bom.calculate_op_cost(frm.doc);
erpnext.bom.calculate_total(frm.doc);
}
@ -252,7 +319,6 @@ frappe.ui.form.on("BOM", "with_operations", function(frm) {
toggle_operations(frm);
});
cur_frm.cscript.image = function() {
refresh_field("image_view");
}

View File

@ -271,6 +271,118 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "currency_detail",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "currency",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Currency",
"length": 0,
"no_copy": 0,
"options": "Currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_12",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "conversion_rate",
"fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Conversion Rate",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "9",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -490,7 +602,7 @@
"label": "Operating Cost",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"options": "currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@ -518,7 +630,7 @@
"label": "Raw Material Cost",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"options": "currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@ -530,6 +642,35 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "scrap_material_cost",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Scrap Material Cost",
"length": 0,
"no_copy": 0,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -556,6 +697,120 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "base_operating_cost",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Operating Cost (Company Currency)",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "base_raw_material_cost",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Raw Material Cost(Company Currency)",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "base_scrap_material_cost",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Scrap Material Cost(Company Currency)",
"length": 0,
"no_copy": 1,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "total_cost_of_bom",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -572,7 +827,7 @@
"label": "Total Cost",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"options": "currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@ -584,6 +839,62 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "column_break_26",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "base_total_cost",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Total Cost(Company Currency)",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -960,12 +1271,33 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2016-11-07 05:13:12.904755",
"modified_by": "Administrator",
"modified": "2016-11-21 17:06:49.349654",
"modified_by": "rohit@erpnext.com",
"module": "Manufacturing",
"name": "BOM",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"is_custom": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "All",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"apply_user_permissions": 0,
@ -1016,4 +1348,4 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
}
}

View File

@ -5,6 +5,7 @@ from __future__ import unicode_literals
import frappe
from frappe.utils import cint, cstr, flt
from frappe import _
from erpnext.setup.utils import get_exchange_rate
from frappe.model.document import Document
from operator import itemgetter
@ -35,6 +36,8 @@ class BOM(Document):
def validate(self):
self.clear_operations()
self.validate_main_item()
self.validate_currency()
self.set_conversion_rate()
from erpnext.utilities.transaction_base import validate_uom_is_integer
validate_uom_is_integer(self, "stock_uom", "qty", "BOM Item")
@ -84,6 +87,8 @@ class BOM(Document):
for r in ret:
if not item.get(r):
item.set(r, ret[r])
self.validate_bom_currecny(item)
def get_bom_material_detail(self, args=None):
""" Get raw material details like uom, desc and rate"""
@ -102,19 +107,27 @@ class BOM(Document):
rate = self.get_rm_rate(args)
ret_item = {
'item_name' : item and args['item_name'] or '',
'description' : item and args['description'] or '',
'image' : item and args['image'] or '',
'stock_uom' : item and args['stock_uom'] or '',
'bom_no' : args['bom_no'],
'rate' : rate
'item_name' : item and args['item_name'] or '',
'description' : item and args['description'] or '',
'image' : item and args['image'] or '',
'stock_uom' : item and args['stock_uom'] or '',
'bom_no' : args['bom_no'],
'rate' : rate,
'base_rate' : rate if self.company_currency() == self.currency else rate * self.conversion_rate
}
return ret_item
def validate_bom_currecny(self, item):
if item.get('bom_no') and frappe.db.get_value('BOM', item.get('bom_no'), 'currency') != self.currency:
frappe.throw(_("Row {0}: Currency of the BOM #{1} should be equal to the selected currency {2}").format(item.idx, item.bom_no, self.currency))
def get_rm_rate(self, arg):
""" Get raw material rate as per selected method, if bom exists takes bom cost """
rate = 0
if arg['bom_no']:
if arg.get('scrap_items'):
rate = self.get_valuation_rate(arg)
elif arg['bom_no']:
rate = self.get_bom_unitcost(arg['bom_no'])
elif arg:
if self.rm_cost_as_per == 'Valuation Rate':
@ -209,6 +222,14 @@ class BOM(Document):
if not self.quantity:
frappe.throw(_("Quantity should be greater than 0"))
def validate_currency(self):
if self.rm_cost_as_per == 'Price List' and \
frappe.db.get_value('Price List', self.buying_price_list, 'currency') != self.currency:
frappe.throw(_("Currency of the price list {0} is not similar with the selected currency {1}").format(self.buying_price_list, self.currency))
def set_conversion_rate(self):
self.conversion_rate = get_exchange_rate(self.currency, self.company_currency())
def validate_materials(self):
""" Validate raw material entries """
@ -270,11 +291,14 @@ class BOM(Document):
"""Calculate bom totals"""
self.calculate_op_cost()
self.calculate_rm_cost()
self.total_cost = self.operating_cost + self.raw_material_cost
self.calculate_sm_cost()
self.total_cost = self.operating_cost + self.raw_material_cost - self.scrap_material_cost
self.base_total_cost = self.base_operating_cost + self.base_raw_material_cost - self.base_scrap_material_cost
def calculate_op_cost(self):
"""Update workstation rate and calculates totals"""
self.operating_cost = 0
self.base_operating_cost = 0
for d in self.get('operations'):
if d.workstation:
if not d.hour_rate:
@ -282,20 +306,45 @@ class BOM(Document):
if d.hour_rate and d.time_in_mins:
d.operating_cost = flt(d.hour_rate) * flt(d.time_in_mins) / 60.0
d.base_hour_rate = flt(d.hour_rate) * flt(self.conversion_rate)
d.base_operating_cost = flt(d.base_hour_rate) * flt(d.time_in_mins) / 60.0
self.operating_cost += flt(d.operating_cost)
self.base_operating_cost += flt(d.base_operating_cost)
def calculate_rm_cost(self):
"""Fetch RM rate as per today's valuation rate and calculate totals"""
total_rm_cost = 0
base_total_rm_cost = 0
for d in self.get('items'):
if d.bom_no:
d.rate = self.get_bom_unitcost(d.bom_no)
d.base_rate = d.rate * self.conversion_rate
d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.qty, self.precision("qty", d))
d.base_amount = d.amount * self.conversion_rate
d.qty_consumed_per_unit = flt(d.qty, self.precision("qty", d)) / flt(self.quantity, self.precision("quantity"))
total_rm_cost += d.amount
base_total_rm_cost += d.base_amount
self.raw_material_cost = total_rm_cost
self.base_raw_material_cost = base_total_rm_cost
def calculate_sm_cost(self):
"""Fetch RM rate as per today's valuation rate and calculate totals"""
total_sm_cost = 0
base_total_sm_cost = 0
for d in self.get('scrap_items'):
d.base_rate = d.rate * self.conversion_rate
d.amount = flt(d.rate, self.precision("rate", d)) * flt(d.qty, self.precision("qty", d))
d.base_amount = d.amount * self.conversion_rate
total_sm_cost += d.amount
base_total_sm_cost += d.base_amount
self.scrap_material_cost = total_sm_cost
self.base_scrap_material_cost = base_total_sm_cost
def update_exploded_items(self):
""" Update Flat BOM, following will be correct data"""
@ -316,8 +365,11 @@ class BOM(Document):
'image' : d.image,
'stock_uom' : d.stock_uom,
'qty' : flt(d.qty),
'rate' : flt(d.rate),
'rate' : d.base_rate,
}))
def company_currency(self):
return frappe.db.get_value('Company', self.company, 'default_currency')
def add_to_cur_exploded_items(self, args):
if self.cur_exploded_items.get(args.item_code):

View File

@ -22,6 +22,7 @@
],
"docstatus": 1,
"doctype": "BOM",
"currency": "USD",
"is_active": 1,
"is_default": 1,
"item": "_Test Item Home Desktop Manufactured",
@ -63,6 +64,7 @@
"doctype": "BOM",
"is_active": 1,
"is_default": 1,
"currency": "USD",
"item": "_Test FG Item",
"quantity": 1.0
},
@ -101,6 +103,7 @@
"doctype": "BOM",
"is_active": 1,
"is_default": 1,
"currency": "USD",
"item": "_Test FG Item 2",
"quantity": 1.0,
"with_operations": 1
@ -130,6 +133,7 @@
"doctype": "BOM",
"is_active": 1,
"is_default": 1,
"currency": "USD",
"item": "_Test Variant Item",
"quantity": 1.0,
"with_operations": 1

View File

@ -7,6 +7,7 @@
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 1,
"fields": [
{
@ -317,7 +318,7 @@
"label": "Rate",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"options": "currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@ -328,6 +329,36 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Amount",
"length": 0,
"no_copy": 0,
"oldfieldname": "amount_as_per_mar",
"oldfieldtype": "Currency",
"options": "currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"width": "150px"
},
{
"allow_on_submit": 0,
"bold": 0,
@ -385,30 +416,79 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amount",
"fieldname": "base_rate",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 1,
"label": "Amount",
"in_list_view": 0,
"label": "Basic Rate (Company Currency)",
"length": 0,
"no_copy": 0,
"oldfieldname": "amount_as_per_mar",
"oldfieldtype": "Currency",
"options": "Company:company:default_currency",
"permlevel": 0,
"print_hide": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"print_width": "150px",
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0,
"width": "150px"
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "base_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Amount (Company Currency)",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "section_break_18",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
@ -475,7 +555,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-08-26 02:42:40.468812",
"modified": "2016-10-21 15:57:22.521537",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Item",

View File

@ -9,11 +9,13 @@
"doctype": "DocType",
"document_type": "Setup",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "operation",
"fieldtype": "Link",
"hidden": 0,
@ -41,6 +43,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "workstation",
"fieldtype": "Link",
"hidden": 0,
@ -68,6 +71,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "description",
"fieldtype": "Text Editor",
"hidden": 0,
@ -94,6 +98,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "col_break1",
"fieldtype": "Column Break",
"hidden": 0,
@ -117,8 +122,9 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "hour_rate",
"fieldtype": "Float",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@ -129,6 +135,7 @@
"no_copy": 0,
"oldfieldname": "hour_rate",
"oldfieldtype": "Currency",
"options": "currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@ -143,6 +150,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"description": "In minutes",
"fieldname": "time_in_mins",
"fieldtype": "Float",
@ -171,6 +179,7 @@
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "operating_cost",
"fieldtype": "Currency",
"hidden": 0,
@ -183,6 +192,7 @@
"no_copy": 0,
"oldfieldname": "operating_cost",
"oldfieldtype": "Currency",
"options": "currency",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
@ -192,6 +202,61 @@
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "base_hour_rate",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Base Hour Rate(Company Currency)",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "5",
"fieldname": "base_operating_cost",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Operating Cost(Company Currency)",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
}
],
"hide_heading": 0,
@ -204,7 +269,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-07-11 03:27:58.625909",
"modified": "2016-10-21 18:38:14.700637",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Operation",

View File

@ -130,7 +130,7 @@
"label": "Rate",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@ -142,6 +142,33 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Amount",
"length": 0,
"no_copy": 0,
"options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -199,20 +226,47 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "amount",
"fieldname": "base_rate",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Amount",
"label": "Basic Rate (Company Currency)",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "base_amount",
"fieldtype": "Currency",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Basic Amount (Company Currency)",
"length": 0,
"no_copy": 0,
"options": "Company:company:default_currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
"print_hide_if_no_value": 0,
"read_only": 1,
"report_hide": 0,
@ -232,7 +286,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-09-26 02:58:58.433348",
"modified": "2016-10-25 00:27:53.712140",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Scrap Item",

View File

@ -217,7 +217,7 @@ class ProductionOrder(Document):
return
self.set('operations', [])
operations = frappe.db.sql("""select operation, description, workstation, idx,
hour_rate, time_in_mins, "Pending" as status from `tabBOM Operation`
base_hour_rate as hour_rate, time_in_mins, "Pending" as status from `tabBOM Operation`
where parent = %s order by idx""", self.bom_no, as_dict=1)
self.set('operations', operations)
self.calculate_time()

View File

@ -352,3 +352,5 @@ erpnext.patches.v7_0.po_status_issue_for_pr_return
erpnext.patches.v7_1.update_missing_salary_component_type
erpnext.patches.v7_1.rename_quality_inspection_field
erpnext.patches.v7_0.update_autoname_field
erpnext.patches.v7_1.repost_gle_for_pi_with_update_stock
erpnext.patches.v7_1.update_bom_base_currency

View File

@ -0,0 +1,19 @@
import frappe
from erpnext import get_default_currency
def execute():
frappe.reload_doc("manufacturing", "doctype", "bom")
frappe.reload_doc("manufacturing", "doctype", "bom_item")
frappe.reload_doc("manufacturing", "doctype", "bom_explosion_item")
frappe.reload_doc("manufacturing", "doctype", "bom_operation")
frappe.reload_doc("manufacturing", "doctype", "bom_scrap_item")
frappe.db.sql(""" update `tabBOM Operation` set base_hour_rate = hour_rate,
base_operating_cost = operating_cost """)
frappe.db.sql(""" update `tabBOM Item` set base_rate = rate, base_amount = amount """)
frappe.db.sql(""" update `tabBOM Scrap Item` set base_rate = rate, base_amount = amount """)
frappe.db.sql(""" update `tabBOM` set `tabBOM`.base_operating_cost = `tabBOM`.operating_cost,
`tabBOM`.base_raw_material_cost = `tabBOM`.raw_material_cost,
`tabBOM`.currency = (select default_currency from `tabCompany` where name = `tabBOM`.company)""")

View File

@ -550,28 +550,20 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
change_form_labels: function(company_currency) {
var me = this;
var field_label_map = {};
var setup_field_label_map = function(fields_list, currency) {
$.each(fields_list, function(i, fname) {
var docfield = frappe.meta.docfield_map[me.frm.doc.doctype][fname];
if(docfield) {
var label = __(docfield.label || "").replace(/\([^\)]*\)/g, "");
field_label_map[fname] = label.trim() + " (" + currency + ")";
}
});
};
setup_field_label_map(["base_total", "base_net_total", "base_total_taxes_and_charges",
this.frm.set_currency_labels(["base_total", "base_net_total", "base_total_taxes_and_charges",
"base_discount_amount", "base_grand_total", "base_rounded_total", "base_in_words",
"base_taxes_and_charges_added", "base_taxes_and_charges_deducted", "total_amount_to_pay",
"base_paid_amount", "base_write_off_amount", "base_change_amount"
"base_paid_amount", "base_write_off_amount", "base_change_amount", "base_operating_cost",
"base_raw_material_cost", "base_total_cost", "base_scrap_material_cost"
], company_currency);
setup_field_label_map(["total", "net_total", "total_taxes_and_charges", "discount_amount",
this.frm.set_currency_labels(["total", "net_total", "total_taxes_and_charges", "discount_amount",
"grand_total", "taxes_and_charges_added", "taxes_and_charges_deducted",
"rounded_total", "in_words", "paid_amount", "write_off_amount"], this.frm.doc.currency);
"rounded_total", "in_words", "paid_amount", "write_off_amount", "operating_cost", "scrap_material_cost",
"raw_material_cost", "total_cost"], this.frm.doc.currency);
setup_field_label_map(["outstanding_amount", "total_advance"], this.frm.doc.party_account_currency);
this.frm.set_currency_labels(["outstanding_amount", "total_advance"], this.frm.doc.party_account_currency);
cur_frm.set_df_property("conversion_rate", "description", "1 " + this.frm.doc.currency
+ " = [?] " + company_currency)
@ -585,17 +577,13 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
this.frm.toggle_display(["conversion_rate", "base_total", "base_net_total", "base_total_taxes_and_charges",
"base_taxes_and_charges_added", "base_taxes_and_charges_deducted",
"base_grand_total", "base_rounded_total", "base_in_words", "base_discount_amount",
"base_paid_amount", "base_write_off_amount"],
"base_paid_amount", "base_write_off_amount", "base_operating_cost",
"base_raw_material_cost", "base_total_cost", "base_scrap_material_cost"],
this.frm.doc.currency != company_currency);
this.frm.toggle_display(["plc_conversion_rate", "price_list_currency"],
this.frm.doc.price_list_currency != company_currency);
// set labels
$.each(field_label_map, function(fname, label) {
me.frm.fields_dict[fname].set_label(label);
});
var show =cint(cur_frm.doc.discount_amount) ||
((cur_frm.doc.taxes || []).filter(function(d) {return d.included_in_print_rate===1}).length);
@ -609,34 +597,43 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
change_grid_labels: function(company_currency) {
var me = this;
var field_label_map = {};
var setup_field_label_map = function(fields_list, currency, parentfield) {
var grid_doctype = me.frm.fields_dict[parentfield].grid.doctype;
$.each(fields_list, function(i, fname) {
var docfield = frappe.meta.docfield_map[grid_doctype][fname];
if(docfield) {
var label = __(docfield.label || "").replace(/\([^\)]*\)/g, "");
field_label_map[grid_doctype + "-" + fname] =
label.trim() + " (" + __(currency) + ")";
}
this.frm.set_currency_labels(["base_rate", "base_net_rate", "base_price_list_rate", "base_amount", "base_net_amount"],
company_currency, "items");
this.frm.set_currency_labels(["rate", "net_rate", "price_list_rate", "amount", "net_amount"],
this.frm.doc.currency, "items");
if(this.frm.fields_dict["operations"]) {
this.frm.set_currency_labels(["operating_cost", "hour_rate"], this.frm.doc.currency, "operations");
this.frm.set_currency_labels(["base_operating_cost", "base_hour_rate"], company_currency, "operations");
var item_grid = this.frm.fields_dict["operations"].grid;
$.each(["base_operating_cost", "base_hour_rate"], function(i, fname) {
if(frappe.meta.get_docfield(item_grid.doctype, fname))
item_grid.set_column_disp(fname, me.frm.doc.currency != company_currency);
});
}
setup_field_label_map(["base_rate", "base_net_rate", "base_price_list_rate", "base_amount", "base_net_amount"],
company_currency, "items");
if(this.frm.fields_dict["scrap_items"]) {
this.frm.set_currency_labels(["rate", "amount"], this.frm.doc.currency, "scrap_items");
this.frm.set_currency_labels(["base_rate", "base_amount"], company_currency, "scrap_items");
setup_field_label_map(["rate", "net_rate", "price_list_rate", "amount", "net_amount"],
this.frm.doc.currency, "items");
var item_grid = this.frm.fields_dict["scrap_items"].grid;
$.each(["base_rate", "base_amount"], function(i, fname) {
if(frappe.meta.get_docfield(item_grid.doctype, fname))
item_grid.set_column_disp(fname, me.frm.doc.currency != company_currency);
});
}
if(this.frm.fields_dict["taxes"]) {
setup_field_label_map(["tax_amount", "total", "tax_amount_after_discount"], this.frm.doc.currency, "taxes");
this.frm.set_currency_labels(["tax_amount", "total", "tax_amount_after_discount"], this.frm.doc.currency, "taxes");
setup_field_label_map(["base_tax_amount", "base_total", "base_tax_amount_after_discount"], company_currency, "taxes");
this.frm.set_currency_labels(["base_tax_amount", "base_total", "base_tax_amount_after_discount"], company_currency, "taxes");
}
if(this.frm.fields_dict["advances"]) {
setup_field_label_map(["advance_amount", "allocated_amount"],
this.frm.set_currency_labels(["advance_amount", "allocated_amount"],
this.frm.doc.party_account_currency, "advances");
}
@ -662,11 +659,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
// set labels
var $wrapper = $(this.frm.wrapper);
$.each(field_label_map, function(fname, label) {
fname = fname.split("-");
var df = frappe.meta.get_docfield(fname[0], fname[1], me.frm.doc.name);
if(df) df.label = label;
});
},
recalculate: function() {