diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index 46f75208fc6..a57cc259203 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -28,6 +28,7 @@ class Account(Document): 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 @@ class Account(Document): 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 43c421352c7..075abd7209a 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py @@ -20,6 +20,7 @@ class GLEntry(Document): 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 @@ class GLEntry(Document): 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 250286c4367..be672cca467 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -7,7 +7,7 @@ import frappe 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 @@ def set_account_and_due_date(party, account, party_type, company, posting_date, "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 af7716be0ea..a70a77195ac 100644 --- a/erpnext/buying/doctype/supplier/supplier.py +++ b/erpnext/buying/doctype/supplier/supplier.py @@ -8,6 +8,7 @@ from frappe import msgprint, _ 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 @@ class Supplier(TransactionBase): 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 fe68966f5f9..ae5cb49f185 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -10,6 +10,7 @@ from frappe.utils import flt 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 @@ class Customer(TransactionBase): 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: