diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 3eaf994672..e38860176f 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -79,6 +79,16 @@ def is_perpetual_inventory_enabled(company): return frappe.local.enable_perpetual_inventory[company] +def get_party_account_type(party_type): + if not hasattr(frappe.local, 'party_account_types'): + frappe.local.party_account_types = {} + + if not party_type in frappe.local.party_account_types: + frappe.local.party_account_types[party_type] = frappe.db.get_value("Party Type", + party_type, "account_type") or '' + + return frappe.local.party_account_types[party_type] + def get_region(company=None): '''Return the default country based on flag, company or global settings diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index 9aa8de1f0c..afa1ffed60 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -158,9 +158,14 @@ erpnext.accounts.JournalEntry = frappe.ui.form.Controller.extend({ }; }); - me.frm.set_query("party_type", "accounts", function() { - return{ - query: "erpnext.setup.doctype.party_type.party_type.get_party_type" + me.frm.set_query("party_type", "accounts", function(doc, cdt, cdn) { + const row = locals[cdt][cdn]; + + return { + query: "erpnext.setup.doctype.party_type.party_type.get_party_type", + filters: { + 'account': row.account + } } }); diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index f79efed1f5..ca50e2d0f6 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -12,10 +12,8 @@ frappe.ui.form.on('Payment Entry', { setup: function(frm) { frm.set_query("paid_from", function() { - var party_account_type = in_list(["Customer", "Student"], frm.doc.party_type) ? - "Receivable" : "Payable"; var account_types = in_list(["Pay", "Internal Transfer"], frm.doc.payment_type) ? - ["Bank", "Cash"] : party_account_type; + ["Bank", "Cash"] : [frappe.boot.party_account_types[frm.doc.party_type]]; return { filters: { @@ -29,16 +27,14 @@ frappe.ui.form.on('Payment Entry', { frm.set_query("party_type", function() { return{ "filters": { - "name": ["in",["Customer","Supplier", "Employee", "Student"]], + "name": ["in", Object.keys(frappe.boot.party_account_types)], } } }); frm.set_query("paid_to", function() { - var party_account_type = in_list(["Customer", "Student"], frm.doc.party_type) ? - "Receivable" : "Payable"; var account_types = in_list(["Receive", "Internal Transfer"], frm.doc.payment_type) ? - ["Bank", "Cash"] : party_account_type; + ["Bank", "Cash"] : [frappe.boot.party_account_types[frm.doc.party_type]]; return { filters: { @@ -86,9 +82,9 @@ frappe.ui.form.on('Payment Entry', { }); frm.set_query("reference_name", "references", function(doc, cdt, cdn) { - child = locals[cdt][cdn]; - filters = {"docstatus": 1, "company": doc.company}; - party_type_doctypes = ['Sales Invoice', 'Sales Order', 'Purchase Invoice', + const child = locals[cdt][cdn]; + const filters = {"docstatus": 1, "company": doc.company}; + const party_type_doctypes = ['Sales Invoice', 'Sales Order', 'Purchase Invoice', 'Purchase Order', 'Expense Claim', 'Fees']; if (in_list(party_type_doctypes, child.reference_doctype)) { diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 9b50252bd4..96b997f9d7 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -160,9 +160,9 @@ class PaymentEntry(AccountsController): if not frappe.db.exists(self.party_type, self.party): frappe.throw(_("Invalid {0}: {1}").format(self.party_type, self.party)) - if self.party_account and self.party_type != "Employee": - party_account_type = "Receivable" if self.party_type in ("Customer", "Student") else "Payable" - self.validate_account_type(self.party_account, [party_account_type]) + if self.party_account: + self.validate_account_type(self.party_account, + [erpnext.get_party_account_type(self.party_type)]) def validate_bank_accounts(self): if self.payment_type in ("Pay", "Internal Transfer"): @@ -413,7 +413,6 @@ class PaymentEntry(AccountsController): else: against_account = self.paid_from - party_gl_dict = self.get_gl_dict({ "account": self.party_account, "party_type": self.party_type, @@ -422,7 +421,7 @@ class PaymentEntry(AccountsController): "account_currency": self.party_account_currency }) - dr_or_cr = "credit" if self.party_type in ["Customer", "Student"] else "debit" + dr_or_cr = "credit" if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit" for d in self.get("references"): gle = party_gl_dict.copy() diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js index 0901046af2..4c24a9fc97 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js @@ -24,8 +24,10 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext onload: function() { var me = this; this.frm.set_query("party_type", function() { - return{ - query: "erpnext.setup.doctype.party_type.party_type.get_party_type" + return { + "filters": { + "name": ["in", Object.keys(frappe.boot.party_account_types)], + } } }); @@ -37,7 +39,7 @@ erpnext.accounts.PaymentReconciliationController = frappe.ui.form.Controller.ext filters: { "company": me.frm.doc.company, "is_group": 0, - "account_type": (me.frm.doc.party_type == "Customer" ? "Receivable" : "Payable") + "account_type": frappe.boot.party_account_types[me.frm.doc.party_type] } }; } diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index 3c87fe5433..7cd951aba4 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -2,7 +2,7 @@ # For license information, please see license.txt from __future__ import unicode_literals -import frappe +import frappe, erpnext from frappe.utils import flt from frappe import msgprint, _ from frappe.model.document import Document @@ -30,8 +30,8 @@ class PaymentReconciliation(Document): return payment_entries def get_jv_entries(self): - dr_or_cr = "credit_in_account_currency" if self.party_type == "Customer" \ - else "debit_in_account_currency" + dr_or_cr = ("credit_in_account_currency" if erpnext.get_party_account_type(self.party_type) == 'Receivable' + else "debit_in_account_currency") bank_account_condition = "t2.against_account like %(bank_cash_account)s" \ if self.bank_cash_account else "1=1" @@ -104,8 +104,8 @@ class PaymentReconciliation(Document): self.get_invoice_entries() self.validate_invoice() - dr_or_cr = "credit_in_account_currency" \ - if self.party_type == "Customer" else "debit_in_account_currency" + dr_or_cr = ("credit_in_account_currency" + if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit_in_account_currency") lst = [] for e in self.get('payments'): @@ -173,11 +173,8 @@ class PaymentReconciliation(Document): def check_condition(self): cond = " and posting_date >= '{0}'".format(frappe.db.escape(self.from_date)) if self.from_date else "" cond += " and posting_date <= '{0}'".format(frappe.db.escape(self.to_date)) if self.to_date else "" - - if self.party_type == "Customer": - dr_or_cr = "debit_in_account_currency" - else: - dr_or_cr = "credit_in_account_currency" + dr_or_cr = ("debit_in_account_currency" if erpnext.get_party_account_type(self.party_type) == 'Receivable' + else "credit_in_account_currency") if self.minimum_amount: cond += " and `{0}` >= {1}".format(dr_or_cr, flt(self.minimum_amount)) diff --git a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.js b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.js index 7ccec30bde..29f798ef5b 100644 --- a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.js +++ b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.js @@ -46,9 +46,10 @@ frappe.query_reports["Trial Balance for Party"] = { { "fieldname":"party_type", "label": __("Party Type"), - "fieldtype": "Select", - "options": ["Customer", "Supplier"], - "default": "Customer" + "fieldtype": "Link", + "options": "Party Type", + "default": "Customer", + "reqd": 1 }, { "fieldname":"party", diff --git a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py index 6480623ffa..8be63a0e69 100644 --- a/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py +++ b/erpnext/accounts/report/trial_balance_for_party/trial_balance_for_party.py @@ -7,26 +7,28 @@ from frappe import _ from frappe.utils import flt, cint from erpnext.accounts.report.trial_balance.trial_balance import validate_filters - def execute(filters=None): validate_filters(filters) - + show_party_name = is_party_name_visible(filters) - + columns = get_columns(filters, show_party_name) data = get_data(filters, show_party_name) return columns, data - + def get_data(filters, show_party_name): - party_name_field = "customer_name" if filters.get("party_type")=="Customer" else "supplier_name" + party_name_field = "{0}_name".format(frappe.scrub(filters.get('party_type'))) + if filters.get('party_type') == 'Student': + party_name_field = 'first_name' + party_filters = {"name": filters.get("party")} if filters.get("party") else {} parties = frappe.get_all(filters.get("party_type"), fields = ["name", party_name_field], filters = party_filters, order_by="name") company_currency = frappe.db.get_value("Company", filters.company, "default_currency") opening_balances = get_opening_balances(filters) balances_within_period = get_balances_within_period(filters) - + data = [] # total_debit, total_credit = 0, 0 total_row = frappe._dict({ @@ -41,28 +43,28 @@ def get_data(filters, show_party_name): row = { "party": party.name } if show_party_name: row["party_name"] = party.get(party_name_field) - + # opening opening_debit, opening_credit = opening_balances.get(party.name, [0, 0]) row.update({ "opening_debit": opening_debit, "opening_credit": opening_credit }) - + # within period debit, credit = balances_within_period.get(party.name, [0, 0]) row.update({ "debit": debit, "credit": credit }) - + # closing closing_debit, closing_credit = toggle_debit_credit(opening_debit + debit, opening_credit + credit) row.update({ "closing_debit": closing_debit, "closing_credit": closing_credit }) - + # totals for col in total_row: total_row[col] += row.get(col) @@ -70,24 +72,24 @@ def get_data(filters, show_party_name): row.update({ "currency": company_currency }) - + has_value = False if (opening_debit or opening_credit or debit or credit or closing_debit or closing_credit): has_value =True if cint(filters.show_zero_values) or has_value: data.append(row) - + # Add total row - + total_row.update({ "party": "'" + _("Totals") + "'", "currency": company_currency }) data.append(total_row) - + return data - + def get_opening_balances(filters): gle = frappe.db.sql(""" select party, sum(debit) as opening_debit, sum(credit) as opening_credit @@ -100,14 +102,14 @@ def get_opening_balances(filters): "from_date": filters.from_date, "party_type": filters.party_type }, as_dict=True) - + opening = frappe._dict() for d in gle: opening_debit, opening_credit = toggle_debit_credit(d.opening_debit, d.opening_credit) opening.setdefault(d.party, [opening_debit, opening_credit]) - + return opening - + def get_balances_within_period(filters): gle = frappe.db.sql(""" select party, sum(debit) as debit, sum(credit) as credit @@ -122,13 +124,13 @@ def get_balances_within_period(filters): "to_date": filters.to_date, "party_type": filters.party_type }, as_dict=True) - + balances_within_period = frappe._dict() for d in gle: balances_within_period.setdefault(d.party, [d.debit, d.credit]) - + return balances_within_period - + def toggle_debit_credit(debit, credit): if flt(debit) > flt(credit): debit = flt(debit) - flt(credit) @@ -136,9 +138,9 @@ def toggle_debit_credit(debit, credit): else: credit = flt(credit) - flt(debit) debit = 0.0 - + return debit, credit - + def get_columns(filters, show_party_name): columns = [ { @@ -198,7 +200,7 @@ def get_columns(filters, show_party_name): "hidden": 1 } ] - + if show_party_name: columns.insert(1, { "fieldname": "party_name", @@ -206,17 +208,21 @@ def get_columns(filters, show_party_name): "fieldtype": "Data", "width": 200 }) - + return columns - + def is_party_name_visible(filters): show_party_name = False - if filters.get("party_type") == "Customer": - party_naming_by = frappe.db.get_single_value("Selling Settings", "cust_master_name") + + if filters.get('party_type') in ['Customer', 'Supplier']: + if filters.get("party_type") == "Customer": + party_naming_by = frappe.db.get_single_value("Selling Settings", "cust_master_name") + else: + party_naming_by = frappe.db.get_single_value("Buying Settings", "supp_master_name") + + if party_naming_by == "Naming Series": + show_party_name = True else: - party_naming_by = frappe.db.get_single_value("Buying Settings", "supp_master_name") - - if party_naming_by == "Naming Series": show_party_name = True - + return show_party_name \ No newline at end of file diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index b5d9cd8593..9c7310fb45 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals -import frappe +import frappe, erpnext import frappe.defaults from frappe.utils import nowdate, cstr, flt, cint, now, getdate from frappe import throw, _ @@ -322,7 +322,9 @@ def check_if_advance_entry_modified(args): and t1.name = %(voucher_no)s and t2.name = %(voucher_detail_no)s and t1.docstatus=1 """.format(dr_or_cr = args.get("dr_or_cr")), args) else: - party_account_field = "paid_from" if args.party_type == "Customer" else "paid_to" + party_account_field = ("paid_from" + if erpnext.get_party_account_type(args.party_type) == 'Receivable' else "paid_to") + if args.voucher_detail_no: ret = frappe.db.sql("""select t1.name from `tabPayment Entry` t1, `tabPayment Entry Reference` t2 @@ -574,14 +576,14 @@ def get_outstanding_invoices(party_type, party, account, condition=None): outstanding_invoices = [] precision = frappe.get_precision("Sales Invoice", "outstanding_amount") - if party_type in ("Customer", "Student"): + if erpnext.get_party_account_type(party_type) == 'Receivable': dr_or_cr = "debit_in_account_currency - credit_in_account_currency" payment_dr_or_cr = "payment_gl_entry.credit_in_account_currency - payment_gl_entry.debit_in_account_currency" else: dr_or_cr = "credit_in_account_currency - debit_in_account_currency" payment_dr_or_cr = "payment_gl_entry.debit_in_account_currency - payment_gl_entry.credit_in_account_currency" - invoice = 'Sales Invoice' if party_type == 'Customer' else 'Purchase Invoice' + invoice = 'Sales Invoice' if erpnext.get_party_account_type(party_type) == 'Receivable' else 'Purchase Invoice' invoice_list = frappe.db.sql(""" select voucher_no, voucher_type, posting_date, ifnull(sum({dr_or_cr}), 0) as invoice_amount, diff --git a/erpnext/patches.txt b/erpnext/patches.txt index abee28f6ca..a8c6ceadbb 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -523,6 +523,7 @@ erpnext.patches.v11_0.update_department_lft_rgt erpnext.patches.v11_0.add_default_email_template_for_leave erpnext.patches.v11_0.set_default_email_template_in_hr erpnext.patches.v10_0.taxes_issue_with_pos +erpnext.patches.v11_0.update_account_type_in_party_type erpnext.patches.v10_1.transfer_subscription_to_auto_repeat erpnext.patches.v10_1.drop_old_subscription_records erpnext.patches.v11_0.update_brand_in_item_price diff --git a/erpnext/patches/v11_0/update_account_type_in_party_type.py b/erpnext/patches/v11_0/update_account_type_in_party_type.py new file mode 100644 index 0000000000..efa04fd2ce --- /dev/null +++ b/erpnext/patches/v11_0/update_account_type_in_party_type.py @@ -0,0 +1,13 @@ +# Copyright (c) 2017, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc('setup', 'doctype', 'party_type') + party_types = {'Customer': 'Receivable', 'Supplier': 'Payable', + 'Employee': 'Payable', 'Member': 'Receivable', 'Shareholder': 'Payable', 'Student': 'Receivable'} + + for party_type, account_type in party_types.items(): + frappe.db.set_value('Party Type', party_type, 'account_type', account_type) \ No newline at end of file diff --git a/erpnext/setup/doctype/party_type/party_type.json b/erpnext/setup/doctype/party_type/party_type.json index e1814aeebe..00f06a0892 100644 --- a/erpnext/setup/doctype/party_type/party_type.json +++ b/erpnext/setup/doctype/party_type/party_type.json @@ -42,6 +42,39 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "account_type", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Account Type", + "length": 0, + "no_copy": 0, + "options": "Payable\nReceivable", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -55,7 +88,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-11-23 17:46:27.075001", + "modified": "2018-04-26 13:00:49.457439", "modified_by": "Administrator", "module": "Setup", "name": "Party Type", @@ -64,7 +97,6 @@ "permissions": [ { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -84,7 +116,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, @@ -104,7 +135,6 @@ }, { "amend": 0, - "apply_user_permissions": 0, "cancel": 0, "create": 0, "delete": 0, diff --git a/erpnext/setup/doctype/party_type/party_type.py b/erpnext/setup/doctype/party_type/party_type.py index 74db0376bb..8baddf4ea8 100644 --- a/erpnext/setup/doctype/party_type/party_type.py +++ b/erpnext/setup/doctype/party_type/party_type.py @@ -11,10 +11,15 @@ class PartyType(Document): @frappe.whitelist() def get_party_type(doctype, txt, searchfield, start, page_len, filters): + cond = '' + if filters and filters.get('account'): + account_type = frappe.db.get_value('Account', filters.get('account'), 'account_type') + cond = "and account_type = '%s'" % account_type + return frappe.db.sql("""select name from `tabParty Type` - where `{key}` LIKE %(txt)s + where `{key}` LIKE %(txt)s {cond} order by name limit %(start)s, %(page_len)s""" - .format(key=searchfield), { + .format(key=searchfield, cond=cond), { 'txt': "%%%s%%" % frappe.db.escape(txt), 'start': start, 'page_len': page_len }) diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py index f2eaece7db..3309cbc39c 100644 --- a/erpnext/setup/setup_wizard/operations/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -198,12 +198,12 @@ def install(country=None): {'doctype': "Email Account", "email_id": "support@example.com", "append_to": "Issue"}, {'doctype': "Email Account", "email_id": "jobs@example.com", "append_to": "Job Applicant"}, - {'doctype': "Party Type", "party_type": "Customer"}, - {'doctype': "Party Type", "party_type": "Supplier"}, - {'doctype': "Party Type", "party_type": "Employee"}, - {'doctype': "Party Type", "party_type": "Member"}, - {'doctype': "Party Type", "party_type": "Shareholder"}, - {'doctype': "Party Type", "party_type": "Student"}, + {'doctype': "Party Type", "party_type": "Customer", "account_type": "Receivable"}, + {'doctype': "Party Type", "party_type": "Supplier", "account_type": "Payable"}, + {'doctype': "Party Type", "party_type": "Employee", "account_type": "Payable"}, + {'doctype': "Party Type", "party_type": "Member", "account_type": "Receivable"}, + {'doctype': "Party Type", "party_type": "Shareholder", "account_type": "Payable"}, + {'doctype': "Party Type", "party_type": "Student", "account_type": "Receivable"}, {'doctype': "Opportunity Type", "name": "Hub"}, {'doctype': "Opportunity Type", "name": _("Sales")}, diff --git a/erpnext/startup/boot.py b/erpnext/startup/boot.py index 8c43306527..62c9e7b90c 100644 --- a/erpnext/startup/boot.py +++ b/erpnext/startup/boot.py @@ -36,6 +36,9 @@ def boot_session(bootinfo): default_letter_head, default_bank_account, enable_perpetual_inventory from `tabCompany`""", as_dict=1, update={"doctype":":Company"}) + party_account_types = frappe.db.sql(""" select name, ifnull(account_type, '') from `tabParty Type`""") + bootinfo.party_account_types = frappe._dict(party_account_types) + def load_country_and_currency(bootinfo): country = frappe.db.get_default("country") if country and frappe.db.exists("Country", country):