fix: update payment request outstanding on unreconciliation

(cherry picked from commit 8098229b55)

# Conflicts:
#	erpnext/accounts/doctype/payment_request/test_payment_request.py
This commit is contained in:
ljain112
2025-06-30 14:18:40 +05:30
committed by Mergify
parent 6b41dc2fed
commit 450061c7db
3 changed files with 95 additions and 45 deletions

View File

@@ -829,8 +829,7 @@ def update_payment_requests_as_per_pe_references(references=None, cancel=False):
if not references: if not references:
return return
precision = references[0].precision("allocated_amount") precision = frappe.get_precision("Payment Entry Reference", "allocated_amount")
referenced_payment_requests = frappe.get_all( referenced_payment_requests = frappe.get_all(
"Payment Request", "Payment Request",
filters={"name": ["in", {row.payment_request for row in references if row.payment_request}]}, filters={"name": ["in", {row.payment_request for row in references if row.payment_request}]},

View File

@@ -645,6 +645,7 @@ def test_partial_paid_invoice_with_submitted_payment_entry(self):
pe.submit() pe.submit()
pe.cancel() pe.cancel()
<<<<<<< HEAD
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC") pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
pe.reference_no = "PURINV0002" pe.reference_no = "PURINV0002"
pe.reference_date = frappe.utils.nowdate() pe.reference_date = frappe.utils.nowdate()
@@ -656,3 +657,32 @@ def test_partial_paid_invoice_with_submitted_payment_entry(self):
pi.load_from_db() pi.load_from_db()
pr = make_payment_request(dt="Purchase Invoice", dn=pi.name, mute_email=1) pr = make_payment_request(dt="Purchase Invoice", dn=pi.name, mute_email=1)
self.assertEqual(pr.grand_total, pi.outstanding_amount) self.assertEqual(pr.grand_total, pi.outstanding_amount)
=======
pi.load_from_db()
pr = make_payment_request(dt="Purchase Invoice", dn=pi.name, mute_email=1)
self.assertEqual(pr.grand_total, pi.outstanding_amount)
def test_payment_request_on_unreconcile(self):
pi = make_purchase_invoice(currency="INR", qty=1, rate=500)
pi.submit()
pr = make_payment_request(dt="Purchase Invoice", dn=pi.name, mute_email=1)
self.assertEqual(pr.grand_total, pi.outstanding_amount)
pe = pr.create_payment_entry()
unreconcile = frappe.get_doc(
{
"doctype": "Unreconcile Payment",
"company": pe.company,
"voucher_type": pe.doctype,
"voucher_no": pe.name,
}
)
unreconcile.add_references()
unreconcile.submit()
pi.load_from_db()
pr.load_from_db()
self.assertEqual(pr.grand_total, pi.outstanding_amount)
>>>>>>> 8098229b55 (fix: update payment request outstanding on unreconciliation)

View File

@@ -997,58 +997,79 @@ def remove_ref_doc_link_from_pe(
per = qb.DocType("Payment Entry Reference") per = qb.DocType("Payment Entry Reference")
pay = qb.DocType("Payment Entry") pay = qb.DocType("Payment Entry")
linked_pe = ( query = (
qb.from_(per) qb.from_(per)
.select(per.parent) .select("*")
.where((per.reference_doctype == ref_type) & (per.reference_name == ref_no) & (per.docstatus.lt(2))) .where(
.run(as_list=1) (per.reference_doctype == ref_type)
) & (per.reference_name == ref_no)
linked_pe = convert_to_list(linked_pe) & (per.docstatus.lt(2))
# remove reference only from specified payment & (per.parenttype == "Payment Entry")
linked_pe = [x for x in linked_pe if x == payment_name] if payment_name else linked_pe
if linked_pe:
update_query = (
qb.update(per)
.set(per.allocated_amount, 0)
.set(per.modified, now())
.set(per.modified_by, frappe.session.user)
.where(per.docstatus.lt(2) & (per.reference_doctype == ref_type) & (per.reference_name == ref_no))
) )
)
if payment_name: # update reference only from specified payment
update_query = update_query.where(per.parent == payment_name) if payment_name:
query = query.where(per.parent == payment_name)
update_query.run() reference_rows = query.run(as_dict=True)
for pe in linked_pe: if not reference_rows:
try: return
pe_doc = frappe.get_doc("Payment Entry", pe)
pe_doc.set_amounts()
# Call cancel on only removed reference linked_pe = set()
references = [ row_names = set()
x
for x in pe_doc.references
if x.reference_doctype == ref_type and x.reference_name == ref_no
]
[pe_doc.make_advance_gl_entries(x, cancel=1) for x in references]
pe_doc.clear_unallocated_reference_document_rows() for row in reference_rows:
pe_doc.validate_payment_type_with_outstanding() linked_pe.add(row.parent)
except Exception: row_names.add(row.name)
msg = _("There were issues unlinking payment entry {0}.").format(pe_doc.name)
msg += "<br>"
msg += _("Please cancel payment entry manually first")
frappe.throw(msg, exc=PaymentEntryUnlinkError, title=_("Payment Unlink Error"))
qb.update(pay).set(pay.total_allocated_amount, pe_doc.total_allocated_amount).set( from erpnext.accounts.doctype.payment_request.payment_request import (
pay.base_total_allocated_amount, pe_doc.base_total_allocated_amount update_payment_requests_as_per_pe_references,
).set(pay.unallocated_amount, pe_doc.unallocated_amount).set(pay.modified, now()).set( )
pay.modified_by, frappe.session.user
).where(pay.name == pe).run()
frappe.msgprint(_("Payment Entries {0} are un-linked").format("\n".join(linked_pe))) # Update payment request amount
update_payment_requests_as_per_pe_references(reference_rows, cancel=True)
# Update allocated amounts and modified fields in one go
(
qb.update(per)
.set(per.allocated_amount, 0)
.set(per.modified, now())
.set(per.modified_by, frappe.session.user)
.where(per.name.isin(row_names))
.where(per.parenttype == "Payment Entry")
.run()
)
for pe in linked_pe:
try:
pe_doc = frappe.get_doc("Payment Entry", pe)
pe_doc.set_amounts()
# Call cancel on only removed reference
references = [x for x in pe_doc.references if x.name in row_names]
[pe_doc.make_advance_gl_entries(x, cancel=1) for x in references]
pe_doc.clear_unallocated_reference_document_rows()
pe_doc.validate_payment_type_with_outstanding()
except Exception:
msg = _("There were issues unlinking payment entry {0}.").format(pe_doc.name)
msg += "<br>"
msg += _("Please cancel payment entry manually first")
frappe.throw(msg, exc=PaymentEntryUnlinkError, title=_("Payment Unlink Error"))
(
qb.update(pay)
.set(pay.total_allocated_amount, pe_doc.total_allocated_amount)
.set(pay.base_total_allocated_amount, pe_doc.base_total_allocated_amount)
.set(pay.unallocated_amount, pe_doc.unallocated_amount)
.set(pay.modified, now())
.set(pay.modified_by, frappe.session.user)
.where(pay.name == pe)
.run()
)
frappe.msgprint(_("Payment Entries {0} are un-linked").format("\n".join(linked_pe)))
@frappe.whitelist() @frappe.whitelist()