From cc582bd7745d5ebafcad8d37ea68f2d1afd30643 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 27 Aug 2014 19:38:54 +0530 Subject: [PATCH] posted party in gl entry and multiple other fixes --- .../journal_voucher/journal_voucher.js | 39 ++++---- .../journal_voucher/journal_voucher.py | 97 ++++++------------- .../purchase_invoice/purchase_invoice.py | 25 ++--- .../doctype/sales_invoice/sales_invoice.py | 29 +++--- erpnext/controllers/accounts_controller.py | 12 --- .../doctype/email_digest/email_digest.py | 16 ++- 6 files changed, 78 insertions(+), 140 deletions(-) diff --git a/erpnext/accounts/doctype/journal_voucher/journal_voucher.js b/erpnext/accounts/doctype/journal_voucher/journal_voucher.js index 4a964807176..0a07b4d8b4f 100644 --- a/erpnext/accounts/doctype/journal_voucher/journal_voucher.js +++ b/erpnext/accounts/doctype/journal_voucher/journal_voucher.js @@ -53,14 +53,14 @@ erpnext.accounts.JournalVoucher = frappe.ui.form.Controller.extend({ }); - $.each([["against_voucher", "Purchase Invoice", "credit_to"], - ["against_invoice", "Sales Invoice", "debit_to"]], function(i, opts) { + $.each([["against_voucher", "Purchase Invoice", "supplier"], + ["against_invoice", "Sales Invoice", "customer"]], function(i, opts) { me.frm.set_query(opts[0], "entries", function(doc, cdt, cdn) { var jvd = frappe.get_doc(cdt, cdn); - frappe.model.validate_missing(jvd, "account"); + frappe.model.validate_missing(jvd, ["party_type", "party"]); return { filters: [ - [opts[1], opts[2], "=", jvd.account], + [opts[1], opts[2], "=", jvd.party], [opts[1], "docstatus", "=", 1], [opts[1], "outstanding_amount", ">", 0] ] @@ -74,7 +74,10 @@ erpnext.accounts.JournalVoucher = frappe.ui.form.Controller.extend({ return { query: "erpnext.accounts.doctype.journal_voucher.journal_voucher.get_against_jv", - filters: { account: jvd.account } + filters: { + account: jvd.account, + party: jvd.party + } }; }); }, @@ -94,36 +97,32 @@ erpnext.accounts.JournalVoucher = frappe.ui.form.Controller.extend({ against_voucher: function(doc, cdt, cdn) { var d = frappe.get_doc(cdt, cdn); if (d.against_voucher && !flt(d.debit)) { - this.get_outstanding({ - 'doctype': 'Purchase Invoice', - 'docname': d.against_voucher - }, d) + this.get_outstanding('Purchase Invoice', d.against_voucher, d); } }, against_invoice: function(doc, cdt, cdn) { var d = frappe.get_doc(cdt, cdn); if (d.against_invoice && !flt(d.credit)) { - this.get_outstanding({ - 'doctype': 'Sales Invoice', - 'docname': d.against_invoice - }, d) + this.get_outstanding('Sales Invoice', d.against_invoice, d); } }, against_jv: function(doc, cdt, cdn) { var d = frappe.get_doc(cdt, cdn); - if (d.against_jv && !flt(d.credit) && !flt(d.debit)) { - this.get_outstanding({ - 'doctype': 'Journal Voucher', - 'docname': d.against_jv, - 'account': d.account - }, d) + if (d.against_jv && d.party && !flt(d.credit) && !flt(d.debit)) { + this.get_outstanding('Journal Voucher', d.against_jv, d); } }, - get_outstanding: function(args, child) { + get_outstanding: function(doctype, docname, child) { var me = this; + var args = { + "doctype": doctype, + "docname": docname, + "party": child.party + } + return this.frm.call({ child: child, method: "get_outstanding", diff --git a/erpnext/accounts/doctype/journal_voucher/journal_voucher.py b/erpnext/accounts/doctype/journal_voucher/journal_voucher.py index 41e70eb20d2..538cdbb2797 100644 --- a/erpnext/accounts/doctype/journal_voucher/journal_voucher.py +++ b/erpnext/accounts/doctype/journal_voucher/journal_voucher.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import cstr, flt, fmt_money, formatdate, getdate +from frappe.utils import cstr, flt, fmt_money, formatdate, getdate, money_in_words from frappe import msgprint, _, scrub from erpnext.setup.utils import get_company_currency from erpnext.controllers.accounts_controller import AccountsController @@ -11,10 +11,6 @@ from erpnext.controllers.accounts_controller import AccountsController class JournalVoucher(AccountsController): def __init__(self, arg1, arg2=None): super(JournalVoucher, self).__init__(arg1, arg2) - self.master_type = {} - self.credit_days_for = {} - self.credit_days_global = -1 - self.is_approving_authority = -1 def get_feed(self): return self.voucher_type @@ -103,11 +99,10 @@ class JournalVoucher(AccountsController): for d in self.get('entries'): if not d.is_advance and not d.against_voucher and \ not d.against_invoice and not d.against_jv: - master_type = frappe.db.get_value("Account", d.account, "master_type") - if (master_type == 'Customer' and flt(d.credit) > 0) or \ - (master_type == 'Supplier' and flt(d.debit) > 0): - msgprint(_("Row {0}: Please check 'Is Advance' against Account {1} if this \ - is an advance entry.").format(d.idx, d.account)) + + if (d.party_type == 'Customer' and flt(d.credit) > 0) or \ + (d.party_type == 'Supplier' and flt(d.debit) > 0): + msgprint(_("Row {0}: Please check 'Is Advance' against Account {1} if this is an advance entry.").format(d.row, d.account)) def validate_against_jv(self): for d in self.get('entries'): @@ -265,8 +260,7 @@ class JournalVoucher(AccountsController): from `tabPurchase Invoice` where name=%s""", d.against_voucher) if bill_no and bill_no[0][0] and bill_no[0][0].lower().strip() \ not in ['na', 'not applicable', 'none']: - r.append(_('{0} {1} against Bill {2} dated {3}').format(bill_no[0][2], - fmt_money(flt(d.debit)), bill_no[0][0], + r.append(_('{0} against Bill {1} dated {2}').format(fmt_money(flt(d.debit), bill_no[0][2]), bill_no[0][0], bill_no[0][1] and formatdate(bill_no[0][1].strftime('%Y-%m-%d')))) if d.against_purchase_order and d.debit: @@ -285,42 +279,23 @@ class JournalVoucher(AccountsController): if self.is_opening != 'Yes': self.aging_date = self.posting_date else: - # check account type whether supplier or customer - exists = False - for d in self.get('entries'): - account_type = frappe.db.get_value("Account", d.account, "account_type") - if account_type in ["Supplier", "Customer"]: - exists = True - break + party_list = [d.party for d in self.get("entries") if d.party_type and d.party] - # If customer/supplier account, aging date is mandatory - if exists and not self.aging_date: - msgprint(_("Aging Date is mandatory for opening entry"), raise_exception=1) + if len(party_list) and not self.aging_date: + frappe.throw(_("Aging Date is mandatory for opening entry")) else: self.aging_date = self.posting_date def set_print_format_fields(self): + currency = get_company_currency(self.company) for d in self.get('entries'): - result = frappe.db.get_value("Account", d.account, - ["account_type", "master_type"]) - - if not result: - continue - - account_type, master_type = result - - if master_type in ['Supplier', 'Customer']: + if d.party_type and d.party: if not self.pay_to_recd_from: - self.pay_to_recd_from = frappe.db.get_value(master_type, - ' - '.join(d.account.split(' - ')[:-1]), - master_type == 'Customer' and 'customer_name' or 'supplier_name') - - if account_type in ['Bank', 'Cash']: - company_currency = get_company_currency(self.company) - amt = flt(d.debit) and d.debit or d.credit - self.total_amount = fmt_money(amt, currency=company_currency) - from frappe.utils import money_in_words - self.total_amount_in_words = money_in_words(amt, company_currency) + self.pay_to_recd_from = frappe.db.get_value(d.party_type, d.party, + "customer_name" if d.party_type=="Customer" else "supplier_name") + elif frappe.db.get_value("Account", d.account, "account_type") in ["Bank", "Cash"]: + self.total_amount = fmt_money(d.debit or d.credit, currency) + self.total_amount_in_words = money_in_words(self.total_amount, currency) def make_gl_entries(self, cancel=0, adv_adj=0): from erpnext.accounts.general_ledger import make_gl_entries @@ -331,6 +306,8 @@ class JournalVoucher(AccountsController): gl_map.append( self.get_gl_dict({ "account": d.account, + "party_type": d.party_type, + "party": d.party, "against": d.against_account, "debit": flt(d.debit, self.precision("debit", "entries")), "credit": flt(d.credit, self.precision("credit", "entries")), @@ -382,11 +359,14 @@ class JournalVoucher(AccountsController): total += flt(d.outstanding_amount, self.precision("credit", "entries")) jd1 = self.append('entries', {}) jd1.account = d.account + jd1.party = d.party if self.write_off_based_on == 'Accounts Receivable': + jd1.party_type = "Customer" jd1.credit = flt(d.outstanding_amount, self.precision("credit", "entries")) jd1.against_invoice = cstr(d.name) elif self.write_off_based_on == 'Accounts Payable': + jd1.party_type = "Supplier" jd1.debit = flt(d.outstanding_amount, self.precision("debit", "entries")) jd1.against_voucher = cstr(d.name) @@ -404,11 +384,11 @@ class JournalVoucher(AccountsController): if flt(self.write_off_amount) > 0 else "" if self.write_off_based_on == 'Accounts Receivable': - return frappe.db.sql("""select name, debit_to as account, outstanding_amount + return frappe.db.sql("""select name, debit_to as account, customer as party, outstanding_amount from `tabSales Invoice` where docstatus = 1 and company = %s and outstanding_amount > 0 %s""" % ('%s', cond), self.company, as_dict=True) elif self.write_off_based_on == 'Accounts Payable': - return frappe.db.sql("""select name, credit_to as account, outstanding_amount + return frappe.db.sql("""select name, credit_to as account, supplier as party, outstanding_amount from `tabPurchase Invoice` where docstatus = 1 and company = %s and outstanding_amount > 0 %s""" % ('%s', cond), self.company, as_dict=True) @@ -486,37 +466,24 @@ def get_opening_accounts(company): return [{"account": a, "balance": get_balance_on(a)} for a in accounts] -def get_against_purchase_invoice(doctype, txt, searchfield, start, page_len, filters): - return frappe.db.sql("""select name, credit_to, outstanding_amount, bill_no, bill_date - from `tabPurchase Invoice` where credit_to = %s and docstatus = 1 - and outstanding_amount > 0 and %s like %s order by name desc limit %s, %s""" % - ("%s", searchfield, "%s", "%s", "%s"), - (filters["account"], "%%%s%%" % txt, start, page_len)) - -def get_against_sales_invoice(doctype, txt, searchfield, start, page_len, filters): - return frappe.db.sql("""select name, debit_to, outstanding_amount - from `tabSales Invoice` where debit_to = %s and docstatus = 1 - and outstanding_amount > 0 and `%s` like %s order by name desc limit %s, %s""" % - ("%s", searchfield, "%s", "%s", "%s"), - (filters["account"], "%%%s%%" % txt, start, page_len)) def get_against_jv(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql("""select jv.name, jv.posting_date, jv.user_remark from `tabJournal Voucher` jv, `tabJournal Voucher Detail` jv_detail - where jv_detail.parent = jv.name and jv_detail.account = %s and jv.docstatus = 1 - and jv.%s like %s order by jv.name desc limit %s, %s""" % + where jv_detail.parent = jv.name and jv_detail.account = %s and jv_detail.party = %s + and jv.docstatus = 1 and jv.%s like %s order by jv.name desc limit %s, %s""" % ("%s", searchfield, "%s", "%s", "%s"), - (filters["account"], "%%%s%%" % txt, start, page_len)) + (filters["account"], filters["party"], "%%%s%%" % txt, start, page_len)) @frappe.whitelist() def get_outstanding(args): args = eval(args) - if args.get("doctype") == "Journal Voucher" and args.get("account"): + if args.get("doctype") == "Journal Voucher" and args.get("party"): against_jv_amount = frappe.db.sql(""" select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0)) - from `tabJournal Voucher Detail` where parent=%s and account=%s + from `tabJournal Voucher Detail` where parent=%s and party=%s and ifnull(against_invoice, '')='' and ifnull(against_voucher, '')='' - and ifnull(against_jv, '')=''""", (args['docname'], args['account'])) + and ifnull(against_jv, '')=''""", (args['docname'], args['party'])) against_jv_amount = flt(against_jv_amount[0][0]) if against_jv_amount else 0 if against_jv_amount > 0: @@ -526,11 +493,9 @@ def get_outstanding(args): elif args.get("doctype") == "Sales Invoice": return { - "credit": flt(frappe.db.get_value("Sales Invoice", args["docname"], - "outstanding_amount")) + "credit": flt(frappe.db.get_value("Sales Invoice", args["docname"], "outstanding_amount")) } elif args.get("doctype") == "Purchase Invoice": return { - "debit": flt(frappe.db.get_value("Purchase Invoice", args["docname"], - "outstanding_amount")) + "debit": flt(frappe.db.get_value("Purchase Invoice", args["docname"], "outstanding_amount")) } diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index b34d07fa36d..8bc3a5b318e 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -46,10 +46,9 @@ class PurchaseInvoice(BuyingController): self.pr_required() self.check_active_purchase_items() self.check_conversion_rate() - self.validate_credit_acc() + self.validate_credit_to_acc() self.clear_unallocated_advances("Purchase Invoice Advance", "advance_allocation_details") self.validate_advance_jv("advance_allocation_details", "purchase_order") - self.check_for_acc_head_of_supplier() self.check_for_stopped_status() self.validate_with_previous_doc() self.validate_uom_is_integer("uom", "qty") @@ -93,21 +92,13 @@ class PurchaseInvoice(BuyingController): if (self.currency == default_currency and flt(self.conversion_rate) != 1.00) or not self.conversion_rate or (self.currency != default_currency and flt(self.conversion_rate) == 1.00): throw(_("Conversion rate cannot be 0 or 1")) - def validate_credit_acc(self): - if frappe.db.get_value("Account", self.credit_to, "report_type") != "Balance Sheet": - frappe.throw(_("Account must be a balance sheet account")) + def validate_credit_to_acc(self): + root_type, account_type = frappe.db.get_value("Account", self.credit_to, ["root_type", "account_type"]) + if root_type != "Liability": + frappe.throw(_("Credit To account must be a liability account")) + if account_type != "Payable": + frappe.throw(_("Credit To account must be a Payable account")) - # Validate Acc Head of Supplier and Credit To Account entered - # ------------------------------------------------------------ - def check_for_acc_head_of_supplier(self): - if self.supplier and self.credit_to: - acc_head = frappe.db.sql("select master_name from `tabAccount` where name = %s", self.credit_to) - - if (acc_head and cstr(acc_head[0][0]) != cstr(self.supplier)) or (not acc_head and (self.credit_to != cstr(self.supplier) + " - " + self.company_abbr)): - msgprint("Credit To: %s do not match with Supplier: %s for Company: %s.\n If both correctly entered, please select Master Type and Master Name in account master." %(self.credit_to,self.supplier,self.company), raise_exception=1) - - # Check for Stopped PO - # --------------------- def check_for_stopped_status(self): check_list = [] for d in self.get('entries'): @@ -274,6 +265,8 @@ class PurchaseInvoice(BuyingController): gl_entries.append( self.get_gl_dict({ "account": self.credit_to, + "party_type": "Supplier", + "party": self.supplier, "against": self.against_expense_account, "credit": self.total_amount_to_pay, "remarks": self.remarks, diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index dbb2e20d381..615e14c2cf7 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -46,8 +46,7 @@ class SalesInvoice(SellingController): self.validate_with_previous_doc() self.validate_uom_is_integer("stock_uom", "qty") self.check_stop_sales_order("sales_order") - self.validate_customer_account() - self.validate_debit_acc() + self.validate_debit_to_acc() self.validate_fixed_asset_account() self.clear_unallocated_advances("Sales Invoice Advance", "advance_adjustment_details") self.validate_advance_jv("advance_adjustment_details", "sales_order") @@ -237,20 +236,12 @@ class SalesInvoice(SellingController): from erpnext.accounts.utils import reconcile_against_document reconcile_against_document(lst) - def validate_customer_account(self): - """Validates Debit To Account and Customer Matches""" - if self.customer and self.debit_to and not cint(self.is_pos): - acc_head = frappe.db.sql("select master_name from `tabAccount` where name = %s and docstatus != 2", self.debit_to) - - if (acc_head and cstr(acc_head[0][0]) != cstr(self.customer)) or \ - (not acc_head and (self.debit_to != cstr(self.customer) + " - " + self.get_company_abbr())): - msgprint("Debit To: %s do not match with Customer: %s for Company: %s.\n If both correctly entered, please select Master Type \ - and Master Name in account master." %(self.debit_to, self.customer,self.company), raise_exception=1) - - - def validate_debit_acc(self): - if frappe.db.get_value("Account", self.debit_to, "report_type") != "Balance Sheet": - frappe.throw(_("Account must be a balance sheet account")) + def validate_debit_to_acc(self): + root_type, account_type = frappe.db.get_value("Account", self.debit_to, ["root_type", "account_type"]) + if root_type != "Asset": + frappe.throw(_("Debit To account must be a liability account")) + if account_type != "Receivable": + frappe.throw(_("Debit To account must be a Receivable account")) def validate_fixed_asset_account(self): """Validate Fixed Asset and whether Income Account Entered Exists""" @@ -494,6 +485,8 @@ class SalesInvoice(SellingController): gl_entries.append( self.get_gl_dict({ "account": self.debit_to, + "party_type": "Customer", + "party": self.customer, "against": self.against_income_account, "debit": self.grand_total, "remarks": self.remarks, @@ -540,6 +533,8 @@ class SalesInvoice(SellingController): gl_entries.append( self.get_gl_dict({ "account": self.debit_to, + "party_type": "Customer", + "party": self.customer, "against": self.cash_bank_account, "credit": self.paid_amount, "remarks": self.remarks, @@ -560,6 +555,8 @@ class SalesInvoice(SellingController): gl_entries.append( self.get_gl_dict({ "account": self.debit_to, + "party_type": "Customer", + "party": self.customer, "against": self.write_off_account, "credit": self.write_off_amount, "remarks": self.remarks, diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 935adb044a4..31f5d397ca2 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -21,7 +21,6 @@ class AccountsController(TransactionBase): self.validate_value("grand_total", ">=", 0) self.set_total_in_words() - self.validate_for_freezed_account() self.validate_due_date() if self.meta.get_field("is_recurring"): @@ -69,17 +68,6 @@ class AccountsController(TransactionBase): elif self.doctype == "Purchase Invoice": validate_due_date(self.posting_date, self.due_date, "Supplier", self.supplier, self.company) - def validate_for_freezed_account(self): - for fieldname in ["customer", "supplier"]: - if self.meta.get_field(fieldname) and self.get(fieldname): - accounts = frappe.db.get_values("Account", - {"master_type": fieldname.title(), "master_name": self.get(fieldname), - "company": self.company}, "name") - if accounts: - from erpnext.accounts.doctype.gl_entry.gl_entry import validate_frozen_account - for account in accounts: - validate_frozen_account(account[0]) - def set_price_list_currency(self, buying_or_selling): if self.meta.get_field("currency"): company_currency = get_company_currency(self.company) diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py index c84a80bfc9a..bb9fb7e806b 100644 --- a/erpnext/setup/doctype/email_digest/email_digest.py +++ b/erpnext/setup/doctype/email_digest/email_digest.py @@ -204,9 +204,7 @@ class EmailDigest(Document): def get_party_total(self, party_type, gle_field, label): import re - # account is of master_type Customer or Supplier - accounts = [a["name"] for a in self.get_accounts() - if a["master_type"]==party_type] + party_list = frappe.db.sql_list("select name from `tab{0}`".format(party_type)) # account is "Bank" or "Cash" bc_accounts = [esc(a["name"], "()|") for a in self.get_accounts() @@ -216,7 +214,7 @@ class EmailDigest(Document): total = 0 for gle in self.get_gl_entries(self.from_date, self.to_date): # check that its made against a bank or cash account - if gle["account"] in accounts and gle["against"] and \ + if gle["party_type"]==party_type and gle["party"] in party_list and gle["against"] and \ bc_regex.findall(gle["against"]): val = gle["debit"] - gle["credit"] total += (gle_field=="debit" and 1 or -1) * val @@ -231,13 +229,11 @@ class EmailDigest(Document): return self.get_booked_total("Supplier", "credit", self.meta.get_label("payables")) def get_booked_total(self, party_type, gle_field, label): - # account is of master_type Customer or Supplier - accounts = [a["name"] for a in self.get_accounts() - if a["master_type"]==party_type] + party_list = frappe.db.sql_list("select name from `tab{0}`".format(party_type)) total = 0 for gle in self.get_gl_entries(self.from_date, self.to_date): - if gle["account"] in accounts: + if gle["party_type"]==party_type and gle["party"] in party_list: total += gle[gle_field] return total, self.get_html(label, self.currency, fmt_money(total)) @@ -379,7 +375,7 @@ class EmailDigest(Document): hasattr(self, "gl_entries"): return self.gl_entries - gl_entries = frappe.db.sql("""select `account`, + gl_entries = frappe.db.sql("""select `account`, `party_type`, `party`, ifnull(credit, 0) as credit, ifnull(debit, 0) as debit, `against` from `tabGL Entry` where company=%s @@ -395,7 +391,7 @@ class EmailDigest(Document): def get_accounts(self): if not hasattr(self, "accounts"): - self.accounts = frappe.db.sql("""select name, account_type, account_name, master_type, root_type + self.accounts = frappe.db.sql("""select name, account_type, account_name, root_type from `tabAccount` where company=%s and docstatus < 2 and group_or_ledger = "Ledger" order by lft""", (self.company,), as_dict=1)