Merge branch 'develop'
diff --git a/erpnext/__version__.py b/erpnext/__version__.py
index c8b2f49..2c86e6c 100644
--- a/erpnext/__version__.py
+++ b/erpnext/__version__.py
@@ -1,2 +1,2 @@
from __future__ import unicode_literals
-__version__ = '5.1.3'
+__version__ = '5.1.4'
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.json b/erpnext/accounts/doctype/pos_profile/pos_profile.json
index ad224f1..0c5a4bb 100644
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.json
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.json
@@ -78,6 +78,51 @@
"reqd": 1
},
{
+ "fieldname": "warehouse",
+ "fieldtype": "Link",
+ "label": "Warehouse",
+ "oldfieldname": "warehouse",
+ "oldfieldtype": "Link",
+ "options": "Warehouse",
+ "permlevel": 0,
+ "read_only": 0,
+ "reqd": 0
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "letter_head",
+ "fieldtype": "Link",
+ "label": "Letter Head",
+ "oldfieldname": "letter_head",
+ "oldfieldtype": "Select",
+ "options": "Letter Head",
+ "permlevel": 0,
+ "print_hide": 1,
+ "read_only": 0
+ },
+ {
+ "fieldname": "tc_name",
+ "fieldtype": "Link",
+ "label": "Terms and Conditions",
+ "oldfieldname": "tc_name",
+ "oldfieldtype": "Link",
+ "options": "Terms and Conditions",
+ "permlevel": 0,
+ "read_only": 0
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "select_print_heading",
+ "fieldtype": "Link",
+ "in_filter": 0,
+ "label": "Print Heading",
+ "oldfieldname": "select_print_heading",
+ "oldfieldtype": "Select",
+ "options": "Print Heading",
+ "permlevel": 0,
+ "read_only": 0
+ },
+ {
"fieldname": "column_break0",
"fieldtype": "Column Break",
"oldfieldtype": "Column Break",
@@ -106,6 +151,14 @@
"reqd": 0
},
{
+ "fieldname": "mode_of_payment",
+ "fieldtype": "Link",
+ "label": "Mode of Payment",
+ "options": "Mode of Payment",
+ "permlevel": 0,
+ "precision": ""
+ },
+ {
"fieldname": "cash_bank_account",
"fieldtype": "Link",
"label": "Cash/Bank Account",
@@ -140,17 +193,6 @@
"reqd": 0
},
{
- "fieldname": "warehouse",
- "fieldtype": "Link",
- "label": "Warehouse",
- "oldfieldname": "warehouse",
- "oldfieldtype": "Link",
- "options": "Warehouse",
- "permlevel": 0,
- "read_only": 0,
- "reqd": 0
- },
- {
"fieldname": "cost_center",
"fieldtype": "Link",
"label": "Cost Center",
@@ -162,16 +204,6 @@
"reqd": 1
},
{
- "fieldname": "taxes_and_charges",
- "fieldtype": "Link",
- "label": "Taxes and Charges",
- "oldfieldname": "charge",
- "oldfieldtype": "Link",
- "options": "Sales Taxes and Charges Template",
- "permlevel": 0,
- "read_only": 0
- },
- {
"fieldname": "write_off_account",
"fieldtype": "Link",
"label": "Write Off Account",
@@ -190,43 +222,19 @@
"reqd": 1
},
{
- "allow_on_submit": 1,
- "fieldname": "letter_head",
+ "fieldname": "taxes_and_charges",
"fieldtype": "Link",
- "label": "Letter Head",
- "oldfieldname": "letter_head",
- "oldfieldtype": "Select",
- "options": "Letter Head",
- "permlevel": 0,
- "print_hide": 1,
- "read_only": 0
- },
- {
- "fieldname": "tc_name",
- "fieldtype": "Link",
- "label": "Terms and Conditions",
- "oldfieldname": "tc_name",
+ "label": "Taxes and Charges",
+ "oldfieldname": "charge",
"oldfieldtype": "Link",
- "options": "Terms and Conditions",
- "permlevel": 0,
- "read_only": 0
- },
- {
- "allow_on_submit": 1,
- "fieldname": "select_print_heading",
- "fieldtype": "Link",
- "in_filter": 0,
- "label": "Print Heading",
- "oldfieldname": "select_print_heading",
- "oldfieldtype": "Select",
- "options": "Print Heading",
+ "options": "Sales Taxes and Charges Template",
"permlevel": 0,
"read_only": 0
}
],
"icon": "icon-cog",
"idx": 1,
- "modified": "2015-05-20 05:38:44.482696",
+ "modified": "2015-07-07 08:56:04.381471",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 50a79ec..af144cb 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -124,20 +124,11 @@
}
})
- if cint(frappe.defaults.get_global_default('maintain_same_rate')):
- super(PurchaseInvoice, self).validate_with_previous_doc({
- "Purchase Order Item": {
- "ref_dn_field": "po_detail",
- "compare_fields": [["rate", "="]],
- "is_child_table": True,
- "allow_duplicate_prev_row_id": True
- },
- "Purchase Receipt Item": {
- "ref_dn_field": "pr_detail",
- "compare_fields": [["rate", "="]],
- "is_child_table": True
- }
- })
+ if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
+ self.validate_rate_with_reference_doc([
+ ["Purchase Order", "purchase_order", "po_detail"],
+ ["Purchase Receipt", "purchase_receipt", "pr_detail"]
+ ])
def set_against_expense_account(self):
auto_accounting_for_stock = cint(frappe.defaults.get_global_default("auto_accounting_for_stock"))
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 604370b..f3acc74 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -169,6 +169,7 @@
if pos:
if not for_validate and not self.customer:
self.customer = pos.customer
+ self.mode_of_payment = pos.mode_of_payment
# self.set_customer_defaults()
for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name',
@@ -263,20 +264,11 @@
},
})
- if cint(frappe.defaults.get_global_default('maintain_same_sales_rate')):
- super(SalesInvoice, self).validate_with_previous_doc({
- "Sales Order Item": {
- "ref_dn_field": "so_detail",
- "compare_fields": [["rate", "="]],
- "is_child_table": True,
- "allow_duplicate_prev_row_id": True
- },
- "Delivery Note Item": {
- "ref_dn_field": "dn_detail",
- "compare_fields": [["rate", "="]],
- "is_child_table": True
- }
- })
+ if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')):
+ self.validate_rate_with_reference_doc([
+ ["Sales Order", "sales_order", "so_detail"],
+ ["Delivery Note", "delivery_note", "dn_detail"]
+ ])
def set_against_income_account(self):
"""Set against account for debit to account"""
diff --git a/erpnext/change_log/v5/v5_1_4.md b/erpnext/change_log/v5/v5_1_4.md
new file mode 100644
index 0000000..c11af81
--- /dev/null
+++ b/erpnext/change_log/v5/v5_1_4.md
@@ -0,0 +1,4 @@
+- Mode of Payment added to POS Profile
+- Expired Batch is not allowed in stock entry of type manufacturing / repack
+- Validate item rate against reference document with tolerance 0.009
+- Set Customer name in opportunity as per company name in lead
\ No newline at end of file
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 4f35fea..801f6f2 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -229,9 +229,10 @@
}, { "start": start, "page_len": page_len, "txt": ("%%%s%%" % txt) })
def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
- if not filters.get("posting_date"):
- filters["posting_date"] = nowdate()
-
+ cond = ""
+ if filters.get("posting_date"):
+ cond = "and (ifnull(batch.expiry_date, '')='' or batch.expiry_date >= %(posting_date)s)"
+
batch_nos = None
args = {
'item_code': filters.get("item_code"),
@@ -251,23 +252,23 @@
and sle.warehouse = %(warehouse)s
and sle.batch_no like %(txt)s
and batch.docstatus < 2
- and (ifnull(batch.expiry_date, '')='' or batch.expiry_date >= %(posting_date)s)
+ {0}
{match_conditions}
group by batch_no having sum(sle.actual_qty) > 0
order by batch.expiry_date, sle.batch_no desc
- limit %(start)s, %(page_len)s""".format(match_conditions=get_match_cond(doctype)), args)
+ limit %(start)s, %(page_len)s""".format(cond, match_conditions=get_match_cond(doctype)), args)
if batch_nos:
return batch_nos
else:
- return frappe.db.sql("""select name, expiry_date from `tabBatch`
+ return frappe.db.sql("""select name, expiry_date from `tabBatch` batch
where item = %(item_code)s
and name like %(txt)s
and docstatus < 2
- and (ifnull(expiry_date, '')='' or expiry_date >= %(posting_date)s)
+ {0}
{match_conditions}
order by expiry_date, name desc
- limit %(start)s, %(page_len)s""".format(match_conditions=get_match_cond(doctype)), args)
+ limit %(start)s, %(page_len)s""".format(cond, match_conditions=get_match_cond(doctype)), args, debug=1)
def get_account_list(doctype, txt, searchfield, start, page_len, filters):
filter_list = []
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 0225398..78729a3 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -79,7 +79,8 @@
if self.customer:
self.customer_name = frappe.db.get_value("Customer", self.customer, "customer_name")
elif self.lead:
- self.customer_name = frappe.db.get_value("Lead", self.lead, "lead_name")
+ lead_name, company_name = frappe.db.get_value("Lead", self.lead, ["lead_name", "company_name"])
+ self.customer_name = company_name or lead_name
def get_cust_address(self,name):
details = frappe.db.sql("""select customer_name, address, territory, customer_group
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index a05e5ae..ef1afa3 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -5,7 +5,7 @@
app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations"
app_icon = "icon-th"
app_color = "#e74c3c"
-app_version = "5.1.3"
+app_version = "5.1.4"
error_report_email = "support@erpnext.com"
@@ -25,8 +25,13 @@
# website
update_website_context = "erpnext.shopping_cart.utils.update_website_context"
my_account_context = "erpnext.shopping_cart.utils.update_my_account_context"
+
email_append_to = ["Job Applicant", "Opportunity", "Issue"]
+calendars = ["Task", "Production Order", "Time Log", "Leave Application"]
+
+website_generators = ["Item Group", "Item", "Sales Partner"]
+
website_context = {
"favicon": "/assets/erpnext/images/favicon.png",
"splash_image": "/assets/erpnext/images/splash.png"
@@ -52,14 +57,10 @@
before_tests = "erpnext.setup.utils.before_tests"
-website_generators = ["Item Group", "Item", "Sales Partner"]
-
standard_queries = {
"Customer": "erpnext.selling.doctype.customer.customer.get_customer_list"
}
-communication_covert_to = ["Lead", "Issue", "Job Application"]
-
doc_events = {
"Stock Entry": {
"on_submit": "erpnext.stock.doctype.material_request.material_request.update_completed_and_requested_qty",
@@ -106,4 +107,3 @@
("page", "setup-wizard"): "frappe.geo.country_info.get_translated_dict",
("doctype", "Global Defaults"): "frappe.geo.country_info.get_translated_dict"
}
-
diff --git a/erpnext/hr/doctype/salary_manager/salary_manager.js b/erpnext/hr/doctype/salary_manager/salary_manager.js
index 240547c..ca70226 100644
--- a/erpnext/hr/doctype/salary_manager/salary_manager.js
+++ b/erpnext/hr/doctype/salary_manager/salary_manager.js
@@ -1,30 +1,44 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
-var display_activity_log = function(msg) {
+cur_frm.cscript.display_activity_log = function(msg) {
if(!cur_frm.ss_html)
cur_frm.ss_html = $a(cur_frm.fields_dict['activity_log'].wrapper,'div');
- cur_frm.ss_html.innerHTML =
- '<div class="padding"><h4>'+__("Activity Log:")+'</h4>'+msg+'</div>';
+ if(msg) {
+ cur_frm.ss_html.innerHTML =
+ '<div class="padding"><h4>'+__("Activity Log:")+'</h4>'+msg+'</div>';
+ } else {
+ cur_frm.ss_html.innerHTML = "";
+ }
}
//Create salary slip
//-----------------------
cur_frm.cscript.create_salary_slip = function(doc, cdt, cdn) {
+ cur_frm.cscript.display_activity_log("");
var callback = function(r, rt){
if (r.message)
- display_activity_log(r.message);
+ cur_frm.cscript.display_activity_log(r.message);
}
return $c('runserverobj', args={'method':'create_sal_slip','docs':doc},callback);
}
cur_frm.cscript.submit_salary_slip = function(doc, cdt, cdn) {
+ cur_frm.cscript.display_activity_log("");
var check = confirm(__("Do you really want to Submit all Salary Slip for month {0} and year {1}", [doc.month, doc.fiscal_year]));
if(check){
+ // clear all in locals
+ if(locals["Salary Slip"]) {
+ $.each(locals["Salary Slip"], function(name, d) {
+ frappe.model.remove_from_locals("Salary Slip", name);
+ });
+ }
+
var callback = function(r, rt){
if (r.message)
- display_activity_log(r.message);
+ cur_frm.cscript.display_activity_log(r.message);
}
+
return $c('runserverobj', args={'method':'submit_salary_slip','docs':doc},callback);
}
}
@@ -47,4 +61,4 @@
frappe.ui.form.on("Salary Manager", "refresh", function(frm) {
frm.disable_save();
-});
\ No newline at end of file
+});
diff --git a/erpnext/hr/doctype/salary_manager/salary_manager.py b/erpnext/hr/doctype/salary_manager/salary_manager.py
index eeb6ac0..3e0b53e 100644
--- a/erpnext/hr/doctype/salary_manager/salary_manager.py
+++ b/erpnext/hr/doctype/salary_manager/salary_manager.py
@@ -101,7 +101,7 @@
log = "<p>No employee for the above selected criteria OR salary slip already created</p>"
if ss_list:
log = "<b>Salary Slip Created For</b>\
- <br><br>%s" % '<br>'.join(ss_list)
+ <br><br>%s" % '<br>'.join(self.format_as_links(ss_list))
return log
@@ -144,7 +144,7 @@
else:
all_ss = [d[0] for d in all_ss]
- submitted_ss = list(set(all_ss) - set(not_submitted_ss))
+ submitted_ss = self.format_as_links(list(set(all_ss) - set(not_submitted_ss)))
if submitted_ss:
mail_sent_msg = self.send_email and " (Mail has been sent to the employee)" or ""
log = """
@@ -164,6 +164,9 @@
"""% ('<br>'.join(not_submitted_ss))
return log
+ def format_as_links(self, ss_list):
+ return ['<a href="#Form/Salary Slip/{0}">{0}</a>'.format(s) for s in ss_list]
+
def get_total_salary(self):
"""
diff --git a/erpnext/public/js/pos/pos.js b/erpnext/public/js/pos/pos.js
index 164e883..70f3023 100644
--- a/erpnext/public/js/pos/pos.js
+++ b/erpnext/public/js/pos/pos.js
@@ -401,7 +401,8 @@
this.with_modes_of_payment(function() {
// prefer cash payment!
- var default_mode = me.modes_of_payment.indexOf(__("Cash"))!==-1 ? __("Cash") : undefined;
+ var default_mode = me.frm.doc.mode_of_payment ? me.frm.doc.mode_of_payment :
+ me.modes_of_payment.indexOf(__("Cash"))!==-1 ? __("Cash") : undefined;
// show payment wizard
var dialog = new frappe.ui.Dialog({
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 775eb41..cd65d18 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -71,7 +71,7 @@
} else {
filters = {
'item_code': item.item_code,
- 'posting_date': me.frm.doc.posting_date,
+ 'posting_date': me.frm.doc.posting_date || nowdate(),
}
if(item.warehouse) filters["warehouse"] = item.warehouse
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index f52f7e5..90a8a6c 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -108,11 +108,9 @@
if not self.installation_status: self.installation_status = 'Not Installed'
def validate_with_previous_doc(self):
- items = self.get("items")
-
for fn in (("Sales Order", "against_sales_order", "so_detail"),
("Sales Invoice", "against_sales_invoice", "si_detail")):
- if filter(None, [getattr(d, fn[1], None) for d in items]):
+ if filter(None, [getattr(d, fn[1], None) for d in self.get("items")]):
super(DeliveryNote, self).validate_with_previous_doc({
fn[0]: {
"ref_dn_field": fn[1],
@@ -120,15 +118,10 @@
["currency", "="]],
},
})
-
- if cint(frappe.defaults.get_global_default('maintain_same_sales_rate')):
- super(DeliveryNote, self).validate_with_previous_doc({
- fn[0] + " Item": {
- "ref_dn_field": fn[2],
- "compare_fields": [["rate", "="]],
- "is_child_table": True
- }
- })
+
+ if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')):
+ self.validate_rate_with_reference_doc([["Sales Order", "sales_order", "so_detail"],
+ ["Sales Invoice", "sales_invoice", "si_detail"]])
def validate_proj_cust(self):
"""check for does customer belong to same project as entered.."""
diff --git a/erpnext/stock/doctype/manage_variants/manage_variants.py b/erpnext/stock/doctype/manage_variants/manage_variants.py
index b6784d3..4dcfb22 100644
--- a/erpnext/stock/doctype/manage_variants/manage_variants.py
+++ b/erpnext/stock/doctype/manage_variants/manage_variants.py
@@ -36,8 +36,8 @@
def get_attributes(self):
attributes = {}
self.set('attributes', [])
- for d in frappe.db.sql("""select attribute, attribute_value from `tabVariant Attribute` as attribute,
- `tabItem` as item where attribute.parent= item.name and item.variant_of = %s""", self.item_code, as_dict=1):
+ for d in frappe.db.sql("""select attr.attribute, attr.attribute_value from `tabVariant Attribute` as attr,
+ `tabItem` as item where attr.parent = item.name and item.variant_of = %s""", self.item_code, as_dict=1):
attributes.setdefault(d.attribute, []).append(d.attribute_value)
for d in attributes:
attribute_values = set(attributes[d])
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index e56cd1e..e782889 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -104,15 +104,8 @@
}
})
- if cint(frappe.defaults.get_global_default('maintain_same_rate')):
- super(PurchaseReceipt, self).validate_with_previous_doc({
- "Purchase Order Item": {
- "ref_dn_field": "prevdoc_detail_docname",
- "compare_fields": [["rate", "="]],
- "is_child_table": True
- }
- })
-
+ if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')):
+ self.validate_rate_with_reference_doc([["Purchase Order", "prevdoc_docname", "prevdoc_detail_docname"]])
def po_required(self):
if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes':
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 1135bc7..465b641 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -411,14 +411,21 @@
var item = locals[cdt][cdn];
if(!item.item_code) {
frappe.throw(__("Please enter Item Code to get batch no"));
- } else {
- var filters = {
- 'item_code': item.item_code,
- 'posting_date': me.frm.doc.posting_date,
+ }
+ else {
+ if (in_list(["Material Transfer for Manufacture", "Manufacture", "Repack", "Subcontract"], doc.purpose)) {
+ var filters = {
+ 'item_code': item.item_code,
+ 'posting_date': me.frm.doc.posting_date || nowdate()
+ }
+ } else {
+ var filters = {
+ 'item_code': item.item_code
+ }
}
+
if(item.s_warehouse) filters["warehouse"] = item.s_warehouse
-
return {
query : "erpnext.controllers.queries.get_batch_no",
filters: filters
@@ -498,9 +505,9 @@
}
cur_frm.cscript.validate = function(doc, cdt, cdn) {
- cur_frm.cscript.validate_items(doc);
if($.inArray(cur_frm.doc.purpose, ["Purchase Return", "Sales Return"])!==-1)
validated = cur_frm.cscript.get_doctype_docname() ? true : false;
+ cur_frm.cscript.validate_items(doc);
}
cur_frm.cscript.validate_items = function(doc) {
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 813a61b..93fd325 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -727,7 +727,7 @@
frappe.MappingMismatchError)
def validate_batch(self):
- if self.purpose == "Material Transfer for Manufacture":
+ if self.purpose in ["Material Transfer for Manufacture", "Manufacture", "Repack", "Subcontract"]:
for item in self.get("items"):
if item.batch_no:
if getdate(self.posting_date) > getdate(frappe.db.get_value("Batch", item.batch_no, "expiry_date")):
@@ -870,8 +870,6 @@
"account": r.get("account"),
"party_type": r.get("party_type"),
"party": r.get("party"),
- "against_invoice": r.get("against_invoice"),
- "against_voucher": r.get("against_voucher"),
"balance": get_balance_on(r.get("account"), se.posting_date) if r.get("account") else 0
})
@@ -882,8 +880,7 @@
parent = {
"account": ref.doc.debit_to,
"party_type": "Customer",
- "party": ref.doc.customer,
- "against_invoice": ref.doc.name,
+ "party": ref.doc.customer
}
# income account entries
@@ -957,9 +954,6 @@
break
- if len(invoices_against_delivery) == 1:
- parent["against_invoice"] = invoices_against_delivery[0]
-
result = [parent] + [{"account": account} for account in children]
return result
@@ -1015,9 +1009,6 @@
break
- if len(invoice_against_receipt) == 1:
- parent["against_voucher"] = invoice_against_receipt[0]
-
result = [parent] + [{"account": account} for account in children]
return result
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index be74aeb..50b0319 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe import _
-from frappe.utils import cstr, now_datetime, cint
+from frappe.utils import cstr, now_datetime, cint, flt
import frappe.share
from erpnext.controllers.status_updater import StatusUpdater
@@ -92,6 +92,17 @@
for field, condition in fields:
if prevdoc_values[field] is not None:
self.validate_value(field, condition, prevdoc_values[field], doc)
+
+
+ def validate_rate_with_reference_doc(self, ref_details):
+ for ref_dt, ref_dn_field, ref_link_field in ref_details:
+ for d in self.get("items"):
+ if d.get(ref_link_field):
+ ref_rate = frappe.db.get_value(ref_dt + " Item", d.get(ref_link_field), "rate")
+
+ if abs(flt(d.rate - ref_rate, d.precision("rate"))) >= .01:
+ frappe.throw(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) ")
+ .format(d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate))
def delete_events(ref_type, ref_name):
diff --git a/setup.py b/setup.py
index a0e3f14..7154899 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
from setuptools import setup, find_packages
-version = "5.1.3"
+version = "5.1.4"
with open("requirements.txt", "r") as f:
install_requires = f.readlines()