From 2064dfc5a9c3b02d7472606ec73009280d757b93 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 24 Sep 2019 19:52:33 +0530 Subject: [PATCH] fix: Handling payments against credit/debit notes and party currency (#19154) --- .../accounts_receivable.py | 43 +++++++++++++++---- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 8cbf845863..bcbd427186 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -59,7 +59,6 @@ class ReceivablePayableReport(object): self.invoices = set() def get_data(self): - t1 = now() self.get_gl_entries() self.voucher_balance = OrderedDict() self.init_voucher_balance() # invoiced, paid, credit_note, outstanding @@ -73,6 +72,9 @@ class ReceivablePayableReport(object): # fetch future payments against invoices self.get_future_payments() + # Get return entries + self.get_return_entries() + self.data = [] for gle in self.gl_entries: self.update_voucher_balance(gle) @@ -91,6 +93,7 @@ class ReceivablePayableReport(object): party = gle.party, posting_date = gle.posting_date, remarks = gle.remarks, + account_currency = gle.account_currency, invoiced = 0.0, paid = 0.0, credit_note = 0.0, @@ -106,7 +109,6 @@ class ReceivablePayableReport(object): # get the row where this balance needs to be updated # if its a payment, it will return the linked invoice or will be considered as advance row = self.get_voucher_balance(gle) - # gle_balance will be the total "debit - credit" for receivable type reports and # and vice-versa for payable type reports gle_balance = self.get_gle_balance(gle) @@ -131,7 +133,18 @@ class ReceivablePayableReport(object): if gle.against_voucher: # find invoice - voucher_balance = self.voucher_balance.get((gle.against_voucher_type, gle.against_voucher, gle.party)) + against_voucher = gle.against_voucher + + # If payment is made against credit note + # and credit note is made against a Sales Invoice + # then consider the payment against original sales invoice. + if gle.against_voucher_type in ('Sales Invoice', 'Purchase Invoice'): + if gle.against_voucher in self.return_entries: + return_against = self.return_entries.get(gle.against_voucher) + if return_against: + against_voucher = return_against + + voucher_balance = self.voucher_balance.get((gle.against_voucher_type, against_voucher, gle.party)) if not voucher_balance: # no invoice, this is an invoice / stand-alone payment / credit note @@ -258,7 +271,6 @@ class ReceivablePayableReport(object): # customer / supplier name party_details = self.get_party_details(row.party) row.update(party_details) - if self.filters.get(scrub(self.filters.party_type)): row.currency = row.account_currency else: @@ -423,6 +435,19 @@ class ReceivablePayableReport(object): if row.future_ref: row.future_ref = ', '.join(row.future_ref) + def get_return_entries(self): + doctype = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice" + filters={ + 'is_return': 1, + 'docstatus': 1 + } + party_field = scrub(self.filters.party_type) + if self.filters.get(party_field): + filters.update({party_field: self.filters.get(party_field)}) + self.return_entries = frappe._dict( + frappe.get_all(doctype, filters, ['name', 'return_against'], as_list=1) + ) + def set_ageing(self, row): if self.filters.ageing_based_on == "Due Date": entry_date = row.due_date @@ -689,11 +714,11 @@ class ReceivablePayableReport(object): def get_chart_data(self): rows = [] for row in self.data: - rows.append( - { - 'values': [row.range1, row.range2, row.range3, row.range4, row.range5] - } - ) + values = [row.range1, row.range2, row.range3, row.range4, row.range5] + precision = cint(frappe.db.get_default("float_precision")) or 2 + rows.append({ + 'values': [flt(val, precision) for val in values] + }) self.chart = { "data": {