mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-02 11:49:10 +00:00
[multi currency] Introduced Accounting Currency in Customer and Supplier, and validation according to that
This commit is contained in:
@@ -114,21 +114,12 @@ class GLEntry(Document):
|
|||||||
|
|
||||||
|
|
||||||
if self.party_type and self.party:
|
if self.party_type and self.party:
|
||||||
existing_gle = frappe.db.get_value("GL Entry", {"party_type": self.party_type,
|
party_account_currency = frappe.db.get_value(self.party_type, self.party, "party_account_currency") \
|
||||||
"party": self.party, "company": self.company}, ["name", "account_currency"], as_dict=1)
|
or company_currency
|
||||||
if not existing_gle:
|
|
||||||
party_currency = frappe.db.get_value(self.party_type, self.party, "default_currency")\
|
if party_account_currency != self.account_currency:
|
||||||
or company_currency
|
frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}")
|
||||||
if party_currency != account_currency:
|
.format(self.party_type, self.party, party_account_currency), InvalidAccountCurrency)
|
||||||
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)
|
|
||||||
|
|
||||||
def validate_balance_type(account, adv_adj=False):
|
def validate_balance_type(account, adv_adj=False):
|
||||||
if not adv_adj and account:
|
if not adv_adj and account:
|
||||||
|
|||||||
@@ -142,17 +142,43 @@ def set_account_and_due_date(party, account, party_type, company, posting_date,
|
|||||||
}
|
}
|
||||||
return out
|
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):
|
def validate_party_account(party):
|
||||||
party_account_defined_for_companies = [d.company for d in party.get("accounts")]
|
company_currency = get_company_currency()
|
||||||
party_account_required_for_companies = []
|
|
||||||
for company, company_currency in frappe.db.sql("select name, default_currency from `tabCompany`"):
|
if party.party_account_currency != company_currency:
|
||||||
if party.default_currency and party.default_currency != company_currency \
|
party_account_defined_for_companies = [d.company for d in party.get("accounts")]
|
||||||
and company not in party_account_defined_for_companies:
|
all_companies = [d.name for d in frappe.get_list("Company")]
|
||||||
party_account_required_for_companies.append(company)
|
party_account_required_for_companies = list(set(all_companies) - set(party_account_defined_for_companies))
|
||||||
|
|
||||||
if party_account_required_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}")
|
frappe.msgprint(_("Please mention Default {0} Account for the following companies, as accounting currency is different from company's default currency: {1}")
|
||||||
.format("\n" + "\n".join(party_account_required_for_companies)))
|
.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()
|
@frappe.whitelist()
|
||||||
def get_party_account(company, party, party_type):
|
def get_party_account(company, party, party_type):
|
||||||
|
|||||||
@@ -385,12 +385,35 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"depends_on": "",
|
"depends_on": "",
|
||||||
"description": "Mention if non-standard receivable account applicable",
|
"description": "Mention if non-standard receivable account",
|
||||||
"fieldname": "accounts",
|
"fieldname": "accounts",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -511,8 +534,8 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-08-27 16:22:08.762061",
|
"modified": "2015-09-02 16:31:35.050738",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "nabin@erpnext.com",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Supplier",
|
"name": "Supplier",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from frappe import msgprint, _
|
|||||||
from frappe.model.naming import make_autoname
|
from frappe.model.naming import make_autoname
|
||||||
from erpnext.utilities.address_and_contact import load_address_and_contact
|
from erpnext.utilities.address_and_contact import load_address_and_contact
|
||||||
from erpnext.utilities.transaction_base import TransactionBase
|
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):
|
class Supplier(TransactionBase):
|
||||||
def get_feed(self):
|
def get_feed(self):
|
||||||
@@ -46,6 +46,7 @@ class Supplier(TransactionBase):
|
|||||||
if not self.naming_series:
|
if not self.naming_series:
|
||||||
msgprint(_("Series is mandatory"), raise_exception=1)
|
msgprint(_("Series is mandatory"), raise_exception=1)
|
||||||
|
|
||||||
|
validate_accounting_currency(self)
|
||||||
validate_party_account(self)
|
validate_party_account(self)
|
||||||
|
|
||||||
def get_contacts(self,nm):
|
def get_contacts(self,nm):
|
||||||
|
|||||||
@@ -428,20 +428,12 @@ class AccountsController(TransactionBase):
|
|||||||
if self.get("currency"):
|
if self.get("currency"):
|
||||||
party_type, party = self.get_party()
|
party_type, party = self.get_party()
|
||||||
if party_type and party:
|
if party_type and party:
|
||||||
existing_gle = frappe.db.get_value("GL Entry", {"party_type": party_type,
|
party_account_currency = frappe.db.get_value(party_type, party, "party_account_currency") \
|
||||||
"party": party, "company": self.company}, ["name", "account_currency"], as_dict=1)
|
or self.company_currency
|
||||||
if existing_gle:
|
|
||||||
currency_in_existing_entries = existing_gle.account_currency or self.company_currency
|
if party_account_currency != self.company_currency and self.currency != party_account_currency:
|
||||||
if currency_in_existing_entries != self.company_currency \
|
frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}")
|
||||||
and currency_in_existing_entries != self.currency:
|
.format(party_type, party, party_account_currency), InvalidCurrency)
|
||||||
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)
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_tax_rate(account_head):
|
def get_tax_rate(account_head):
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import frappe
|
|||||||
def execute():
|
def execute():
|
||||||
# Reload doctype
|
# Reload doctype
|
||||||
for dt in ("Account", "GL Entry", "Journal Entry",
|
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)
|
frappe.reload_doctype(dt)
|
||||||
|
|
||||||
for company in frappe.get_all("Company", fields=["name", "default_currency", "default_receivable_account"]):
|
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
|
# Set party account if default currency of party other than company's default currency
|
||||||
for dt in ("Customer", "Supplier"):
|
for dt in ("Customer", "Supplier"):
|
||||||
parties = frappe.db.sql("""select name from `tab{0}` p
|
parties = frappe.get_all(dt, ["name", "default_currency"])
|
||||||
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))
|
|
||||||
|
|
||||||
for p in parties:
|
for p in parties:
|
||||||
party = frappe.get_doc(dt, p[0])
|
# Get party GL Entries
|
||||||
party_gle = frappe.db.get_value("GL Entry", {"party_type": dt, "party": p[0],
|
party_gle = frappe.db.get_value("GL Entry", {"party_type": dt, "party": p.name,
|
||||||
"company": company.name}, ["account"], as_dict=True)
|
"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", {
|
# set default currency and party account currency
|
||||||
"company": company.name,
|
if not party.default_currency:
|
||||||
"account": party_account
|
party.default_currency = company.default_currency
|
||||||
})
|
|
||||||
party.ignore_mandatory()
|
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()
|
party.save()
|
||||||
@@ -273,7 +273,7 @@
|
|||||||
"ignore_user_permissions": 1,
|
"ignore_user_permissions": 1,
|
||||||
"in_filter": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_list_view": 0,
|
||||||
"label": "Currency",
|
"label": "Default Currency",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Currency",
|
"options": "Currency",
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
@@ -459,12 +459,35 @@
|
|||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"unique": 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,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"depends_on": "",
|
"depends_on": "",
|
||||||
"description": "Mention if non-standard receivable account applicable",
|
"description": "Mention if non-standard receivable account",
|
||||||
"fieldname": "accounts",
|
"fieldname": "accounts",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@@ -796,8 +819,8 @@
|
|||||||
"is_submittable": 0,
|
"is_submittable": 0,
|
||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"modified": "2015-08-27 17:00:50.604869",
|
"modified": "2015-09-02 16:32:54.474655",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "nabin@erpnext.com",
|
||||||
"module": "Selling",
|
"module": "Selling",
|
||||||
"name": "Customer",
|
"name": "Customer",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from frappe.utils import flt
|
|||||||
|
|
||||||
from erpnext.utilities.transaction_base import TransactionBase
|
from erpnext.utilities.transaction_base import TransactionBase
|
||||||
from erpnext.utilities.address_and_contact import load_address_and_contact
|
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):
|
class Customer(TransactionBase):
|
||||||
def get_feed(self):
|
def get_feed(self):
|
||||||
@@ -33,6 +33,7 @@ class Customer(TransactionBase):
|
|||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_mandatory()
|
self.validate_mandatory()
|
||||||
|
validate_accounting_currency(self)
|
||||||
validate_party_account(self)
|
validate_party_account(self)
|
||||||
|
|
||||||
def update_lead_status(self):
|
def update_lead_status(self):
|
||||||
|
|||||||
@@ -34,13 +34,8 @@ class Company(Document):
|
|||||||
if not self.abbr.strip():
|
if not self.abbr.strip():
|
||||||
frappe.throw(_("Abbreviation is mandatory"))
|
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_default_accounts()
|
||||||
|
self.validate_currency()
|
||||||
|
|
||||||
def validate_default_accounts(self):
|
def validate_default_accounts(self):
|
||||||
for field in ["default_bank_account", "default_cash_account", "default_receivable_account", "default_payable_account",
|
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:
|
if for_company != self.name:
|
||||||
frappe.throw(_("Account {0} does not belong to company: {1}")
|
frappe.throw(_("Account {0} does not belong to company: {1}")
|
||||||
.format(self.get(field), self.name))
|
.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):
|
def on_update(self):
|
||||||
if not frappe.db.sql("""select name from tabAccount
|
if not frappe.db.sql("""select name from tabAccount
|
||||||
|
|||||||
Reference in New Issue
Block a user