From f86123ad5a5a0da9be7e74f7b6e1360f3f9733f9 Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Tue, 15 Jan 2019 15:18:43 +0500 Subject: [PATCH] feat(Party Ledger Summary): Include columns for discount and other adjustments --- .../customer_ledger_summary.py | 91 +++++++++++++------ erpnext/setup/doctype/company/company.js | 2 + erpnext/setup/doctype/company/company.json | 68 +++++++++++++- 3 files changed, 131 insertions(+), 30 deletions(-) diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py index 2b228fd6b6f..c8044c532aa 100644 --- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py +++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py @@ -6,6 +6,7 @@ import frappe import erpnext from frappe import _, scrub from frappe.utils import getdate, nowdate, flt, cint +from six import iteritems class PartyLedgerSummaryReport(object): def __init__(self, filters=None): @@ -20,6 +21,11 @@ class PartyLedgerSummaryReport(object): self.filters.party_type = args.get("party_type") self.party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1]) + discount_account_field = "discount_allowed_account" if self.filters.party_type == "Customer" \ + else "discount_received_account" + self.round_off_account, self.write_off_account, self.discount_account = frappe.get_cached_value('Company', + self.filters.company, ["round_off_account", "write_off_account", discount_account_field]) + columns = self.get_columns() data = self.get_data() return columns, data @@ -42,6 +48,8 @@ class PartyLedgerSummaryReport(object): }) credit_or_debit_note = "Credit Note" if self.filters.party_type == "Customer" else "Debit Note" + discount_allowed_or_received = "Discount Allowed" if self.filters.party_type == "Customer" else "Discount Received" + columns += [ { "label": _("Opening Balance"), @@ -71,6 +79,13 @@ class PartyLedgerSummaryReport(object): "options": "currency", "width": 120 }, + { + "label": _(discount_allowed_or_received), + "fieldname": "discount_amount", + "fieldtype": "Currency", + "options": "currency", + "width": 120 + }, { "label": _("Write Off Amount"), "fieldname": "write_off_amount", @@ -78,6 +93,13 @@ class PartyLedgerSummaryReport(object): "options": "currency", "width": 120 }, + { + "label": _("Other Adjustments"), + "fieldname": "adjustment_amount", + "fieldtype": "Currency", + "options": "currency", + "width": 120 + }, { "label": _("Closing Balance"), "fieldname": "closing_balance", @@ -106,18 +128,17 @@ class PartyLedgerSummaryReport(object): self.get_gl_entries() self.get_return_invoices() - self.get_party_write_off_amounts() + self.get_party_adjustment_amounts() self.party_data = frappe._dict({}) for gle in self.gl_entries: self.party_data.setdefault(gle.party, frappe._dict({ "party": gle.party, - "party_name": "", # TODO add party_name + "party_name": "", # TODO add party_name "opening_balance": 0, "invoiced_amount": 0, - "paid_amount": -self.party_write_off_amounts.get(gle.party, 0), + "paid_amount": 0, "return_amount": 0, - "write_off_amount": self.party_write_off_amounts.get(gle.party, 0), "closing_balance": 0, "currency": company_currency })) @@ -135,8 +156,18 @@ class PartyLedgerSummaryReport(object): else: self.party_data[gle.party].paid_amount -= amount - return [d for d in self.party_data.values() if d.opening_balance or d.invoiced_amount or d.paid_amount - or d.return_amount or d.write_off_amount or d.closing_amount] + out = [] + for party, row in iteritems(self.party_data): + if row.opening_balance or row.invoiced_amount or row.paid_amount or row.return_amount or row.closing_amount: + total_party_adjustment = sum([amount for account, amount in iteritems(self.party_adjustment_details.get(party, {}))]) + row.paid_amount -= total_party_adjustment + row.discount_amount = self.party_adjustment_details.get(party, {}).get(self.discount_account, 0) + row.write_off_amount = self.party_adjustment_details.get(party, {}).get(self.write_off_account, 0) + row.adjustment_amount = total_party_adjustment - row.discount_amount - row.write_off_amount + + out.append(row) + + return out def get_gl_entries(self): conditions = self.prepare_conditions() @@ -215,12 +246,11 @@ class PartyLedgerSummaryReport(object): self.return_invoices = [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1, "posting_date": ["between", [self.filters.from_date, self.filters.to_date]]})] - def get_party_write_off_amounts(self): + def get_party_adjustment_amounts(self): conditions = self.prepare_conditions() - income_or_expense = "Expense Account" if self.filters.party_type == "Customer" else "Income Account" + income_or_expense = "Expense" if self.filters.party_type == "Customer" else "Income" invoice_dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit" reverse_dr_or_cr = "credit" if self.filters.party_type == "Customer" else "debit" - round_off_account = frappe.get_cached_value('Company', self.filters.company, "round_off_account") gl_entries = frappe.db.sql(""" select @@ -231,7 +261,7 @@ class PartyLedgerSummaryReport(object): docstatus < 2 and (voucher_type, voucher_no) in ( select voucher_type, voucher_no from `tabGL Entry` gle, `tabAccount` acc - where acc.name = gle.account and acc.account_type = '{income_or_expense}' + where acc.name = gle.account and acc.root_type = '{income_or_expense}' and gle.posting_date between %(from_date)s and %(to_date)s and gle.docstatus < 2 ) and (voucher_type, voucher_no) in ( select voucher_type, voucher_no from `tabGL Entry` gle @@ -241,39 +271,42 @@ class PartyLedgerSummaryReport(object): order by posting_date """.format(conditions=conditions, income_or_expense=income_or_expense), self.filters, as_dict=True) - self.party_write_off_amounts = {} - write_off_voucher_entries = {} + self.party_adjustment_details = {} + adjustment_voucher_entries = {} for gle in gl_entries: - write_off_voucher_entries.setdefault((gle.voucher_type, gle.voucher_no), []) - write_off_voucher_entries[(gle.voucher_type, gle.voucher_no)].append(gle) + adjustment_voucher_entries.setdefault((gle.voucher_type, gle.voucher_no), []) + adjustment_voucher_entries[(gle.voucher_type, gle.voucher_no)].append(gle) - for voucher, voucher_gl_entries in write_off_voucher_entries.iteritems(): + for voucher, voucher_gl_entries in iteritems(adjustment_voucher_entries): parties = {} - write_offs = {} + accounts = {} has_irrelevant_entry = False for gle in voucher_gl_entries: - if gle.account == round_off_account: + if gle.account == self.round_off_account: continue elif gle.party: parties.setdefault(gle.party, 0) parties[gle.party] += gle.get(reverse_dr_or_cr) - gle.get(invoice_dr_or_cr) - elif frappe.get_cached_value("Account", gle.account, "account_type") == income_or_expense: - write_offs.setdefault(gle.account, 0) - write_offs[gle.account] += gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr) + elif frappe.get_cached_value("Account", gle.account, "root_type") == income_or_expense: + accounts.setdefault(gle.account, 0) + accounts[gle.account] += gle.get(invoice_dr_or_cr) - gle.get(reverse_dr_or_cr) else: has_irrelevant_entry = True - if parties and write_offs: + if parties and accounts: if len(parties) == 1: - for account, amount in write_offs.iteritems(): - party = parties.keys()[0] - self.party_write_off_amounts.setdefault(party, 0) - self.party_write_off_amounts[party] += amount - elif len(write_offs) == 1 and not has_irrelevant_entry: - for party, amount in parties.iteritems(): - self.party_write_off_amounts.setdefault(party, 0) - self.party_write_off_amounts[party] += amount + party = parties.keys()[0] + for account, amount in iteritems(accounts): + self.party_adjustment_details.setdefault(party, {}) + self.party_adjustment_details[party].setdefault(account, 0) + self.party_adjustment_details[party][account] += amount + elif len(accounts) == 1 and not has_irrelevant_entry: + account = accounts.keys()[0] + for party, amount in iteritems(parties): + self.party_adjustment_details.setdefault(party, {}) + self.party_adjustment_details[party].setdefault(account, 0) + self.party_adjustment_details[party][account] += amount def execute(filters=None): args = { diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index 16676ac78af..70e047a4e80 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -206,6 +206,8 @@ erpnext.company.setup_queries = function(frm) { ["default_payroll_payable_account", {"root_type": "Liability"}], ["round_off_account", {"root_type": "Expense"}], ["write_off_account", {"root_type": "Expense"}], + ["discount_allowed_account", {"root_type": "Expense"}], + ["discount_received_account", {"root_type": "Income"}], ["exchange_gain_loss_account", {"root_type": "Expense"}], ["unrealized_exchange_gain_loss_account", {"root_type": "Expense"}], ["accumulated_depreciation_account", diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json index 01f8956a826..77c371e0cdd 100644 --- a/erpnext/setup/doctype/company/company.json +++ b/erpnext/setup/doctype/company/company.json @@ -1250,6 +1250,72 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "discount_allowed_account", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Discount Allowed Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "discount_received_account", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Discount Received Account", + "length": 0, + "no_copy": 0, + "options": "Account", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -2903,7 +2969,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2018-10-24 12:57:46.776452", + "modified": "2019-01-15 13:29:54.510379", "modified_by": "Administrator", "module": "Setup", "name": "Company",