Currency validation in gl entry
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 46f7520..a57cc25 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -28,6 +28,7 @@
self.validate_warehouse_account()
self.validate_frozen_accounts_modifier()
self.validate_balance_must_be_debit_or_credit()
+ self.validate_account_currency()
def validate_parent(self):
"""Fetch Parent Details and validate parent account"""
@@ -86,6 +87,14 @@
frappe.throw(_("Account balance already in Debit, you are not allowed to set 'Balance Must Be' as 'Credit'"))
elif account_balance < 0 and self.balance_must_be == "Debit":
frappe.throw(_("Account balance already in Credit, you are not allowed to set 'Balance Must Be' as 'Debit'"))
+
+ def validate_account_currency(self):
+ if not self.currency:
+ self.currency = frappe.db.get_value("Company", self.company, "default_currency")
+
+ elif self.currency != frappe.db.get_value("Account", self.name, "currency"):
+ if frappe.db.get_value("GL Entry", {"account": self.name}):
+ frappe.throw(_("Currency can not be changed after making entries using some other currency"))
def convert_group_to_ledger(self):
if self.check_if_child_exists():
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 43c4213..075abd7 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -20,6 +20,7 @@
self.check_pl_account()
self.validate_cost_center()
self.validate_party()
+ self.validate_currency()
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
self.validate_account_details(adv_adj)
@@ -98,6 +99,31 @@
if not frozen_accounts_modifier in frappe.get_roles():
if frappe.db.get_value(self.party_type, self.party, "is_frozen"):
frappe.throw("{0} {1} is frozen".format(self.party_type, self.party), CustomerFrozen)
+
+ def validate_currency(self):
+ company_currency = frappe.db.get_value("Company", self.company, "default_currency")
+ account_currency = frappe.db.get_value("Account", self.account, "currency") or company_currency
+
+ if not self.currency:
+ self.currency = company_currency
+
+ if account_currency != self.currency:
+ frappe.throw(_("Accounting Entry for {0} can only be made in currency: {1}")
+ .format(self.account, (account_currency or company_currency)))
+
+ if self.party_type and self.party:
+ existing_gle = frappe.db.get_value("GL Entry",
+ {"party_type": self.party_type, "party": self.party}, ["name", "currency"])
+ if not existing_gle:
+ party_currency = frappe.db.get_value(self.party_type, self.party, "currency") or company_currency
+ if party_currency != account_currency:
+ frappe.throw(_("Invalid Account {0}. Account Currency must be {1}, same as {2}: {3}")
+ .format(self.account, party_currency, self.party_type, self.party))
+ else:
+ currency_in_existing_entries = existing_gle.currency or company_currency
+ if currency_in_existing_entries != self.currency:
+ frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}")
+ .format(self.party_type, self.party, currency_in_existing_entries))
def validate_balance_type(account, adv_adj=False):
if not adv_adj and account:
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 250286c..be672cc 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -7,7 +7,7 @@
import datetime
from frappe import _, msgprint, scrub
from frappe.defaults import get_user_permissions
-from frappe.utils import add_days, getdate, formatdate, flt, get_first_day, date_diff, nowdate
+from frappe.utils import add_days, getdate, formatdate, get_first_day, date_diff
from erpnext.utilities.doctype.address.address import get_address_display
from erpnext.utilities.doctype.contact.contact import get_contact_details
@@ -141,7 +141,16 @@
"due_date": get_due_date(posting_date, party_type, party, company)
}
return out
-
+
+def validate_party_account(party):
+ party_account_defined_for_companies = [d.company for d in party.get("party_accounts")]
+
+ for company, company_currency in frappe.db.sql("select name, default_currency from `tabCompany`"):
+ if party.currency and party.currency != company_currency \
+ and company not in party_account_defined_for_companies:
+ frappe.throw(_("Please mention Party Account for company {0}, as party currency is different than company's default currency")
+ .format(company))
+
@frappe.whitelist()
def get_party_account(company, party, party_type):
"""Returns the account for the given `party`.
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index af7716b..a70a771 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -8,6 +8,7 @@
from frappe.model.naming import make_autoname
from erpnext.utilities.address_and_contact import load_address_and_contact
from erpnext.utilities.transaction_base import TransactionBase
+from erpnext.accounts.party import validate_party_account
class Supplier(TransactionBase):
def get_feed(self):
@@ -44,6 +45,8 @@
if frappe.defaults.get_global_default('supp_master_name') == 'Naming Series':
if not self.naming_series:
msgprint(_("Series is mandatory"), raise_exception=1)
+
+ validate_party_account(self)
def get_contacts(self,nm):
if nm:
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index fe68966..ae5cb49 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -10,6 +10,7 @@
from erpnext.utilities.transaction_base import TransactionBase
from erpnext.utilities.address_and_contact import load_address_and_contact
+from erpnext.accounts.party import validate_party_account
class Customer(TransactionBase):
def get_feed(self):
@@ -26,12 +27,13 @@
else:
self.name = make_autoname(self.naming_series+'.#####')
- def validate_values(self):
+ def validate_mandatory(self):
if frappe.defaults.get_global_default('cust_master_name') == 'Naming Series' and not self.naming_series:
frappe.throw(_("Series is mandatory"), frappe.MandatoryError)
-
+
def validate(self):
- self.validate_values()
+ self.validate_mandatory()
+ validate_party_account(self)
def update_lead_status(self):
if self.lead_name: