[multi currency] Introduced Accounting Currency in Customer and Supplier, and validation according to that
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 83edf1d..fe49163 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -114,21 +114,12 @@
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 2b2912d..4a19645 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -142,17 +142,43 @@
}
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 35742be..e90ffc5 100644
--- a/erpnext/buying/doctype/supplier/supplier.json
+++ b/erpnext/buying/doctype/supplier/supplier.json
@@ -389,8 +389,31 @@
"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 a70a771..6ee6b39 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -8,7 +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
+from erpnext.accounts.party import validate_accounting_currency, validate_party_account
class Supplier(TransactionBase):
def get_feed(self):
@@ -46,6 +46,7 @@
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 7af7369..47d7e7a 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -428,20 +428,12 @@
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 45e8ebb..0441c4a 100644
--- a/erpnext/patches/v6_0/multi_currency.py
+++ b/erpnext/patches/v6_0/multi_currency.py
@@ -7,7 +7,7 @@
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 @@
# 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 952be8b..d160798 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,
@@ -463,8 +463,31 @@
"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 ae5cb49..c8f774c 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -10,7 +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
+from erpnext.accounts.party import validate_accounting_currency, validate_party_account
class Customer(TransactionBase):
def get_feed(self):
@@ -33,6 +33,7 @@
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 cf47de5..72c6cdd 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -34,13 +34,8 @@
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 @@
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