Merge pull request #38071 from GursheenK/unequal-dr-cr-for-payments-with-partial-credit-note
fix: handle partial return against invoices in payment entries
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index fc22f53..448224b 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -1054,9 +1054,9 @@
item=self,
)
- dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
-
for d in self.get("references"):
+ # re-defining dr_or_cr for every reference in order to avoid the last value affecting calculation of reverse
+ dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
cost_center = self.cost_center
if d.reference_doctype == "Sales Invoice" and not cost_center:
cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center")
@@ -1072,11 +1072,9 @@
against_voucher_type = d.reference_doctype
against_voucher = d.reference_name
- reverse_dr_or_cr, standalone_note = 0, 0
+ reverse_dr_or_cr = 0
if d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]:
- is_return, return_against = frappe.db.get_value(
- d.reference_doctype, d.reference_name, ["is_return", "return_against"]
- )
+ is_return = frappe.db.get_value(d.reference_doctype, d.reference_name, "is_return")
payable_party_types = get_party_types_from_account_type("Payable")
receivable_party_types = get_party_types_from_account_type("Receivable")
if is_return and self.party_type in receivable_party_types and (self.payment_type == "Pay"):
@@ -1086,7 +1084,7 @@
):
reverse_dr_or_cr = 1
- if is_return and not return_against and not reverse_dr_or_cr:
+ if is_return and not reverse_dr_or_cr:
dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
gle.update(
@@ -1100,6 +1098,7 @@
)
gl_entries.append(gle)
+ dr_or_cr = "credit" if self.payment_type == "Receive" else "debit"
if self.unallocated_amount:
exchange_rate = self.get_exchange_rate()
base_unallocated_amount = self.unallocated_amount * exchange_rate
diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
index 603f24a..f4b0c55 100644
--- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
@@ -1290,6 +1290,9 @@
self.assertEqual(references[2].payment_term, "Tax Receivable")
def test_receive_payment_from_payable_party_type(self):
+ """
+ Checks GL entries generated while receiving payments from a Payable Party Type.
+ """
pe = create_payment_entry(
party_type="Supplier",
party="_Test Supplier",
@@ -1301,8 +1304,57 @@
)
self.voucher_no = pe.name
self.expected_gle = [
- {"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0},
{"account": "Creditors - _TC", "debit": 0.0, "credit": 1000.0},
+ {"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0},
+ ]
+ self.check_gl_entries()
+
+ def test_payment_against_partial_return_invoice(self):
+ """
+ Checks GL entries generated for partial return invoice payments.
+ """
+ si = create_sales_invoice(qty=10, rate=10, customer="_Test Customer")
+ credit_note = create_sales_invoice(
+ qty=-4, rate=10, customer="_Test Customer", is_return=1, return_against=si.name
+ )
+ pe = create_payment_entry(
+ party_type="Customer",
+ party="_Test Customer",
+ payment_type="Receive",
+ paid_from="Debtors - _TC",
+ paid_to="_Test Cash - _TC",
+ )
+ pe.set(
+ "references",
+ [
+ {
+ "reference_doctype": "Sales Invoice",
+ "reference_name": si.name,
+ "due_date": si.get("due_date"),
+ "total_amount": si.grand_total,
+ "outstanding_amount": si.outstanding_amount,
+ "allocated_amount": si.outstanding_amount,
+ },
+ {
+ "reference_doctype": "Sales Invoice",
+ "reference_name": credit_note.name,
+ "due_date": credit_note.get("due_date"),
+ "total_amount": credit_note.grand_total,
+ "outstanding_amount": credit_note.outstanding_amount,
+ "allocated_amount": credit_note.outstanding_amount,
+ },
+ ],
+ )
+ pe.save()
+ pe.submit()
+ self.assertEqual(pe.total_allocated_amount, 60)
+ self.assertEqual(pe.unallocated_amount, 940)
+ self.voucher_no = pe.name
+ self.expected_gle = [
+ {"account": "Debtors - _TC", "debit": 40.0, "credit": 0.0},
+ {"account": "Debtors - _TC", "debit": 0.0, "credit": 940.0},
+ {"account": "Debtors - _TC", "debit": 0.0, "credit": 100.0},
+ {"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0},
]
self.check_gl_entries()
@@ -1316,7 +1368,7 @@
gle.credit,
)
.where((gle.voucher_no == self.voucher_no) & (gle.is_cancelled == 0))
- .orderby(gle.account)
+ .orderby(gle.account, gle.debit, gle.credit, order=frappe.qb.desc)
).run(as_dict=True)
for row in range(len(self.expected_gle)):
for field in ["account", "debit", "credit"]: