[multi currency] Introduced Accounting Currency in Customer and Supplier, and validation according to that

This commit is contained in:
Nabin Hait 2015-09-03 10:28:08 +05:30
parent bac9b8eef6
commit 98096771c2
9 changed files with 150 additions and 68 deletions

View File

@ -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:

View File

@ -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):

View File

@ -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",

View File

@ -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):

View File

@ -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):

View File

@ -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()

View File

@ -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",

View File

@ -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):

View File

@ -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