Skip to content

Commit

Permalink
fix: Payment against credit notes will be considered as payment again…
Browse files Browse the repository at this point in the history
…st parent invoice in Accounts Receivable/Payable report (#35642)

fix: Payment against credit notes will be considered as payment against parent invoice in Accounts Receivable/Payable report (#35642)

* fix: payment against credit note should be linked to parent invoice

* test: AR/AP report for payment against cr note scenario

* fix: cr_note shows up as outstanding invoice

Payment made against cr_note causes it be reported as outstanding invoice

(cherry picked from commit 42f4f80)

Co-authored-by: ruthra kumar <ruthra@erpnext.com>
  • Loading branch information
mergify[bot] and ruthra-kumar authored Jun 12, 2023
1 parent 043815e commit 81ef2ba
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from frappe import _, msgprint, qb
from frappe.model.document import Document
from frappe.query_builder.custom import ConstantColumn
from frappe.query_builder.functions import IfNull
from frappe.utils import flt, get_link_to_form, getdate, nowdate, today

import erpnext
Expand Down Expand Up @@ -127,32 +126,40 @@ def get_jv_entries(self):

return list(journal_entries)

def get_return_invoices(self):
voucher_type = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice"
doc = qb.DocType(voucher_type)
self.return_invoices = (
qb.from_(doc)
.select(
ConstantColumn(voucher_type).as_("voucher_type"),
doc.name.as_("voucher_no"),
doc.return_against,
)
.where(
(doc.docstatus == 1)
& (doc[frappe.scrub(self.party_type)] == self.party)
& (doc.is_return == 1)
)
.run(as_dict=True)
)

def get_dr_or_cr_notes(self):

self.build_qb_filter_conditions(get_return_invoices=True)

ple = qb.DocType("Payment Ledger Entry")
voucher_type = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice"

if erpnext.get_party_account_type(self.party_type) == "Receivable":
self.common_filter_conditions.append(ple.account_type == "Receivable")
else:
self.common_filter_conditions.append(ple.account_type == "Payable")
self.common_filter_conditions.append(ple.account == self.receivable_payable_account)

# get return invoices
doc = qb.DocType(voucher_type)
return_invoices = (
qb.from_(doc)
.select(ConstantColumn(voucher_type).as_("voucher_type"), doc.name.as_("voucher_no"))
.where(
(doc.docstatus == 1)
& (doc[frappe.scrub(self.party_type)] == self.party)
& (doc.is_return == 1)
& (IfNull(doc.return_against, "") == "")
)
.run(as_dict=True)
)
self.get_return_invoices()
return_invoices = [
x for x in self.return_invoices if x.return_against == None or x.return_against == ""
]

outstanding_dr_or_cr = []
if return_invoices:
Expand Down Expand Up @@ -204,6 +211,9 @@ def get_invoice_entries(self):
accounting_dimensions=self.accounting_dimension_filter_conditions,
)

cr_dr_notes = [x.voucher_no for x in self.return_invoices]
non_reconciled_invoices = [x for x in non_reconciled_invoices if x.voucher_no not in cr_dr_notes]

if self.invoice_limit:
non_reconciled_invoices = non_reconciled_invoices[: self.invoice_limit]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,16 @@ def get_voucher_balance(self, ple):
return

key = (ple.against_voucher_type, ple.against_voucher_no, ple.party)

# 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 ple.against_voucher_type in ("Sales Invoice", "Purchase Invoice"):
if ple.against_voucher_no in self.return_entries:
return_against = self.return_entries.get(ple.against_voucher_no)
if return_against:
key = (ple.against_voucher_type, return_against, ple.party)

row = self.voucher_balance.get(key)

if not row:
Expand Down Expand Up @@ -610,7 +620,7 @@ def allocate_future_payments(self, row):

def get_return_entries(self):
doctype = "Sales Invoice" if self.party_type == "Customer" else "Purchase Invoice"
filters = {"is_return": 1, "docstatus": 1}
filters = {"is_return": 1, "docstatus": 1, "company": self.filters.company}
party_field = scrub(self.filters.party_type)
if self.filters.get(party_field):
filters.update({party_field: self.filters.get(party_field)})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,67 @@ def test_exchange_revaluation_for_party(self):
],
)

def test_payment_against_credit_note(self):
"""
Payment against credit/debit note should be considered against the parent invoice
"""
company = "_Test Company 2"
customer = "_Test Customer 2"

si1 = make_sales_invoice()

pe = get_payment_entry("Sales Invoice", si1.name, bank_account="Cash - _TC2")
pe.paid_from = "Debtors - _TC2"
pe.insert()
pe.submit()

cr_note = make_credit_note(si1.name)

si2 = make_sales_invoice()

# manually link cr_note with si2 using journal entry
je = frappe.new_doc("Journal Entry")
je.company = company
je.voucher_type = "Credit Note"
je.posting_date = today()

debit_account = "Debtors - _TC2"
debit_entry = {
"account": debit_account,
"party_type": "Customer",
"party": customer,
"debit": 100,
"debit_in_account_currency": 100,
"reference_type": cr_note.doctype,
"reference_name": cr_note.name,
"cost_center": "Main - _TC2",
}
credit_entry = {
"account": debit_account,
"party_type": "Customer",
"party": customer,
"credit": 100,
"credit_in_account_currency": 100,
"reference_type": si2.doctype,
"reference_name": si2.name,
"cost_center": "Main - _TC2",
}

je.append("accounts", debit_entry)
je.append("accounts", credit_entry)
je = je.save().submit()

filters = {
"company": company,
"report_date": today(),
"range1": 30,
"range2": 60,
"range3": 90,
"range4": 120,
}
report = execute(filters)
self.assertEqual(report[1], [])


def make_sales_invoice(no_payment_schedule=False, do_not_submit=False):
frappe.set_user("Administrator")
Expand Down Expand Up @@ -256,7 +317,7 @@ def make_payment(docname):


def make_credit_note(docname):
create_sales_invoice(
credit_note = create_sales_invoice(
company="_Test Company 2",
customer="_Test Customer 2",
currency="EUR",
Expand All @@ -269,3 +330,5 @@ def make_credit_note(docname):
is_return=1,
return_against=docname,
)

return credit_note

0 comments on commit 81ef2ba

Please sign in to comment.