diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py index 079bc361cac..7b6d0daebad 100644 --- a/erpnext/accounts/doctype/account/account.py +++ b/erpnext/accounts/doctype/account/account.py @@ -50,20 +50,20 @@ class Account(Document): def set_root_and_report_type(self): if self.parent_account: par = frappe.db.get_value("Account", self.parent_account, ["report_type", "root_type"], as_dict=1) - + if par.report_type: self.report_type = par.report_type if par.root_type: self.root_type = par.root_type - + if self.is_group: db_value = frappe.db.get_value("Account", self.name, ["report_type", "root_type"], as_dict=1) if db_value: if self.report_type != db_value.report_type: - frappe.db.sql("update `tabAccount` set report_type=%s where lft > %s and rgt < %s", + frappe.db.sql("update `tabAccount` set report_type=%s where lft > %s and rgt < %s", (self.report_type, self.lft, self.rgt)) if self.root_type != db_value.root_type: - frappe.db.sql("update `tabAccount` set root_type=%s where lft > %s and rgt < %s", + frappe.db.sql("update `tabAccount` set root_type=%s where lft > %s and rgt < %s", (self.root_type, self.lft, self.rgt)) def validate_root_details(self): @@ -89,11 +89,11 @@ 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.account_currency: self.account_currency = frappe.db.get_value("Company", self.company, "default_currency") - + elif self.account_currency != frappe.db.get_value("Account", self.name, "account_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")) @@ -207,3 +207,14 @@ def get_parent_account(doctype, txt, searchfield, start, page_len, filters): and %s like %s order by name limit %s, %s""" % ("%s", searchfield, "%s", "%s", "%s"), (filters["company"], "%%%s%%" % txt, start, page_len), as_list=1) + +def get_account_currency(account): + """Helper function to get account currency""" + def generator(): + account_currency, company = frappe.db.get_value("Account", account, ["account_currency", "company"]) + if not account_currency: + account_currency = frappe.db.get_value("Company", company, "default_currency") + + return account_currency + + return frappe.local_cache("account_currency", account, generator) diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py index dbaf5901daf..3927b8e61de 100644 --- a/erpnext/accounts/doctype/gl_entry/gl_entry.py +++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py @@ -3,15 +3,13 @@ from __future__ import unicode_literals import frappe - -from frappe.utils import flt, fmt_money, getdate, formatdate from frappe import _ - +from frappe.utils import flt, fmt_money, getdate, formatdate from frappe.model.document import Document - -class CustomerFrozen(frappe.ValidationError): pass -class InvalidCurrency(frappe.ValidationError): pass -class InvalidAccountCurrency(frappe.ValidationError): pass +from erpnext.accounts.party import validate_party_gle_currency, get_party_account_currency +from erpnext.accounts.utils import get_account_currency +from erpnext.setup.doctype.company.company import get_company_currency +from erpnext.exceptions import InvalidAccountCurrency, CustomerFrozen class GLEntry(Document): def validate(self): @@ -101,25 +99,26 @@ 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, "account_currency") or company_currency + company_currency = get_company_currency(self.company) + account_currency = get_account_currency(self.account) if not self.account_currency: self.account_currency = company_currency + if account_currency != self.account_currency: frappe.throw(_("Accounting Entry for {0} can only be made in currency: {1}") .format(self.account, (account_currency or company_currency)), InvalidAccountCurrency) - - + if self.party_type and self.party: - party_account_currency = frappe.db.get_value(self.party_type, self.party, "party_account_currency") \ - or company_currency + party_account_currency = get_party_account_currency(self.party_type, self.party, self.company) 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) + .format(self.party_type, self.party, party_account_currency), InvalidAccountCurrency) + + validate_party_gle_currency(self.party_type, self.party, self.company) def validate_balance_type(account, adv_adj=False): if not adv_adj and account: @@ -159,7 +158,7 @@ def update_outstanding_amt(account, party_type, party, against_voucher_type, aga where against_voucher_type=%s and against_voucher=%s and account = %s {0}""".format(party_condition), (against_voucher_type, against_voucher, account))[0][0] or 0.0) - + if against_voucher_type == 'Purchase Invoice': bal = -bal elif against_voucher_type == "Journal Entry": diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 33192bd04af..e7773a63880 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -6,7 +6,8 @@ import frappe from frappe.utils import cstr, flt, fmt_money, formatdate from frappe import msgprint, _, scrub from erpnext.controllers.accounts_controller import AccountsController -from erpnext.accounts.utils import get_balance_on +from erpnext.accounts.utils import get_balance_on, get_account_currency +from erpnext.accounts.party import get_party_account_currency from erpnext.setup.utils import get_company_currency @@ -146,7 +147,7 @@ class JournalEntry(AccountsController): self.reference_totals = {} self.reference_types = {} - self.reference_parties = {} + self.reference_accounts = {} for d in self.get("accounts"): if not d.reference_type: @@ -169,8 +170,7 @@ class JournalEntry(AccountsController): self.reference_totals[d.reference_name] = 0.0 self.reference_totals[d.reference_name] += flt(d.get(dr_or_cr)) self.reference_types[d.reference_name] = d.reference_type - if d.party_type and d.party: - self.reference_parties[d.reference_name] = [d.party_type, d.party] + self.reference_accounts[d.reference_name] = d.account against_voucher = frappe.db.get_value(d.reference_type, d.reference_name, [scrub(dt) for dt in field_dict.get(d.reference_type)]) @@ -196,7 +196,7 @@ class JournalEntry(AccountsController): """Validate totals, stopped and docstatus for orders""" for reference_name, total in self.reference_totals.iteritems(): reference_type = self.reference_types[reference_name] - party_type, party = self.reference_parties.get(reference_name) + account = self.reference_accounts[reference_name] if reference_type in ("Sales Order", "Purchase Order"): order = frappe.db.get_value(reference_type, reference_name, @@ -212,8 +212,8 @@ class JournalEntry(AccountsController): if cstr(order.status) == "Stopped": frappe.throw(_("{0} {1} is stopped").format(reference_type, reference_name)) - party_account_currency = frappe.db.get_value(party_type, party, "party_account_currency") - if party_account_currency == self.company_currency: + account_currency = get_account_currency(account) + if account_currency == self.company_currency: voucher_total = order.base_grand_total else: voucher_total = order.grand_total @@ -609,8 +609,8 @@ def get_payment_entry_from_sales_order(sales_order): jv = get_payment_entry(so) jv.remark = 'Advance payment received against Sales Order {0}.'.format(so.name) - party_account = get_party_account(so.company, so.customer, "Customer") - party_account_currency = frappe.db.get_value("Account", party_account, "account_currency") + party_account = get_party_account("Customer", so.customer, so.company) + party_account_currency = get_account_currency(party_account) exchange_rate = get_exchange_rate(party_account, party_account_currency, so.company) @@ -660,8 +660,8 @@ def get_payment_entry_from_purchase_order(purchase_order): jv = get_payment_entry(po) jv.remark = 'Advance payment made against Purchase Order {0}.'.format(po.name) - party_account = get_party_account(po.company, po.supplier, "Supplier") - party_account_currency = frappe.db.get_value("Account", party_account, "account_currency") + party_account = get_party_account("Supplier", po.supplier, po.company) + party_account_currency = get_account_currency(party_account) exchange_rate = get_exchange_rate(party_account, party_account_currency, po.company) @@ -779,7 +779,7 @@ def get_party_account_and_balance(company, party_type, party): frappe.msgprint(_("No Permission"), raise_exception=1) from erpnext.accounts.party import get_party_account - account = get_party_account(company, party, party_type) + account = get_party_account(party_type, party, company) account_balance = get_balance_on(account=account) party_balance = get_balance_on(party_type=party_type, party=party) diff --git a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py index 753e0126c9b..a4d6406fba1 100644 --- a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import unittest, frappe from frappe.utils import flt from erpnext.accounts.utils import get_actual_expense, BudgetError, get_fiscal_year +from erpnext.exceptions import InvalidAccountCurrency class TestJournalEntry(unittest.TestCase): @@ -166,15 +167,15 @@ class TestJournalEntry(unittest.TestCase): existing_expense = self.get_actual_expense(posting_date) make_journal_entry("_Test Account Cost for Goods Sold - _TC", "_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True) - + def test_multi_currency(self): jv = make_journal_entry("_Test Bank USD - _TC", "_Test Bank - _TC", 100, exchange_rate=50, save=False) - + jv.get("accounts")[1].credit_in_account_currency = 5000 jv.submit() - - gl_entries = frappe.db.sql("""select account, account_currency, debit, credit, + + gl_entries = frappe.db.sql("""select account, account_currency, debit, credit, debit_in_account_currency, credit_in_account_currency from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s order by account asc""", jv.name, as_dict=1) @@ -197,12 +198,10 @@ class TestJournalEntry(unittest.TestCase): "credit_in_account_currency": 5000 } } - + for field in ("account_currency", "debit", "debit_in_account_currency", "credit", "credit_in_account_currency"): for i, gle in enumerate(gl_entries): self.assertEquals(expected_values[gle.account][field], gle[field]) - - # cancel jv.cancel() @@ -212,6 +211,40 @@ class TestJournalEntry(unittest.TestCase): self.assertFalse(gle) + def test_disallow_change_in_account_currency_for_a_party(self): + # create jv in USD + jv = make_journal_entry("_Test Bank USD - _TC", + "_Test Receivable USD - _TC", 100, save=False) + + jv.accounts[1].update({ + "party_type": "Customer", + "party": "_Test Customer USD" + }) + + jv.submit() + + # create jv in USD, but account currency in INR + jv = make_journal_entry("_Test Bank - _TC", + "_Test Receivable - _TC", 100, save=False) + + jv.accounts[1].update({ + "party_type": "Customer", + "party": "_Test Customer USD" + }) + + self.assertRaises(InvalidAccountCurrency, jv.submit) + + # back in USD + jv = make_journal_entry("_Test Bank USD - _TC", + "_Test Receivable USD - _TC", 100, save=False) + + jv.accounts[1].update({ + "party_type": "Customer", + "party": "_Test Customer USD" + }) + + jv.submit() + def make_journal_entry(account1, account2, amount, cost_center=None, exchange_rate=1, save=True, submit=False): jv = frappe.new_doc("Journal Entry") jv.posting_date = "2013-02-14" @@ -231,7 +264,7 @@ def make_journal_entry(account1, account2, amount, cost_center=None, exchange_ra "cost_center": cost_center, "credit_in_account_currency": amount if amount > 0 else 0, "debit_in_account_currency": abs(amount) if amount < 0 else 0, - exchange_rate: exchange_rate + "exchange_rate": exchange_rate } ]) if save or submit: diff --git a/erpnext/accounts/doctype/payment_tool/payment_tool.py b/erpnext/accounts/doctype/payment_tool/payment_tool.py index b02214c847d..6cf2b6dfe03 100644 --- a/erpnext/accounts/doctype/payment_tool/payment_tool.py +++ b/erpnext/accounts/doctype/payment_tool/payment_tool.py @@ -7,6 +7,7 @@ from frappe import _, scrub from frappe.utils import flt from frappe.model.document import Document import json +from erpnext.accounts.utils import get_account_currency class PaymentTool(Document): def make_journal_entry(self): @@ -59,7 +60,7 @@ def get_outstanding_vouchers(args): args = json.loads(args) - party_account_currency = frappe.db.get_value("Account", args.get("party_account"), "account_currency") + party_account_currency = get_account_currency(args.get("party_account")) company_currency = frappe.db.get_value("Company", args.get("company"), "default_currency") if args.get("party_type") == "Customer" and args.get("received_or_paid") == "Received": @@ -112,7 +113,7 @@ def get_orders_to_be_billed(party_type, party, party_account_currency, company_c @frappe.whitelist() def get_against_voucher_amount(against_voucher_type, against_voucher_no, party_account, company): - party_account_currency = frappe.db.get_value("Account", party_account, "account_currency") + party_account_currency = get_account_currency(party_account) company_currency = frappe.db.get_value("Company", company, "default_currency") ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total" diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index d92e1fa0ccd..5697b778ed7 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -10,6 +10,7 @@ import frappe.defaults from erpnext.controllers.buying_controller import BuyingController from erpnext.accounts.party import get_party_account, get_due_date +from erpnext.accounts.utils import get_account_currency form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -66,7 +67,7 @@ class PurchaseInvoice(BuyingController): def set_missing_values(self, for_validate=False): if not self.credit_to: - self.credit_to = get_party_account(self.company, self.supplier, "Supplier") + self.credit_to = get_party_account("Supplier", self.supplier, self.company) if not self.due_date: self.due_date = get_due_date(self.posting_date, "Supplier", self.supplier, self.company) @@ -91,7 +92,7 @@ class PurchaseInvoice(BuyingController): throw(_("Conversion rate cannot be 0 or 1")) def validate_credit_to_acc(self): - account = frappe.db.get_value("Account", self.credit_to, + account = frappe.db.get_value("Account", self.credit_to, ["account_type", "report_type", "account_currency"], as_dict=True) if account.report_type != "Balance Sheet": @@ -99,7 +100,7 @@ class PurchaseInvoice(BuyingController): if self.supplier and account.account_type != "Payable": frappe.throw(_("Credit To account must be a Payable account")) - + self.party_account_currency = account.account_currency def check_for_stopped_status(self): @@ -251,7 +252,7 @@ class PurchaseInvoice(BuyingController): expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation") gl_entries = [] - + # parent's gl entry if self.base_grand_total: gl_entries.append( @@ -272,10 +273,10 @@ class PurchaseInvoice(BuyingController): valuation_tax = {} for tax in self.get("taxes"): if tax.category in ("Total", "Valuation and Total") and flt(tax.base_tax_amount_after_discount_amount): - account_currency = frappe.db.get_value("Account", tax.account_head, "account_currency") - + account_currency = get_account_currency(tax.account_head) + dr_or_cr = "debit" if tax.add_deduct_tax == "Add" else "credit" - + gl_entries.append( self.get_gl_dict({ "account": tax.account_head, @@ -301,7 +302,7 @@ class PurchaseInvoice(BuyingController): stock_items = self.get_stock_items() for item in self.get("items"): if flt(item.base_net_amount): - account_currency = frappe.db.get_value("Account", item.expense_account, "account_currency") + account_currency = get_account_currency(item.expense_account) gl_entries.append( self.get_gl_dict({ "account": item.expense_account, @@ -363,8 +364,8 @@ class PurchaseInvoice(BuyingController): # writeoff account includes petty difference in the invoice amount # and the amount that is paid if self.write_off_account and flt(self.write_off_amount): - write_off_account_currency = frappe.db.get_value("Account", self.write_off_account, "account_currency") - + write_off_account_currency = get_account_currency(self.write_off_account) + gl_entries.append( self.get_gl_dict({ "account": self.credit_to, diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index b39f30bbdcc..67286db2021 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -10,7 +10,7 @@ from frappe.utils import cint import frappe.defaults from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory, \ test_records as pr_test_records -from erpnext.controllers.accounts_controller import InvalidCurrency +from erpnext.exceptions import InvalidCurrency test_dependencies = ["Item", "Cost Center"] test_ignore = ["Serial No"] @@ -219,7 +219,7 @@ class TestPurchaseInvoice(unittest.TestCase): pi.load_from_db() self.assertTrue(frappe.db.sql("""select name from `tabJournal Entry Account` - where reference_type='Purchase Invoice' + where reference_type='Purchase Invoice' and reference_name=%s and debit_in_account_currency=300""", pi.name)) self.assertEqual(pi.outstanding_amount, 1212.30) @@ -237,17 +237,17 @@ class TestPurchaseInvoice(unittest.TestCase): existing_purchase_cost = frappe.db.sql("""select sum(ifnull(base_net_amount, 0)) from `tabPurchase Invoice Item` where project_name = '_Test Project' and docstatus=1""") existing_purchase_cost = existing_purchase_cost and existing_purchase_cost[0][0] or 0 - + pi = make_purchase_invoice(currency="USD", conversion_rate=60, project_name="_Test Project") - self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), + self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), existing_purchase_cost + 15000) pi1 = make_purchase_invoice(qty=10, project_name="_Test Project") - self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), + self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), existing_purchase_cost + 15500) pi1.cancel() - self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), + self.assertEqual(frappe.db.get_value("Project", "_Test Project", "total_purchase_cost"), existing_purchase_cost + 15000) pi.cancel() @@ -278,14 +278,14 @@ class TestPurchaseInvoice(unittest.TestCase): self.assertEquals(expected_values[gle.account][1], gle.credit) set_perpetual_inventory(0) - + def test_multi_currency_gle(self): set_perpetual_inventory(0) - - pi = make_purchase_invoice(supplier="_Test Supplier USD", credit_to="_Test Payable USD - _TC", + + pi = make_purchase_invoice(supplier="_Test Supplier USD", credit_to="_Test Payable USD - _TC", currency="USD", conversion_rate=50) - gl_entries = frappe.db.sql("""select account, account_currency, debit, credit, + gl_entries = frappe.db.sql("""select account, account_currency, debit, credit, debit_in_account_currency, credit_in_account_currency from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s order by account asc""", pi.name, as_dict=1) @@ -308,16 +308,16 @@ class TestPurchaseInvoice(unittest.TestCase): "credit_in_account_currency": 0 } } - + for field in ("account_currency", "debit", "debit_in_account_currency", "credit", "credit_in_account_currency"): for i, gle in enumerate(gl_entries): self.assertEquals(expected_values[gle.account][field], gle[field]) - - + + # Check for valid currency pi1 = make_purchase_invoice(supplier="_Test Supplier USD", credit_to="_Test Payable USD - _TC", do_not_save=True) - + self.assertRaises(InvalidCurrency, pi1.save) # cancel diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 885e7bd1603..dba7647a624 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -11,6 +11,7 @@ from erpnext.controllers.stock_controller import update_gl_entries_after from frappe.model.mapper import get_mapped_doc from erpnext.controllers.selling_controller import SellingController +from erpnext.accounts.utils import get_account_currency form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -186,7 +187,7 @@ class SalesInvoice(SellingController): pos = self.set_pos_fields(for_validate) if not self.debit_to: - self.debit_to = get_party_account(self.company, self.customer, "Customer") + self.debit_to = get_party_account("Customer", self.customer, self.company) if not self.due_date and self.customer: self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company) @@ -531,7 +532,7 @@ class SalesInvoice(SellingController): def make_tax_gl_entries(self, gl_entries): for tax in self.get("taxes"): if flt(tax.base_tax_amount_after_discount_amount): - account_currency = frappe.db.get_value("Account", tax.account_head, "account_currency") + account_currency = get_account_currency(tax.account_head) gl_entries.append( self.get_gl_dict({ "account": tax.account_head, @@ -547,7 +548,7 @@ class SalesInvoice(SellingController): # income account gl entries for item in self.get("items"): if flt(item.base_net_amount): - account_currency = frappe.db.get_value("Account", item.income_account, "account_currency") + account_currency = get_account_currency(item.income_account) gl_entries.append( self.get_gl_dict({ "account": item.income_account, @@ -566,7 +567,7 @@ class SalesInvoice(SellingController): def make_pos_gl_entries(self, gl_entries): if cint(self.is_pos) and self.cash_bank_account and self.paid_amount: - bank_account_currency = frappe.db.get_value("Account", self.cash_bank_account, "account_currency") + bank_account_currency = get_account_currency(self.cash_bank_account) # POS, make payment entries gl_entries.append( self.get_gl_dict({ @@ -594,7 +595,7 @@ class SalesInvoice(SellingController): def make_write_off_gl_entry(self, gl_entries): # write off entries, applicable if only pos if self.write_off_account and self.write_off_amount: - write_off_account_currency = frappe.db.get_value("Account", self.write_off_account, "account_currency") + write_off_account_currency = get_account_currency(self.write_off_account) gl_entries.append( self.get_gl_dict({ diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 449f98d8f2d..0eae7cbcfb6 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -7,8 +7,7 @@ import unittest, copy from frappe.utils import nowdate, add_days, flt from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry, get_qty_after_transaction from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory -from erpnext.controllers.accounts_controller import InvalidCurrency -from erpnext.accounts.doctype.gl_entry.gl_entry import InvalidAccountCurrency +from erpnext.exceptions import InvalidAccountCurrency, InvalidCurrency class TestSalesInvoice(unittest.TestCase): def make(self): @@ -842,13 +841,13 @@ class TestSalesInvoice(unittest.TestCase): self.assertEquals(si.total_taxes_and_charges, 234.44) self.assertEquals(si.base_grand_total, 859.44) self.assertEquals(si.grand_total, 859.44) - + def test_multi_currency_gle(self): set_perpetual_inventory(0) - si = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC", + si = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC", currency="USD", conversion_rate=50) - gl_entries = frappe.db.sql("""select account, account_currency, debit, credit, + gl_entries = frappe.db.sql("""select account, account_currency, debit, credit, debit_in_account_currency, credit_in_account_currency from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s order by account asc""", si.name, as_dict=1) @@ -871,7 +870,7 @@ class TestSalesInvoice(unittest.TestCase): "credit_in_account_currency": 5000 } } - + for field in ("account_currency", "debit", "debit_in_account_currency", "credit", "credit_in_account_currency"): for i, gle in enumerate(gl_entries): self.assertEquals(expected_values[gle.account][field], gle[field]) @@ -883,38 +882,38 @@ class TestSalesInvoice(unittest.TestCase): where voucher_type='Sales Invoice' and voucher_no=%s""", si.name) self.assertFalse(gle) - + def test_invalid_currency(self): # Customer currency = USD - + # Transaction currency cannot be INR - si1 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC", + si1 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC", do_not_save=True) - + self.assertRaises(InvalidCurrency, si1.save) - + # Transaction currency cannot be EUR - si2 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC", + si2 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC", currency="EUR", conversion_rate=80, do_not_save=True) - + self.assertRaises(InvalidCurrency, si2.save) - + # Transaction currency only allowed in USD - si3 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC", + si3 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC", currency="USD", conversion_rate=50) - + # Party Account currency must be in USD, as there is existing GLE with USD - si4 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable - _TC", + si4 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable - _TC", currency="USD", conversion_rate=50, do_not_submit=True) - + self.assertRaises(InvalidAccountCurrency, si4.submit) - + # Party Account currency must be in USD, force customer currency as there is no GLE - + si3.cancel() - si5 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable - _TC", + si5 = create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable - _TC", currency="USD", conversion_rate=50, do_not_submit=True) - + self.assertRaises(InvalidAccountCurrency, si5.submit) def create_sales_invoice(**args): diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 2090e774d92..1eaf8a79319 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -10,9 +10,9 @@ from frappe.defaults import get_user_permissions 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 +from erpnext.exceptions import InvalidAccountCurrency -class InvalidCurrency(frappe.ValidationError): pass -class InvalidAccountCurrency(frappe.ValidationError): pass +class DuplicatePartyAccountError(frappe.ValidationError): pass @frappe.whitelist() def get_party_details(party=None, account=None, party_type="Customer", company=None, @@ -142,7 +142,7 @@ def set_account_and_due_date(party, account, party_type, company, posting_date, } if party: - account = get_party_account(company, party, party_type) + account = get_party_account(party_type, party, company) account_fieldname = "debit_to" if party_type=="Customer" else "credit_to" @@ -153,44 +153,6 @@ def set_account_and_due_date(party, account, party_type, company, posting_date, } return out -def validate_accounting_currency(party): - party_account_currency_in_db = frappe.db.get_value(party.doctype, party.name, "party_account_currency") - if 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: - if party_account_currency_in_db: - frappe.throw(_("Accounting Currency cannot be changed, as GL Entry exists for this {0}") - .format(party.doctype), InvalidCurrency) - else: - party.party_account_currency = existing_gle.account_currency - - -def validate_party_account(party): - company_currency = get_company_currency() - if party.party_account_currency: - companies_with_different_currency = [] - for company, currency in company_currency.items(): - if currency != party.party_account_currency: - companies_with_different_currency.append(company) - - for d in party.get("accounts"): - if d.company in companies_with_different_currency: - companies_with_different_currency.remove(d.company) - - selected_account_currency = frappe.db.get_value("Account", d.account, "account_currency") - if selected_account_currency != party.party_account_currency: - frappe.throw(_("Account {0} is invalid, account currency must be {1}") - .format(d.account, selected_account_currency), InvalidAccountCurrency) - - if companies_with_different_currency: - 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(companies_with_different_currency) - ) - ) - def get_company_currency(): company_currency = frappe._dict() for d in frappe.get_all("Company", fields=["name", "default_currency"]): @@ -199,13 +161,13 @@ def get_company_currency(): return company_currency @frappe.whitelist() -def get_party_account(company, party, party_type): +def get_party_account(party_type, party, company): """Returns the account for the given `party`. Will first search in party (Customer / Supplier) record, if not found, will search in group (Customer Group / Supplier Type), finally will return default.""" if not company: - frappe.throw(_("Please select company first.")) + frappe.throw(_("Please select a Company")) if party: account = frappe.db.get_value("Party Account", @@ -223,6 +185,42 @@ def get_party_account(company, party, party_type): return account +def get_party_account_currency(party_type, party, company): + def generator(): + party_account = get_party_account(party_type, party, company) + return frappe.db.get_value("Account", party_account, "account_currency") + + return frappe.local_cache("party_account_currency", (party_type, party, company), generator) + +def get_party_gle_currency(party_type, party, company): + def generator(): + existing_gle_currency = frappe.db.sql("""select account_currency from `tabGL Entry` + where docstatus=1 and company=%(company)s and party_type=%(party_type)s and party=%(party)s + limit 1""", { "company": company, "party_type": party_type, "party": party }) + + return existing_gle_currency[0][0] if existing_gle_currency else None + + return frappe.local_cache("party_gle_currency", (party_type, party, company), generator) + +def validate_party_gle_currency(party_type, party, company): + """Validate party account currency with existing GL Entry's currency""" + party_account_currency = get_party_account_currency(party_type, party, company) + existing_gle_currency = get_party_gle_currency(party_type, party, company) + + if existing_gle_currency and party_account_currency != existing_gle_currency: + frappe.throw(_("Accounting Entry for {0}: {1} can only be made in currency: {2}") + .format(party_type, party, existing_gle_currency), InvalidAccountCurrency) + +def validate_party_accounts(doc): + companies = [] + + for account in doc.get("accounts"): + if account.company in companies: + frappe.throw(_("There can only be 1 Account per Company in {0} {1}").format(doc.doctype, doc.name), + DuplicatePartyAccountError) + else: + companies.append(account.company) + @frappe.whitelist() def get_due_date(posting_date, party_type, party, company): """Set Due Date = Posting Date + Credit Days""" diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index fd91929a76a..1229a052637 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe from frappe.utils import flt, getdate, cstr from frappe import _ +from erpnext.accounts.utils import get_account_currency def execute(filters=None): account_details = {} @@ -12,10 +13,10 @@ def execute(filters=None): account_details.setdefault(acc.name, acc) validate_filters(filters, account_details) - + validate_party(filters) - - filters = set_account_currency(filters) + + filters = set_account_currency(filters) columns = get_columns(filters) @@ -46,49 +47,49 @@ def validate_party(filters): frappe.throw(_("To filter based on Party, select Party Type first")) elif not frappe.db.exists(party_type, party): frappe.throw(_("Invalid {0}: {1}").format(party_type, party)) - + def set_account_currency(filters): if not (filters.get("account") or filters.get("party")): return filters else: filters["company_currency"] = frappe.db.get_value("Company", filters.company, "default_currency") account_currency = None - + if filters.get("account"): - account_currency = frappe.db.get_value("Account", filters.account, "account_currency") + account_currency = get_account_currency(filters.account) elif filters.get("party"): - gle_currency = frappe.db.get_value("GL Entry", {"party_type": filters.party_type, + gle_currency = frappe.db.get_value("GL Entry", {"party_type": filters.party_type, "party": filters.party, "company": filters.company}, "account_currency") if gle_currency: account_currency = gle_currency else: account_currency = frappe.db.get_value(filters.party_type, filters.party, "default_currency") - + filters["account_currency"] = account_currency or filters.company_currency - + if filters.account_currency != filters.company_currency: filters["show_in_account_currency"] = 1 - + return filters - + def get_columns(filters): columns = [ _("Posting Date") + ":Date:90", _("Account") + ":Link/Account:200", _("Debit") + ":Float:100", _("Credit") + ":Float:100" ] - + if filters.get("show_in_account_currency"): columns += [ - _("Debit") + " (" + filters.account_currency + ")" + ":Float:100", + _("Debit") + " (" + filters.account_currency + ")" + ":Float:100", _("Credit") + " (" + filters.account_currency + ")" + ":Float:100" ] - + columns += [ _("Voucher Type") + "::120", _("Voucher No") + ":Dynamic Link/Voucher Type:160", _("Against Account") + "::120", _("Party Type") + "::80", _("Party") + "::150", _("Cost Center") + ":Link/Cost Center:100", _("Remarks") + "::400" ] - + return columns def get_result(filters, account_details): @@ -101,21 +102,21 @@ def get_result(filters, account_details): return result def get_gl_entries(filters): - select_fields = """, sum(ifnull(debit_in_account_currency, 0)) as debit_in_account_currency, + select_fields = """, sum(ifnull(debit_in_account_currency, 0)) as debit_in_account_currency, sum(ifnull(credit_in_account_currency, 0)) as credit_in_account_currency""" \ if filters.get("show_in_account_currency") else "" - + group_by_condition = "group by voucher_type, voucher_no, account, cost_center" \ if filters.get("group_by_voucher") else "group by name" gl_entries = frappe.db.sql("""select posting_date, account, party_type, party, - sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit, + sum(ifnull(debit, 0)) as debit, sum(ifnull(credit, 0)) as credit, voucher_type, voucher_no, cost_center, remarks, against, is_opening {select_fields} from `tabGL Entry` where company=%(company)s {conditions} {group_by_condition} order by posting_date, account"""\ - .format(select_fields=select_fields, conditions=get_conditions(filters), + .format(select_fields=select_fields, conditions=get_conditions(filters), group_by_condition=group_by_condition), filters, as_dict=1) return gl_entries @@ -135,7 +136,7 @@ def get_conditions(filters): if filters.get("party"): conditions.append("party=%(party)s") - + if not (filters.get("account") or filters.get("party") or filters.get("group_by_account")): conditions.append("posting_date >=%(from_date)s") @@ -160,7 +161,7 @@ def get_data_with_opening_closing(filters, account_details, gl_entries): if acc_dict.entries: # Opening for individual ledger, if grouped by account if filters.get("group_by_account"): - data.append(get_balance_row(_("Opening"), acc_dict.opening, + data.append(get_balance_row(_("Opening"), acc_dict.opening, acc_dict.opening_in_account_currency)) data += acc_dict.entries @@ -170,7 +171,7 @@ def get_data_with_opening_closing(filters, account_details, gl_entries): account_closing = acc_dict.opening + acc_dict.total_debit - acc_dict.total_credit account_closing_in_account_currency = acc_dict.opening_in_account_currency \ + acc_dict.total_debit_in_account_currency - acc_dict.total_credit_in_account_currency - + data += [{"account": "'" + _("Totals") + "'", "debit": acc_dict.total_debit, "credit": acc_dict.total_credit}, get_balance_row(_("Closing (Opening + Totals)"), @@ -179,10 +180,10 @@ def get_data_with_opening_closing(filters, account_details, gl_entries): # Total debit and credit between from and to date if total_debit or total_credit: data.append({ - "account": "'" + _("Totals") + "'", - "debit": total_debit, + "account": "'" + _("Totals") + "'", + "debit": total_debit, "credit": total_credit, - "debit_in_account_currency": total_debit_in_account_currency, + "debit_in_account_currency": total_debit_in_account_currency, "credit_in_account_currency": total_credit_in_account_currency }) @@ -191,7 +192,7 @@ def get_data_with_opening_closing(filters, account_details, gl_entries): closing = opening + total_debit - total_credit closing_in_account_currency = opening_in_account_currency + \ total_debit_in_account_currency - total_credit_in_account_currency - + data.append(get_balance_row(_("Closing (Opening + Totals)"), closing, closing_in_account_currency)) @@ -216,38 +217,38 @@ def initialize_gle_map(gl_entries): def get_accountwise_gle(filters, gl_entries, gle_map): opening, total_debit, total_credit = 0, 0, 0 opening_in_account_currency, total_debit_in_account_currency, total_credit_in_account_currency = 0, 0, 0 - + from_date, to_date = getdate(filters.from_date), getdate(filters.to_date) for gle in gl_entries: amount = flt(gle.debit, 3) - flt(gle.credit, 3) amount_in_account_currency = flt(gle.debit_in_account_currency, 3) - flt(gle.credit_in_account_currency, 3) - + if (filters.get("account") or filters.get("party") or filters.get("group_by_account")) \ and (gle.posting_date < from_date or cstr(gle.is_opening) == "Yes"): - + gle_map[gle.account].opening += amount if filters.get("show_in_account_currency"): gle_map[gle.account].opening_in_account_currency += amount_in_account_currency - + if filters.get("account") or filters.get("party"): opening += amount if filters.get("show_in_account_currency"): opening_in_account_currency += amount_in_account_currency - + elif gle.posting_date <= to_date: gle_map[gle.account].entries.append(gle) gle_map[gle.account].total_debit += flt(gle.debit, 3) gle_map[gle.account].total_credit += flt(gle.credit, 3) - + total_debit += flt(gle.debit, 3) total_credit += flt(gle.credit, 3) - + if filters.get("show_in_account_currency"): gle_map[gle.account].total_debit_in_account_currency += flt(gle.debit_in_account_currency, 3) gle_map[gle.account].total_credit_in_account_currency += flt(gle.credit_in_account_currency, 3) - + total_debit_in_account_currency += flt(gle.debit_in_account_currency, 3) - total_credit_in_account_currency += flt(gle.credit_in_account_currency, 3) + total_credit_in_account_currency += flt(gle.credit_in_account_currency, 3) return opening, total_debit, total_credit, opening_in_account_currency, \ total_debit_in_account_currency, total_credit_in_account_currency, gle_map @@ -258,27 +259,27 @@ def get_balance_row(label, balance, balance_in_account_currency=None): "debit": balance if balance > 0 else 0, "credit": -1*balance if balance < 0 else 0 } - + if balance_in_account_currency != None: balance_row.update({ "debit_in_account_currency": balance_in_account_currency if balance_in_account_currency > 0 else 0, "credit_in_account_currency": -1*balance_in_account_currency if balance_in_account_currency < 0 else 0 }) - + return balance_row def get_result_as_list(data, filters): result = [] for d in data: row = [d.get("posting_date"), d.get("account"), d.get("debit"), d.get("credit")] - + if filters.get("show_in_account_currency"): row += [d.get("debit_in_account_currency"), d.get("credit_in_account_currency")] - - row += [d.get("voucher_type"), d.get("voucher_no"), d.get("against"), + + row += [d.get("voucher_type"), d.get("voucher_no"), d.get("against"), d.get("party_type"), d.get("party"), d.get("cost_center"), d.get("remarks") ] - + result.append(row) return result diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 645c91c8f7b..2a77fa1465e 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -9,6 +9,9 @@ from frappe import throw, _ from frappe.utils import formatdate import frappe.desk.reportview +# imported to enable erpnext.accounts.utils.get_account_currency +from erpnext.accounts.doctype.account.account import get_account_currency + class FiscalYearError(frappe.ValidationError): pass class BudgetError(frappe.ValidationError): pass @@ -94,8 +97,8 @@ def get_balance_on(account=None, date=None, party_type=None, party=None, in_acco select name from `tabAccount` ac where ac.name = gle.account and ac.lft >= %s and ac.rgt <= %s )""" % (acc.lft, acc.rgt)) - - # If group and currency same as company, + + # If group and currency same as company, # always return balance based on debit and credit in company currency if acc.account_currency == frappe.db.get_value("Company", acc.company, "default_currency"): in_account_currency = False diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json index 2c337a8fa8b..4607d4a4b8b 100644 --- a/erpnext/buying/doctype/supplier/supplier.json +++ b/erpnext/buying/doctype/supplier/supplier.json @@ -1,688 +1,665 @@ { - "allow_copy": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "naming_series:", - "creation": "2013-01-10 16:34:11", - "custom": 0, - "description": "Supplier of Goods or Services.", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", + "allow_copy": 0, + "allow_import": 1, + "allow_rename": 1, + "autoname": "naming_series:", + "creation": "2013-01-10 16:34:11", + "custom": 0, + "description": "Supplier of Goods or Services.", + "docstatus": 0, + "doctype": "DocType", + "document_type": "Setup", "fields": [ { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "basic_info", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "", - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "icon-user", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "basic_info", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "", + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "icon-user", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Series", - "no_copy": 1, - "oldfieldname": "naming_series", - "oldfieldtype": "Select", - "options": "SUPP-", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "naming_series", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Series", + "no_copy": 1, + "oldfieldname": "naming_series", + "oldfieldtype": "Select", + "options": "SUPP-", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "supplier_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Supplier Name", - "no_copy": 1, - "oldfieldname": "supplier_name", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "supplier_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Supplier Name", + "no_copy": 1, + "oldfieldname": "supplier_name", + "oldfieldtype": "Data", + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "column_break0", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "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, + "fieldname": "column_break0", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "supplier_type", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 1, - "label": "Supplier Type", - "no_copy": 0, - "oldfieldname": "supplier_type", - "oldfieldtype": "Link", - "options": "Supplier Type", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "supplier_type", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Supplier Type", + "no_copy": 0, + "oldfieldname": "supplier_type", + "oldfieldtype": "Link", + "options": "Supplier Type", + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "is_frozen", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Is Frozen", - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "is_frozen", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Is Frozen", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "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, - "fieldname": "section_break_7", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "section_break_7", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "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, - "fieldname": "default_currency", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "in_filter": 0, - "in_list_view": 0, - "label": "Billing Currency", - "no_copy": 1, - "options": "Currency", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "default_currency", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "in_filter": 0, + "in_list_view": 0, + "label": "Billing Currency", + "no_copy": 1, + "options": "Currency", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "default_price_list", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "in_filter": 0, - "in_list_view": 0, - "label": "Price List", - "no_copy": 0, - "options": "Price List", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "default_price_list", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "in_filter": 0, + "in_list_view": 0, + "label": "Price List", + "no_copy": 0, + "options": "Price List", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "column_break_10", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "column_break_10", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "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, - "fieldname": "default_taxes_and_charges", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "in_filter": 0, - "in_list_view": 0, - "label": "Taxes and Charges", - "no_copy": 0, - "options": "Purchase Taxes and Charges Template", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "default_taxes_and_charges", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "in_filter": 0, + "in_list_view": 0, + "label": "Taxes and Charges", + "no_copy": 0, + "options": "Purchase Taxes and Charges Template", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "credit_days", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Credit Days", - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "credit_days", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Credit Days", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "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": "eval:!doc.__islocal", - "fieldname": "address_contacts", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Address and Contacts", - "no_copy": 0, - "oldfieldtype": "Column Break", - "options": "icon-map-marker", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "depends_on": "eval:!doc.__islocal", + "fieldname": "address_contacts", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Address and Contacts", + "no_copy": 0, + "oldfieldtype": "Column Break", + "options": "icon-map-marker", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "address_html", - "fieldtype": "HTML", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Address HTML", - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "read_only": 1, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "address_html", + "fieldtype": "HTML", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Address HTML", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "column_break1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "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, + "fieldname": "column_break1", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "contact_html", - "fieldtype": "HTML", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Contact HTML", - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "read_only": 1, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "contact_html", + "fieldtype": "HTML", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Contact HTML", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "accounts", - "fieldname": "default_payable_accounts", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Default Payable Accounts", - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "accounts", + "fieldname": "default_payable_accounts", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Default Payable Accounts", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "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, - "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, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "depends_on": "", + "description": "Mention if non-standard receivable account", + "fieldname": "accounts", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Accounts", + "no_copy": 0, + "options": "Party Account", + "permlevel": 0, + "print_hide": 0, + "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", - "fieldname": "accounts", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Accounts", - "no_copy": 0, - "options": "Party Account", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "supplier_details", - "fieldname": "column_break2", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Supplier Details", - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "supplier_details", + "fieldname": "column_break2", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Supplier Details", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "website", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Website", - "no_copy": 0, - "oldfieldname": "website", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "website", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Website", + "no_copy": 0, + "oldfieldname": "website", + "oldfieldtype": "Data", + "permlevel": 0, + "print_hide": 0, + "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, - "description": "Statutory info and other general information about your Supplier", - "fieldname": "supplier_details", - "fieldtype": "Text", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Supplier Details", - "no_copy": 0, - "oldfieldname": "supplier_details", - "oldfieldtype": "Code", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "description": "Statutory info and other general information about your Supplier", + "fieldname": "supplier_details", + "fieldtype": "Text", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Supplier Details", + "no_copy": 0, + "oldfieldname": "supplier_details", + "oldfieldtype": "Code", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "communications", - "fieldtype": "Table", - "hidden": 1, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Communications", - "no_copy": 0, - "options": "Communication", - "permlevel": 0, - "print_hide": 1, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "communications", + "fieldtype": "Table", + "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Communications", + "no_copy": 0, + "options": "Communication", + "permlevel": 0, + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 } - ], - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "icon-user", - "idx": 1, - "in_create": 0, - "in_dialog": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "modified": "2015-09-17 14:05:24.793609", - "modified_by": "Administrator", - "module": "Buying", - "name": "Supplier", - "owner": "Administrator", + ], + "hide_heading": 0, + "hide_toolbar": 0, + "icon": "icon-user", + "idx": 1, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "modified": "2015-09-25 06:34:56.909099", + "modified_by": "Administrator", + "module": "Buying", + "name": "Supplier", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Purchase User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Purchase User", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 0 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Purchase Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Purchase Manager", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 0 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Purchase Master Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Purchase Master Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, "write": 1 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 0, - "read": 1, - "report": 0, - "role": "Stock User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 0, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 0, + "read": 1, + "report": 0, + "role": "Stock User", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 0 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Stock Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock Manager", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 0 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 0, - "read": 1, - "report": 0, - "role": "Accounts User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 0, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 0, + "read": 1, + "report": 0, + "role": "Accounts User", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 0 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Accounts Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts Manager", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 0 } - ], - "read_only": 0, - "read_only_onload": 0, - "search_fields": "supplier_name, supplier_type", + ], + "read_only": 0, + "read_only_onload": 0, + "search_fields": "supplier_name, supplier_type", "title_field": "supplier_name" -} +} \ No newline at end of file diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py index 6d0a1a35592..6ae0a2ea511 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_accounting_currency, validate_party_account +from erpnext.accounts.party import validate_party_accounts class Supplier(TransactionBase): def get_feed(self): @@ -45,9 +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_accounting_currency(self) - validate_party_account(self) + + validate_party_accounts(self) def get_contacts(self,nm): if nm: @@ -96,14 +95,14 @@ def get_dashboard_info(supplier): billing_this_year = frappe.db.sql(""" select sum(ifnull(credit_in_account_currency, 0)) - sum(ifnull(debit_in_account_currency, 0)) from `tabGL Entry` - where voucher_type='Purchase Invoice' and party_type = 'Supplier' - and party=%s and fiscal_year = %s""", + where voucher_type='Purchase Invoice' and party_type = 'Supplier' + and party=%s and fiscal_year = %s""", (supplier, frappe.db.get_default("fiscal_year"))) - + total_unpaid = frappe.db.sql("""select sum(outstanding_amount) from `tabPurchase Invoice` where supplier=%s and docstatus = 1""", supplier) - + out["billing_this_year"] = billing_this_year[0][0] if billing_this_year else 0 out["total_unpaid"] = total_unpaid[0][0] if total_unpaid else 0 diff --git a/erpnext/buying/doctype/supplier/test_records.json b/erpnext/buying/doctype/supplier/test_records.json index 6d01dffb614..f335d5c4230 100644 --- a/erpnext/buying/doctype/supplier/test_records.json +++ b/erpnext/buying/doctype/supplier/test_records.json @@ -1,22 +1,21 @@ [ { - "doctype": "Supplier", - "supplier_name": "_Test Supplier", + "doctype": "Supplier", + "supplier_name": "_Test Supplier", "supplier_type": "_Test Supplier Type" }, { - "doctype": "Supplier", - "supplier_name": "_Test Supplier 1", + "doctype": "Supplier", + "supplier_name": "_Test Supplier 1", "supplier_type": "_Test Supplier Type" }, { - "doctype": "Supplier", - "supplier_name": "_Test Supplier USD", + "doctype": "Supplier", + "supplier_name": "_Test Supplier USD", "supplier_type": "_Test Supplier Type", - "party_account_currency": "USD", "accounts": [{ "company": "_Test Company", "account": "_Test Payable USD - _TC" }] } -] \ No newline at end of file +] diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 26203857086..a92d0707808 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -6,16 +6,15 @@ import frappe from frappe import _, throw from frappe.utils import today, flt, cint from erpnext.setup.utils import get_company_currency, get_exchange_rate -from erpnext.accounts.utils import get_fiscal_year, validate_fiscal_year +from erpnext.accounts.utils import get_fiscal_year, validate_fiscal_year, get_account_currency from erpnext.utilities.transaction_base import TransactionBase from erpnext.controllers.recurring_document import convert_to_recurring, validate_recurring_document from erpnext.controllers.sales_and_purchase_return import validate_return +from erpnext.accounts.party import get_party_account_currency, validate_party_gle_currency +from erpnext.exceptions import CustomerFrozen, InvalidCurrency force_item_fields = ("item_group", "barcode", "brand", "stock_uom") -class CustomerFrozen(frappe.ValidationError): pass -class InvalidCurrency(frappe.ValidationError): pass - class AccountsController(TransactionBase): def __init__(self, arg1, arg2=None): super(AccountsController, self).__init__(arg1, arg2) @@ -220,7 +219,7 @@ class AccountsController(TransactionBase): gl_dict.update(args) if not account_currency: - account_currency = frappe.db.get_value("Account", gl_dict.account, "account_currency") + account_currency = get_account_currency(gl_dict.account) if self.doctype != "Journal Entry": self.validate_account_currency(gl_dict.account, account_currency) @@ -427,8 +426,7 @@ class AccountsController(TransactionBase): if self.get("currency"): party_type, party = self.get_party() if party_type and party: - party_account_currency = frappe.db.get_value(party_type, party, "party_account_currency") \ - or self.company_currency + party_account_currency = get_party_account_currency(party_type, party, self.company) 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}") diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index 5cf96e99044..866b9827168 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -7,8 +7,8 @@ from frappe.utils import cstr, cint from frappe import msgprint, _ from frappe.model.mapper import get_mapped_doc from erpnext.setup.utils import get_exchange_rate - from erpnext.utilities.transaction_base import TransactionBase +from erpnext.accounts.party import get_party_account_currency subject_field = "title" sender_field = "contact_email" @@ -180,9 +180,10 @@ def get_item_details(item_code): def make_quotation(source_name, target_doc=None): def set_missing_values(source, target): quotation = frappe.get_doc(target) - + company_currency = frappe.db.get_value("Company", quotation.company, "default_currency") - party_account_currency = frappe.db.get_value("Customer", quotation.customer, "party_account_currency") + party_account_currency = get_party_account_currency("Customer", quotation.customer, quotation.company) + if company_currency == party_account_currency: exchange_rate = 1 else: @@ -190,7 +191,7 @@ def make_quotation(source_name, target_doc=None): quotation.currency = party_account_currency or company_currency quotation.conversion_rate = exchange_rate - + quotation.run_method("set_missing_values") quotation.run_method("calculate_taxes_and_totals") diff --git a/erpnext/exceptions.py b/erpnext/exceptions.py new file mode 100644 index 00000000000..c339edf2398 --- /dev/null +++ b/erpnext/exceptions.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals +import frappe + +# accounts +class CustomerFrozen(frappe.ValidationError): pass +class InvalidAccountCurrency(frappe.ValidationError): pass +class InvalidCurrency(frappe.ValidationError): pass diff --git a/erpnext/patches/v6_0/multi_currency.py b/erpnext/patches/v6_0/multi_currency.py index 242df94258b..b4c37fc2530 100644 --- a/erpnext/patches/v6_0/multi_currency.py +++ b/erpnext/patches/v6_0/multi_currency.py @@ -63,56 +63,3 @@ def execute(): where company=%s """, (company.default_currency, company.name)) - - # Set party account if default currency of party other than company's default currency - for dt in ("Customer", "Supplier"): - parties = frappe.get_all(dt, filters={"docstatus": 0}) - for p in parties: - party = frappe.get_doc(dt, p.name) - party_accounts = [] - - for company in company_list: - # Get party GL Entries - party_gle = frappe.db.get_value("GL Entry", {"party_type": dt, "party": p.name, - "company": company.name}, ["account", "account_currency", "name"], as_dict=True) - - # set party account currency - if party_gle: - party.party_account_currency = party_gle.account_currency - elif not party.party_account_currency: - party.party_account_currency = company.default_currency - - # Add default receivable /payable account if not exists - # and currency is other than company currency - if party.party_account_currency and party.party_account_currency != company.default_currency: - party_account_exists_for_company = False - for d in party.get("accounts"): - if d.company == company.name: - account_currency = frappe.db.get_value("Account", d.account, "account_currency") - if account_currency == party.party_account_currency: - party_accounts.append({ - "company": d.company, - "account": d.account - }) - party_account_exists_for_company = True - break - - if not party_account_exists_for_company: - party_account = None - if party_gle: - party_account = party_gle.account - else: - default_receivable_account_currency = frappe.db.get_value("Account", - company.default_receivable_account, "account_currency") - if default_receivable_account_currency != company.default_currency: - party_account = company.default_receivable_account - - if party_account: - party_accounts.append({ - "company": company.name, - "account": party_account - }) - - party.set("accounts", party_accounts) - party.flags.ignore_mandatory = True - party.save() diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json index 51ddc46bca3..272964c2b6f 100644 --- a/erpnext/selling/doctype/customer/customer.json +++ b/erpnext/selling/doctype/customer/customer.json @@ -1,1013 +1,990 @@ { - "allow_copy": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "naming_series:", - "creation": "2013-06-11 14:26:44", - "custom": 0, - "description": "Buyer of Goods and Services.", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", + "allow_copy": 0, + "allow_import": 1, + "allow_rename": 1, + "autoname": "naming_series:", + "creation": "2013-06-11 14:26:44", + "custom": 0, + "description": "Buyer of Goods and Services.", + "docstatus": 0, + "doctype": "DocType", + "document_type": "Setup", "fields": [ { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "basic_info", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "", - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "icon-user", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "basic_info", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "", + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "icon-user", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Series", - "no_copy": 1, - "options": "CUST-", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "naming_series", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Series", + "no_copy": 1, + "options": "CUST-", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "customer_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 1, - "in_list_view": 0, - "label": "Full Name", - "no_copy": 1, - "oldfieldname": "customer_name", - "oldfieldtype": "Data", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "customer_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 1, + "in_list_view": 0, + "label": "Full Name", + "no_copy": 1, + "oldfieldname": "customer_name", + "oldfieldtype": "Data", + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 1, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "customer_type", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Type", - "no_copy": 0, - "oldfieldname": "customer_type", - "oldfieldtype": "Select", - "options": "\nCompany\nIndividual", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "customer_type", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Type", + "no_copy": 0, + "oldfieldname": "customer_type", + "oldfieldtype": "Select", + "options": "\nCompany\nIndividual", + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "lead_name", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 1, - "in_list_view": 0, - "label": "From Lead", - "no_copy": 1, - "oldfieldname": "lead_name", - "oldfieldtype": "Link", - "options": "Lead", - "permlevel": 0, - "print_hide": 1, - "read_only": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "lead_name", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 1, + "in_list_view": 0, + "label": "From Lead", + "no_copy": 1, + "oldfieldname": "lead_name", + "oldfieldtype": "Link", + "options": "Lead", + "permlevel": 0, + "print_hide": 1, + "read_only": 0, + "report_hide": 1, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "column_break0", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "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, + "fieldname": "column_break0", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "description": "", - "fieldname": "customer_group", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 1, - "in_list_view": 1, - "label": "Customer Group", - "no_copy": 0, - "oldfieldname": "customer_group", - "oldfieldtype": "Link", - "options": "Customer Group", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "description": "", + "fieldname": "customer_group", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 1, + "in_list_view": 1, + "label": "Customer Group", + "no_copy": 0, + "oldfieldname": "customer_group", + "oldfieldtype": "Link", + "options": "Customer Group", + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 1, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "description": "", - "fieldname": "territory", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 1, - "label": "Territory", - "no_copy": 0, - "oldfieldname": "territory", - "oldfieldtype": "Link", - "options": "Territory", - "permlevel": 0, - "print_hide": 1, - "read_only": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "description": "", + "fieldname": "territory", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Territory", + "no_copy": 0, + "oldfieldname": "territory", + "oldfieldtype": "Link", + "options": "Territory", + "permlevel": 0, + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "tax_id", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Tax ID", - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "tax_id", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Tax ID", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "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, - "fieldname": "is_frozen", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Is Frozen", - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "is_frozen", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Is Frozen", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "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, - "fieldname": "currency_and_price_list", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "", - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "currency_and_price_list", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "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, - "fieldname": "default_currency", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "in_filter": 0, - "in_list_view": 0, - "label": "Billing Currency", - "no_copy": 1, - "options": "Currency", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "default_currency", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "in_filter": 0, + "in_list_view": 0, + "label": "Billing Currency", + "no_copy": 1, + "options": "Currency", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "default_price_list", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "in_filter": 0, - "in_list_view": 0, - "label": "Default Price List", - "no_copy": 0, - "options": "Price List", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "default_price_list", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "in_filter": 0, + "in_list_view": 0, + "label": "Default Price List", + "no_copy": 0, + "options": "Price List", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "column_break_14", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "column_break_14", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "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, - "fieldname": "default_taxes_and_charges", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "in_filter": 0, - "in_list_view": 0, - "label": "Default Taxes and Charges", - "no_copy": 0, - "options": "Sales Taxes and Charges Template", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "default_taxes_and_charges", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "in_filter": 0, + "in_list_view": 0, + "label": "Default Taxes and Charges", + "no_copy": 0, + "options": "Sales Taxes and Charges Template", + "permlevel": 0, + "print_hide": 0, + "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": "eval:!doc.__islocal", - "fieldname": "address_contacts", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Address and Contact", - "no_copy": 0, - "options": "icon-map-marker", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "depends_on": "eval:!doc.__islocal", + "fieldname": "address_contacts", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Address and Contact", + "no_copy": 0, + "options": "icon-map-marker", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "address_html", - "fieldtype": "HTML", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Address HTML", - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "read_only": 1, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "address_html", + "fieldtype": "HTML", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Address HTML", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "column_break1", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "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, + "fieldname": "column_break1", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "contact_html", - "fieldtype": "HTML", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Contact HTML", - "no_copy": 0, - "oldfieldtype": "HTML", - "permlevel": 0, - "print_hide": 0, - "read_only": 1, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "contact_html", + "fieldtype": "HTML", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Contact HTML", + "no_copy": 0, + "oldfieldtype": "HTML", + "permlevel": 0, + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "accounts", - "fieldname": "default_receivable_accounts", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Default Receivable Accounts", - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "accounts", + "fieldname": "default_receivable_accounts", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Default Receivable Accounts", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "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, - "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, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "depends_on": "", + "description": "Mention if non-standard receivable account", + "fieldname": "accounts", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Accounts", + "no_copy": 0, + "options": "Party Account", + "permlevel": 0, + "print_hide": 0, + "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", - "fieldname": "accounts", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Accounts", - "no_copy": 0, - "options": "Party Account", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "eval:doc.credit_days || doc.credit_limit", - "fieldname": "column_break2", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Credit Limit", - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "eval:doc.credit_days || doc.credit_limit", + "fieldname": "column_break2", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Credit Limit", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "fieldname": "credit_days_based_on", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Credit Days Based On", - "no_copy": 0, - "options": "\nFixed Days\nLast Day of the Next Month", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "credit_days_based_on", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Credit Days Based On", + "no_copy": 0, + "options": "\nFixed Days\nLast Day of the Next Month", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "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": "eval:doc.credit_days_based_on=='Fixed Days'", - "fieldname": "credit_days", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Credit Days", - "no_copy": 0, - "oldfieldname": "credit_days", - "oldfieldtype": "Int", - "permlevel": 1, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "depends_on": "eval:doc.credit_days_based_on=='Fixed Days'", + "fieldname": "credit_days", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Credit Days", + "no_copy": 0, + "oldfieldname": "credit_days", + "oldfieldtype": "Int", + "permlevel": 1, + "print_hide": 0, + "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, - "fieldname": "credit_limit", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Credit Limit", - "no_copy": 0, - "oldfieldname": "credit_limit", - "oldfieldtype": "Currency", - "options": "", - "permlevel": 1, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "credit_limit", + "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Credit Limit", + "no_copy": 0, + "oldfieldname": "credit_limit", + "oldfieldtype": "Currency", + "options": "", + "permlevel": 1, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "customer_details", - "fieldname": "more_info", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Customer Details", - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "icon-file-text", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "customer_details", + "fieldname": "more_info", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Details", + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "icon-file-text", + "permlevel": 0, + "print_hide": 0, + "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, - "description": "Additional information regarding the customer.", - "fieldname": "customer_details", - "fieldtype": "Text", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Customer Details", - "no_copy": 0, - "oldfieldname": "customer_details", - "oldfieldtype": "Code", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "description": "Additional information regarding the customer.", + "fieldname": "customer_details", + "fieldtype": "Text", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Customer Details", + "no_copy": 0, + "oldfieldname": "customer_details", + "oldfieldtype": "Code", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "website", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Website", - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "website", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Website", + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "default_sales_partner", - "fieldname": "sales_team_section_break", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Sales Partner and Commission", - "no_copy": 0, - "oldfieldtype": "Section Break", - "options": "icon-group", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "default_sales_partner", + "fieldname": "sales_team_section_break", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Sales Partner and Commission", + "no_copy": 0, + "oldfieldtype": "Section Break", + "options": "icon-group", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "default_sales_partner", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "in_filter": 0, - "in_list_view": 0, - "label": "Sales Partner", - "no_copy": 0, - "oldfieldname": "default_sales_partner", - "oldfieldtype": "Link", - "options": "Sales Partner", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "default_sales_partner", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 1, + "in_filter": 0, + "in_list_view": 0, + "label": "Sales Partner", + "no_copy": 0, + "oldfieldname": "default_sales_partner", + "oldfieldtype": "Link", + "options": "Sales Partner", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "default_commission_rate", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Commission Rate", - "no_copy": 0, - "oldfieldname": "default_commission_rate", - "oldfieldtype": "Currency", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "default_commission_rate", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Commission Rate", + "no_copy": 0, + "oldfieldname": "default_commission_rate", + "oldfieldtype": "Currency", + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "collapsible_depends_on": "sales_team", - "fieldname": "sales_team_section", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Sales Team", - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "collapsible_depends_on": "sales_team", + "fieldname": "sales_team_section", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Sales Team", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "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, - "fieldname": "sales_team", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Sales Team Details", - "no_copy": 0, - "oldfieldname": "sales_team", - "oldfieldtype": "Table", - "options": "Sales Team", - "permlevel": 0, - "print_hide": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "sales_team", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Sales Team Details", + "no_copy": 0, + "oldfieldname": "sales_team", + "oldfieldtype": "Table", + "options": "Sales Team", + "permlevel": 0, + "print_hide": 0, + "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, - "fieldname": "communications", - "fieldtype": "Table", - "hidden": 1, - "ignore_user_permissions": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Communications", - "no_copy": 0, - "options": "Communication", - "permlevel": 0, - "print_hide": 1, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "fieldname": "communications", + "fieldtype": "Table", + "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Communications", + "no_copy": 0, + "options": "Communication", + "permlevel": 0, + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, "unique": 0 } - ], - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "icon-user", - "idx": 1, - "in_create": 0, - "in_dialog": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "modified": "2015-09-17 14:05:38.541266", - "modified_by": "Administrator", - "module": "Selling", - "name": "Customer", - "owner": "Administrator", + ], + "hide_heading": 0, + "hide_toolbar": 0, + "icon": "icon-user", + "idx": 1, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "modified": "2015-09-25 06:25:13.944742", + "modified_by": "Administrator", + "module": "Selling", + "name": "Customer", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Sales User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Sales User", + "set_user_permissions": 0, + "share": 1, + "submit": 0, "write": 1 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 1, - "print": 0, - "read": 1, - "report": 0, - "role": "Sales User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 0, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 1, + "print": 0, + "read": 1, + "report": 0, + "role": "Sales User", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 0 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Sales Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Sales Manager", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 0 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Sales Master Manager", - "set_user_permissions": 1, - "share": 1, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Sales Master Manager", + "set_user_permissions": 1, + "share": 1, + "submit": 0, "write": 1 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 1, - "print": 0, - "read": 1, - "report": 0, - "role": "Sales Master Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 0, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 1, + "print": 0, + "read": 1, + "report": 0, + "role": "Sales Master Manager", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 1 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Stock User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock User", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 0 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Stock Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Stock Manager", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 0 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Accounts User", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 0 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Accounts Manager", - "set_user_permissions": 0, - "share": 0, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts Manager", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 0 } - ], - "read_only": 0, - "read_only_onload": 0, - "search_fields": "customer_name,customer_group,territory", + ], + "read_only": 0, + "read_only_onload": 0, + "search_fields": "customer_name,customer_group,territory", "title_field": "customer_name" -} +} \ No newline at end of file diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index dcff06d4db6..9e5e7bdc7ed 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -7,11 +7,10 @@ from frappe.model.naming import make_autoname from frappe import _, msgprint, throw import frappe.defaults from frappe.utils import flt - +from frappe.desk.reportview import build_match_conditions from erpnext.utilities.transaction_base import TransactionBase from erpnext.utilities.address_and_contact import load_address_and_contact -from erpnext.accounts.party import validate_accounting_currency, validate_party_account -from frappe.desk.reportview import build_match_conditions +from erpnext.accounts.party import validate_party_accounts class Customer(TransactionBase): def get_feed(self): @@ -33,8 +32,7 @@ class Customer(TransactionBase): def validate(self): self.flags.is_new_doc = self.is_new() - validate_accounting_currency(self) - validate_party_account(self) + validate_party_accounts(self) def update_lead_status(self): if self.lead_name: diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py index a0a1501a467..f18194f3ab3 100644 --- a/erpnext/selling/doctype/customer/test_customer.py +++ b/erpnext/selling/doctype/customer/test_customer.py @@ -7,9 +7,7 @@ import frappe import unittest from frappe.test_runner import make_test_records -from erpnext.controllers.accounts_controller import CustomerFrozen -from erpnext.accounts.party import InvalidCurrency -from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice +from erpnext.exceptions import CustomerFrozen test_ignore = ["Price List"] @@ -37,9 +35,9 @@ class TestCustomer(unittest.TestCase): make_test_records("Address") make_test_records("Contact") - frappe.db.set_value("Contact", "_Test Contact For _Test Customer-_Test Customer", + frappe.db.set_value("Contact", "_Test Contact For _Test Customer-_Test Customer", "is_primary_contact", 1) - + details = get_party_details("_Test Customer") for key, value in to_check.iteritems(): @@ -68,25 +66,15 @@ class TestCustomer(unittest.TestCase): {"comment_doctype": "Customer", "comment_docname": "_Test Customer 1 Renamed"}), comment.name) frappe.rename_doc("Customer", "_Test Customer 1 Renamed", "_Test Customer 1") - + def test_freezed_customer(self): frappe.db.set_value("Customer", "_Test Customer", "is_frozen", 1) - + from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order - + so = make_sales_order(do_not_save= True) self.assertRaises(CustomerFrozen, so.save) - + frappe.db.set_value("Customer", "_Test Customer", "is_frozen", 0) - + so.save() - - def test_multi_currency(self): - customer = frappe.get_doc("Customer", "_Test Customer USD") - - create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC", - currency="USD", conversion_rate=50) - - customer.party_account_currency = "EUR" - self.assertRaises(InvalidCurrency, customer.save) - \ No newline at end of file diff --git a/erpnext/selling/doctype/customer/test_records.json b/erpnext/selling/doctype/customer/test_records.json index 060633ec4f6..94f14ed6fb0 100644 --- a/erpnext/selling/doctype/customer/test_records.json +++ b/erpnext/selling/doctype/customer/test_records.json @@ -33,7 +33,6 @@ "customer_type": "Individual", "doctype": "Customer", "territory": "_Test Territory", - "party_account_currency": "USD", "accounts": [{ "company": "_Test Company", "account": "_Test Receivable USD - _TC" diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index ccb792f1112..ba5f025cfe0 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -7,6 +7,8 @@ import frappe.permissions import unittest from erpnext.selling.doctype.sales_order.sales_order \ import make_material_request, make_delivery_note, make_sales_invoice, WarehouseRequired +from erpnext.accounts.doctype.journal_entry.test_journal_entry \ + import make_journal_entry from frappe.tests.test_permissions import set_user_permission_doctypes diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 785e7aa6fa7..d3378053445 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -46,13 +46,13 @@ 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.")) + frappe.throw(_("Cannot change company's default currency, because there are existing transactions. Transactions must be cancelled to change the default currency.")) def on_update(self): if not frappe.db.sql("""select name from tabAccount @@ -208,7 +208,7 @@ class Company(Document): # clear default accounts, warehouses from item if warehouses: - + for f in ["default_warehouse", "website_warehouse"]: frappe.db.sql("""update tabItem set %s=NULL where %s in (%s)""" % (f, f, ', '.join(['%s']*len(warehouses))), tuple(warehouses)) @@ -257,3 +257,7 @@ def get_name_with_abbr(name, company): parts.append(company_abbr) return " - ".join(parts) + +def get_company_currency(company): + return frappe.local_cache("company_currency", company, + lambda: frappe.db.get_value("Company", company, "default_currency")) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 85610a49d21..1ca81b66d9c 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -10,6 +10,7 @@ from frappe import _ import frappe.defaults from erpnext.controllers.buying_controller import BuyingController +from erpnext.accounts.utils import get_account_currency form_grid_templates = { "items": "templates/form_grid/item_grid.html" @@ -307,9 +308,9 @@ class PurchaseReceipt(BuyingController): val_rate_db_precision = 6 if cint(d.precision("valuation_rate")) <= 6 else 9 # warehouse account - stock_value_diff = flt(flt(d.valuation_rate, val_rate_db_precision) * flt(d.qty) + stock_value_diff = flt(flt(d.valuation_rate, val_rate_db_precision) * flt(d.qty) * flt(d.conversion_factor), d.precision("base_net_amount")) - + gl_entries.append(self.get_gl_dict({ "account": warehouse_account[d.warehouse]["name"], "against": stock_rbnb, @@ -319,7 +320,7 @@ class PurchaseReceipt(BuyingController): }, warehouse_account[d.warehouse]["account_currency"])) # stock received but not billed - stock_rbnb_currency = frappe.db.get_value("Account", stock_rbnb, "account_currency") + stock_rbnb_currency = get_account_currency(stock_rbnb) gl_entries.append(self.get_gl_dict({ "account": stock_rbnb, "against": warehouse_account[d.warehouse]["name"],