fix: bom incorrect price list rate for raw material if price list currency is different from company currency (#21585)

* fix: bom incorrect price list rate for raw material if price list currency is different from company currency

* fixed test cases

* fixed base_rate calculation and added plc_conversion_rate trigger
This commit is contained in:
rohitwaghchaure 2020-05-18 14:23:30 +05:30 committed by GitHub
parent 1e7bc3a97e
commit be750096ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 105 additions and 20 deletions

View File

@ -212,6 +212,12 @@ frappe.ui.form.on("BOM", {
});
},
rm_cost_as_per: function(frm) {
if (in_list(["Valuation Rate", "Last Purchase Rate"], frm.doc.rm_cost_as_per)) {
frm.set_value("plc_conversion_rate", 1.0);
}
},
routing: function(frm) {
if (frm.doc.routing) {
frappe.call({
@ -242,7 +248,7 @@ erpnext.bom.BomController = erpnext.TransactionController.extend({
item_code: function(doc, cdt, cdn){
var scrap_items = false;
var child = locals[cdt][cdn];
if(child.doctype == 'BOM Scrap Item') {
if (child.doctype == 'BOM Scrap Item') {
scrap_items = true;
}
@ -252,8 +258,19 @@ erpnext.bom.BomController = erpnext.TransactionController.extend({
get_bom_material_detail(doc, cdt, cdn, scrap_items);
},
buying_price_list: function(doc) {
this.apply_price_list();
},
plc_conversion_rate: function(doc) {
if (!this.in_apply_price_list) {
this.apply_price_list();
}
},
conversion_factor: function(doc, cdt, cdn) {
if(frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
if (frappe.meta.get_docfield(cdt, "stock_qty", cdn)) {
var item = frappe.get_doc(cdt, cdn);
frappe.model.round_floats_in(item, ["qty", "conversion_factor"]);
item.stock_qty = flt(item.qty * item.conversion_factor, precision("stock_qty", item));

View File

@ -1,4 +1,5 @@
{
"actions": [],
"allow_import": 1,
"creation": "2013-01-22 15:11:38",
"doctype": "DocType",
@ -6,23 +7,25 @@
"engine": "InnoDB",
"field_order": [
"item",
"quantity",
"set_rate_of_sub_assembly_item_based_on_bom",
"company",
"item_name",
"uom",
"cb0",
"is_active",
"is_default",
"allow_alternative_item",
"image",
"item_name",
"uom",
"currency_detail",
"company",
"set_rate_of_sub_assembly_item_based_on_bom",
"project",
"quantity",
"image",
"currency_detail",
"currency",
"conversion_rate",
"column_break_12",
"currency",
"rm_cost_as_per",
"buying_price_list",
"price_list_currency",
"plc_conversion_rate",
"section_break_21",
"with_operations",
"column_break_23",
@ -176,7 +179,8 @@
},
{
"fieldname": "currency_detail",
"fieldtype": "Section Break"
"fieldtype": "Section Break",
"label": "Currency and Price List"
},
{
"fieldname": "company",
@ -324,7 +328,7 @@
},
{
"fieldname": "base_scrap_material_cost",
"fieldtype": "Data",
"fieldtype": "Currency",
"label": "Scrap Material Cost(Company Currency)",
"no_copy": 1,
"options": "Company:company:default_currency",
@ -477,13 +481,31 @@
{
"fieldname": "column_break_52",
"fieldtype": "Column Break"
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.rm_cost_as_per=='Price List'",
"fieldname": "plc_conversion_rate",
"fieldtype": "Float",
"label": "Price List Exchange Rate"
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.rm_cost_as_per=='Price List'",
"fieldname": "price_list_currency",
"fieldtype": "Link",
"label": "Price List Currency",
"options": "Currency",
"print_hide": 1,
"read_only": 1
}
],
"icon": "fa fa-sitemap",
"idx": 1,
"image_field": "image",
"is_submittable": 1,
"modified": "2019-11-22 14:35:12.142150",
"links": [],
"modified": "2020-05-05 14:29:32.634952",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM",

View File

@ -70,11 +70,13 @@ class BOM(WebsiteGenerator):
self.validate_main_item()
self.validate_currency()
self.set_conversion_rate()
self.set_plc_conversion_rate()
self.validate_uom_is_interger()
self.set_bom_material_details()
self.validate_materials()
self.validate_operations()
self.calculate_cost()
self.update_cost(update_parent=False, from_child_bom=True, save=False)
def get_context(self, context):
context.parents = [{'name': 'boms', 'title': _('All BOMs') }]
@ -165,7 +167,7 @@ class BOM(WebsiteGenerator):
'rate' : rate,
'qty' : args.get("qty") or args.get("stock_qty") or 1,
'stock_qty' : args.get("qty") or args.get("stock_qty") or 1,
'base_rate' : rate,
'base_rate' : flt(rate) * (flt(self.conversion_rate) or 1),
'include_item_in_manufacturing': cint(args['transfer_for_manufacture']) or 0
}
@ -226,7 +228,7 @@ class BOM(WebsiteGenerator):
frappe.msgprint(_("{0} not found for item {1}")
.format(self.rm_cost_as_per, arg["item_code"]), alert=True)
return flt(rate) / (self.conversion_rate or 1)
return flt(rate) * flt(self.plc_conversion_rate or 1) / (self.conversion_rate or 1)
def update_cost(self, update_parent=True, from_child_bom=False, save=True):
if self.docstatus == 2:
@ -243,10 +245,15 @@ class BOM(WebsiteGenerator):
"stock_uom": d.stock_uom,
"conversion_factor": d.conversion_factor
})
if rate:
d.rate = rate
d.amount = flt(d.rate) * flt(d.qty)
d.db_update()
d.base_rate = flt(d.rate) * flt(self.conversion_rate)
d.base_amount = flt(d.amount) * flt(self.conversion_rate)
if save:
d.db_update()
if self.docstatus == 1:
self.flags.ignore_validate_update_after_submit = True
@ -372,6 +379,13 @@ class BOM(WebsiteGenerator):
elif self.conversion_rate == 1 or flt(self.conversion_rate) <= 0:
self.conversion_rate = get_exchange_rate(self.currency, self.company_currency(), args="for_buying")
def set_plc_conversion_rate(self):
if self.rm_cost_as_per in ["Valuation Rate", "Last Purchase Rate"]:
self.plc_conversion_rate = 1
elif not self.plc_conversion_rate and self.price_list_currency:
self.plc_conversion_rate = get_exchange_rate(self.price_list_currency,
self.company_currency(), args="for_buying")
def validate_materials(self):
""" Validate raw material entries """

View File

@ -81,13 +81,13 @@ class TestBOM(unittest.TestCase):
# test amounts in selected currency
self.assertEqual(bom.operating_cost, 100)
self.assertEqual(bom.raw_material_cost, 8000)
self.assertEqual(bom.total_cost, 8100)
self.assertEqual(bom.raw_material_cost, 351.68)
self.assertEqual(bom.total_cost, 451.68)
# test amounts in selected currency
self.assertEqual(bom.base_operating_cost, 6000)
self.assertEqual(bom.base_raw_material_cost, 480000)
self.assertEqual(bom.base_total_cost, 486000)
self.assertEqual(bom.base_raw_material_cost, 21100.80)
self.assertEqual(bom.base_total_cost, 27100.80)
def test_bom_cost_multi_uom_multi_currency_based_on_price_list(self):
frappe.db.set_value("Price List", "_Test Price List", "price_not_uom_dependent", 1)

View File

@ -685,3 +685,4 @@ execute:frappe.rename_doc("Desk Page", "Getting Started", "Home", force=True)
erpnext.patches.v12_0.unset_customer_supplier_based_on_type_of_item_price
erpnext.patches.v12_0.set_valid_till_date_in_supplier_quotation
erpnext.patches.v12_0.set_serial_no_status
erpnext.patches.v12_0.update_price_list_currency_in_bom

View File

@ -0,0 +1,31 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import getdate, flt
from erpnext.setup.utils import get_exchange_rate
def execute():
frappe.reload_doc("manufacturing", "doctype", "bom")
frappe.reload_doc("manufacturing", "doctype", "bom_item")
frappe.db.sql(""" UPDATE `tabBOM`, `tabPrice List`
SET
`tabBOM`.price_list_currency = `tabPrice List`.currency,
`tabBOM`.plc_conversion_rate = 1.0
WHERE
`tabBOM`.buying_price_list = `tabPrice List`.name AND `tabBOM`.docstatus < 2
AND `tabBOM`.rm_cost_as_per = 'Price List'
""")
for d in frappe.db.sql("""
SELECT
bom.creation, bom.name, bom.price_list_currency as currency,
company.default_currency as company_currency
FROM
`tabBOM` as bom, `tabCompany` as company
WHERE
bom.company = company.name AND bom.rm_cost_as_per = 'Price List' AND
bom.price_list_currency != company.default_currency AND bom.docstatus < 2""", as_dict=1):
plc_conversion_rate = get_exchange_rate(d.currency,
d.company_currency, getdate(d.creation), "for_buying")
frappe.db.set_value("BOM", d.name, "plc_conversion_rate", plc_conversion_rate)