diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py index 83edf1df557..fe49163f269 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py @@ -114,21 +114,12 @@ class GLEntry(Document): if self.party_type and self.party: - existing_gle = frappe.db.get_value("GL Entry", {"party_type": self.party_type, - "party": self.party, "company": self.company}, ["name", "account_currency"], as_dict=1) - if not existing_gle: - party_currency = frappe.db.get_value(self.party_type, self.party, "default_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), - InvalidAccountCurrency) - else: - currency_in_existing_entries = existing_gle.account_currency or company_currency - if currency_in_existing_entries != self.account_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), - InvalidAccountCurrency) + party_account_currency = frappe.db.get_value(self.party_type, self.party, "party_account_currency") \ + or company_currency + + if party_account_currency != self.account_currency: + frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}") + .format(self.party_type, self.party, party_account_currency), InvalidAccountCurrency) 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 2b2912d190b..4a19645bec0 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -142,17 +142,43 @@ def set_account_and_due_date(party, account, party_type, company, posting_date, } return out +def validate_accounting_currency(party): + company_currency = get_company_currency() + + # set party account currency + if not party.party_account_currency: + if party.default_currency: + party.party_account_currency = party.default_currency + else: + party.party_account_currency = company_currency + + party_account_currency_in_db = frappe.db.get_value(party.doctype, party.name, "party_account_currency") + if party_account_currency_in_db and party_account_currency_in_db != party.party_account_currency: + existing_gle = frappe.db.get_value("GL Entry", {"party_type": party.doctype, + "party": party.name}, ["name", "account_currency"], as_dict=1) + if existing_gle: + frappe.throw(_("Accounting Currency cannot be changed, as GL Entry exists for this {0}") + .format(party.doctype)) + + def validate_party_account(party): - party_account_defined_for_companies = [d.company for d in party.get("accounts")] - party_account_required_for_companies = [] - for company, company_currency in frappe.db.sql("select name, default_currency from `tabCompany`"): - if party.default_currency and party.default_currency != company_currency \ - and company not in party_account_defined_for_companies: - party_account_required_for_companies.append(company) + company_currency = get_company_currency() + + if party.party_account_currency != company_currency: + party_account_defined_for_companies = [d.company for d in party.get("accounts")] + all_companies = [d.name for d in frappe.get_list("Company")] + party_account_required_for_companies = list(set(all_companies) - set(party_account_defined_for_companies)) - if party_account_required_for_companies: - frappe.msgprint(_("Please mention Party Account for the following companies, as party currency is different from company's default currency: {0}") - .format("\n" + "\n".join(party_account_required_for_companies))) + if party_account_required_for_companies: + frappe.msgprint(_("Please mention Default {0} Account for the following companies, as accounting currency is different from company's default currency: {1}") + .format( + "Receivable" if party.doctype=="Customer" else "Payable", + "\n" + "\n".join(party_account_required_for_companies) + ) + ) + +def get_company_currency(): + return frappe.db.sql("select default_currency from tabCompany limit 1")[0][0] @frappe.whitelist() def get_party_account(company, party, party_type): diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json index 35742be6624..e90ffc541f9 100644 --- a/erpnext/buying/doctype/supplier/supplier.json +++ b/erpnext/buying/doctype/supplier/supplier.json @@ -385,12 +385,35 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "party_account_currency", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Accounting Currency", + "no_copy": 0, + "options": "Currency", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, "collapsible": 0, "depends_on": "", - "description": "Mention if non-standard receivable account applicable", + "description": "Mention if non-standard receivable account", "fieldname": "accounts", "fieldtype": "Table", "hidden": 0, @@ -511,8 +534,8 @@ "is_submittable": 0, "issingle": 0, "istable": 0, - "modified": "2015-08-27 16:22:08.762061", - "modified_by": "Administrator", + "modified": "2015-09-02 16:31:35.050738", + "modified_by": "nabin@erpnext.com", "module": "Buying", "name": "Supplier", "owner": "Administrator", diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py index a70a77195ac..6ee6b3928b1 100644 --- a/erpnext/buying/doctype/supplier/supplier.py +++ b/erpnext/buying/doctype/supplier/supplier.py @@ -8,7 +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 +from erpnext.accounts.party import validate_accounting_currency, validate_party_account class Supplier(TransactionBase): def get_feed(self): @@ -46,6 +46,7 @@ class Supplier(TransactionBase): if not self.naming_series: msgprint(_("Series is mandatory"), raise_exception=1) + validate_accounting_currency(self) validate_party_account(self) def get_contacts(self,nm): diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 7af73691889..47d7e7a4fee 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -428,20 +428,12 @@ class AccountsController(TransactionBase): if self.get("currency"): party_type, party = self.get_party() if party_type and party: - existing_gle = frappe.db.get_value("GL Entry", {"party_type": party_type, - "party": party, "company": self.company}, ["name", "account_currency"], as_dict=1) - if existing_gle: - currency_in_existing_entries = existing_gle.account_currency or self.company_currency - if currency_in_existing_entries != self.company_currency \ - and currency_in_existing_entries != self.currency: - frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}") - .format(party_type, party, currency_in_existing_entries), InvalidCurrency) - else: - party_currency = frappe.db.get_value(party_type, party, "default_currency") \ - or self.company_currency - if party_currency != self.company_currency and self.currency != party_currency: - frappe.throw(_("Currency must be same as {0} currency {1}") - .format(party_type, party_currency), InvalidCurrency) + party_account_currency = frappe.db.get_value(party_type, party, "party_account_currency") \ + or self.company_currency + + if party_account_currency != self.company_currency and self.currency != party_account_currency: + frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}") + .format(party_type, party, party_account_currency), InvalidCurrency) @frappe.whitelist() def get_tax_rate(account_head): diff --git a/erpnext/patches/v6_0/multi_currency.py b/erpnext/patches/v6_0/multi_currency.py index 45e8ebb3d0d..0441c4a776d 100644 --- a/erpnext/patches/v6_0/multi_currency.py +++ b/erpnext/patches/v6_0/multi_currency.py @@ -7,7 +7,7 @@ import frappe def execute(): # Reload doctype for dt in ("Account", "GL Entry", "Journal Entry", - "Journal Entry Account", "Sales Invoice", "Purchase Invoice"): + "Journal Entry Account", "Sales Invoice", "Purchase Invoice", "Customer", "Supplier"): frappe.reload_doctype(dt) for company in frappe.get_all("Company", fields=["name", "default_currency", "default_receivable_account"]): @@ -65,21 +65,36 @@ def execute(): # Set party account if default currency of party other than company's default currency for dt in ("Customer", "Supplier"): - parties = frappe.db.sql("""select name from `tab{0}` p - where ifnull(default_currency, '') != '' and default_currency != %s - and not exists(select name from `tabParty Account` where parent=p.name and company=%s)""" - .format(dt), (company.default_currency, company.name)) - + parties = frappe.get_all(dt, ["name", "default_currency"]) for p in parties: - party = frappe.get_doc(dt, p[0]) - party_gle = frappe.db.get_value("GL Entry", {"party_type": dt, "party": p[0], - "company": company.name}, ["account"], as_dict=True) + # Get party GL Entries + party_gle = frappe.db.get_value("GL Entry", {"party_type": dt, "party": p.name, + "company": company.name}, ["account", "account_currency"], as_dict=True) - party_account = party_gle.account or company.default_receivable_account + party = frappe.get_doc(dt, p.name) - party.append("accounts", { - "company": company.name, - "account": party_account - }) - party.ignore_mandatory() + # set default currency and party account currency + if not party.default_currency: + party.default_currency = company.default_currency + + party.party_account_currency = company.default_currency if party_gle else party.default_currency + + # Add default receivable /payable account if not exists + # and currency is other than company currency + if party.default_currency != company.default_currency: + party_account_exists = False + for d in party.get("accounts"): + if d.company == company.name: + party_account_exists = True + break + + if not party_account_exists: + party_account = party_gle.account if party_gle else company.default_receivable_account + if party_account: + party.append("accounts", { + "company": company.name, + "account": party_account + }) + + party.flags.ignore_mandatory = True party.save() \ No newline at end of file diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json index 952be8ba721..d160798b3d9 100644 --- a/erpnext/selling/doctype/customer/customer.json +++ b/erpnext/selling/doctype/customer/customer.json @@ -273,7 +273,7 @@ "ignore_user_permissions": 1, "in_filter": 0, "in_list_view": 0, - "label": "Currency", + "label": "Default Currency", "no_copy": 1, "options": "Currency", "permlevel": 0, @@ -459,12 +459,35 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "party_account_currency", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Accounting Currency", + "no_copy": 0, + "options": "Currency", + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, "collapsible": 0, "depends_on": "", - "description": "Mention if non-standard receivable account applicable", + "description": "Mention if non-standard receivable account", "fieldname": "accounts", "fieldtype": "Table", "hidden": 0, @@ -796,8 +819,8 @@ "is_submittable": 0, "issingle": 0, "istable": 0, - "modified": "2015-08-27 17:00:50.604869", - "modified_by": "Administrator", + "modified": "2015-09-02 16:32:54.474655", + "modified_by": "nabin@erpnext.com", "module": "Selling", "name": "Customer", "owner": "Administrator", diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index ae5cb49f185..c8f774c17ec 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -10,7 +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 +from erpnext.accounts.party import validate_accounting_currency, validate_party_account class Customer(TransactionBase): def get_feed(self): @@ -33,6 +33,7 @@ class Customer(TransactionBase): def validate(self): self.validate_mandatory() + validate_accounting_currency(self) validate_party_account(self) def update_lead_status(self): diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index cf47de5f6f6..72c6cdd52b5 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -34,13 +34,8 @@ class Company(Document): if not self.abbr.strip(): frappe.throw(_("Abbreviation is mandatory")) - self.previous_default_currency = frappe.db.get_value("Company", self.name, "default_currency") - if self.default_currency and self.previous_default_currency and \ - self.default_currency != self.previous_default_currency and \ - self.check_if_transactions_exist(): - frappe.throw(_("Cannot change company's default currency, because there are existing transactions. Transactions must be cancelled to change the default currency.")) - self.validate_default_accounts() + self.validate_currency() def validate_default_accounts(self): for field in ["default_bank_account", "default_cash_account", "default_receivable_account", "default_payable_account", @@ -51,6 +46,21 @@ class Company(Document): if for_company != self.name: frappe.throw(_("Account {0} does not belong to company: {1}") .format(self.get(field), self.name)) + + def validate_currency(self): + self.previous_default_currency = frappe.db.get_value("Company", self.name, "default_currency") + if self.default_currency and self.previous_default_currency and \ + self.default_currency != self.previous_default_currency and \ + self.check_if_transactions_exist(): + frappe.throw(_("Cannot change company's default currency, because there are existing transactions. Transactions must be cancelled to change the default currency.")) + + if self.default_currency: + currency_in_other_companies = frappe.db.sql("""select default_currency from tabCompany + where name!=%s limit 1""", self.name) + + if currency_in_other_companies and self.default_currency != currency_in_other_companies[0][0]: + frappe.throw(_("Currency must be same for all Companies")) + def on_update(self): if not frappe.db.sql("""select name from tabAccount