mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-26 16:34:46 +00:00
fix: update payment request outstanding on unreconciliation
(cherry picked from commit 8098229b55)
# Conflicts:
# erpnext/accounts/doctype/payment_request/test_payment_request.py
# erpnext/accounts/utils.py
This commit is contained in:
@@ -698,8 +698,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}]},
|
||||||
|
|||||||
@@ -524,3 +524,142 @@ class TestPaymentRequest(FrappeTestCase):
|
|||||||
self.assertEqual(pr.grand_total, 1000)
|
self.assertEqual(pr.grand_total, 1000)
|
||||||
|
|
||||||
so.load_from_db()
|
so.load_from_db()
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
self.assertEqual(so.advance_payment_status, "Requested")
|
||||||
|
|
||||||
|
def test_partial_paid_invoice_with_payment_request(self):
|
||||||
|
si = create_sales_invoice(currency="INR", qty=1, rate=5000)
|
||||||
|
si.save()
|
||||||
|
si.submit()
|
||||||
|
|
||||||
|
pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC")
|
||||||
|
pe.reference_no = "PAYEE0002"
|
||||||
|
pe.reference_date = frappe.utils.nowdate()
|
||||||
|
pe.paid_amount = 2500
|
||||||
|
pe.references[0].allocated_amount = 2500
|
||||||
|
pe.save()
|
||||||
|
pe.submit()
|
||||||
|
|
||||||
|
si.load_from_db()
|
||||||
|
pr = make_payment_request(dt="Sales Invoice", dn=si.name, mute_email=1)
|
||||||
|
|
||||||
|
self.assertEqual(pr.grand_total, si.outstanding_amount)
|
||||||
|
|
||||||
|
def test_partial_paid_invoice_with_more_payment_entry(self):
|
||||||
|
pi = make_purchase_invoice(currency="INR", qty=1, rate=500)
|
||||||
|
pi.submit()
|
||||||
|
pi_1 = make_purchase_invoice(currency="INR", qty=1, rate=300)
|
||||||
|
pi_1.submit()
|
||||||
|
|
||||||
|
pr = make_payment_request(dt="Purchase Invoice", dn=pi.name, mute_email=1, submit_doc=0, return_doc=1)
|
||||||
|
pr.grand_total = 200
|
||||||
|
pr.submit()
|
||||||
|
pr.create_payment_entry()
|
||||||
|
pr_1 = make_payment_request(
|
||||||
|
dt="Purchase Invoice", dn=pi.name, mute_email=1, submit_doc=0, return_doc=1
|
||||||
|
)
|
||||||
|
pr_1.grand_total = 200
|
||||||
|
pr_1.submit()
|
||||||
|
pr_1.create_payment_entry()
|
||||||
|
|
||||||
|
pe = get_payment_entry(dt="Purchase Invoice", dn=pi.name)
|
||||||
|
pe.paid_amount = 200
|
||||||
|
pe.references[0].reference_doctype = pi.doctype
|
||||||
|
pe.references[0].reference_name = pi.name
|
||||||
|
pe.references[0].grand_total = pi.grand_total
|
||||||
|
pe.references[0].outstanding_amount = pi.outstanding_amount
|
||||||
|
pe.references[0].allocated_amount = 100
|
||||||
|
pe.append(
|
||||||
|
"references",
|
||||||
|
{
|
||||||
|
"reference_doctype": pi_1.doctype,
|
||||||
|
"reference_name": pi_1.name,
|
||||||
|
"grand_total": pi_1.grand_total,
|
||||||
|
"outstanding_amount": pi_1.outstanding_amount,
|
||||||
|
"allocated_amount": 100,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
pr_2 = make_payment_request(dt="Purchase Invoice", dn=pi.name, mute_email=1)
|
||||||
|
pi.load_from_db()
|
||||||
|
self.assertEqual(pr_2.grand_total, pi.outstanding_amount)
|
||||||
|
|
||||||
|
def test_consider_journal_entry_and_return_invoice(self):
|
||||||
|
from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
|
||||||
|
|
||||||
|
si = create_sales_invoice(currency="INR", qty=5, rate=500)
|
||||||
|
|
||||||
|
je = make_journal_entry("_Test Cash - _TC", "Debtors - _TC", 500, save=False)
|
||||||
|
je.accounts[1].party_type = "Customer"
|
||||||
|
je.accounts[1].party = si.customer
|
||||||
|
je.accounts[1].reference_type = "Sales Invoice"
|
||||||
|
je.accounts[1].reference_name = si.name
|
||||||
|
je.accounts[1].credit_in_account_currency = 500
|
||||||
|
je.submit()
|
||||||
|
|
||||||
|
pe = get_payment_entry("Sales Invoice", si.name)
|
||||||
|
pe.paid_amount = 500
|
||||||
|
pe.references[0].allocated_amount = 500
|
||||||
|
pe.save()
|
||||||
|
pe.submit()
|
||||||
|
|
||||||
|
cr_note = create_sales_invoice(qty=-1, rate=500, is_return=1, return_against=si.name, do_not_save=1)
|
||||||
|
cr_note.update_outstanding_for_self = 0
|
||||||
|
cr_note.save()
|
||||||
|
cr_note.submit()
|
||||||
|
|
||||||
|
si.load_from_db()
|
||||||
|
pr = make_payment_request(dt="Sales Invoice", dn=si.name, mute_email=1)
|
||||||
|
self.assertEqual(pr.grand_total, si.outstanding_amount)
|
||||||
|
|
||||||
|
def test_partial_paid_invoice_with_submitted_payment_entry(self):
|
||||||
|
pi = make_purchase_invoice(currency="INR", qty=1, rate=5000)
|
||||||
|
pi.save()
|
||||||
|
pi.submit()
|
||||||
|
|
||||||
|
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
|
||||||
|
pe.reference_no = "PURINV0001"
|
||||||
|
pe.reference_date = frappe.utils.nowdate()
|
||||||
|
pe.paid_amount = 2500
|
||||||
|
pe.references[0].allocated_amount = 2500
|
||||||
|
pe.save()
|
||||||
|
pe.submit()
|
||||||
|
pe.cancel()
|
||||||
|
|
||||||
|
pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
|
||||||
|
pe.reference_no = "PURINV0002"
|
||||||
|
pe.reference_date = frappe.utils.nowdate()
|
||||||
|
pe.paid_amount = 2500
|
||||||
|
pe.references[0].allocated_amount = 2500
|
||||||
|
pe.save()
|
||||||
|
pe.submit()
|
||||||
|
|
||||||
|
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)
|
||||||
|
|||||||
@@ -920,30 +920,24 @@ 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)
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
for pe in linked_pe:
|
for pe in linked_pe:
|
||||||
try:
|
try:
|
||||||
pe_doc = frappe.get_doc("Payment Entry", pe)
|
pe_doc = frappe.get_doc("Payment Entry", pe)
|
||||||
@@ -955,14 +949,64 @@ def remove_ref_doc_link_from_pe(
|
|||||||
msg += "<br>"
|
msg += "<br>"
|
||||||
msg += _("Please cancel payment entry manually first")
|
msg += _("Please cancel payment entry manually first")
|
||||||
frappe.throw(msg, exc=PaymentEntryUnlinkError, title=_("Payment Unlink Error"))
|
frappe.throw(msg, exc=PaymentEntryUnlinkError, title=_("Payment Unlink Error"))
|
||||||
|
=======
|
||||||
|
if not reference_rows:
|
||||||
|
return
|
||||||
|
|
||||||
qb.update(pay).set(pay.total_allocated_amount, pe_doc.total_allocated_amount).set(
|
linked_pe = set()
|
||||||
pay.base_total_allocated_amount, pe_doc.base_total_allocated_amount
|
row_names = set()
|
||||||
).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)))
|
for row in reference_rows:
|
||||||
|
linked_pe.add(row.parent)
|
||||||
|
row_names.add(row.name)
|
||||||
|
>>>>>>> 8098229b55 (fix: update payment request outstanding on unreconciliation)
|
||||||
|
|
||||||
|
from erpnext.accounts.doctype.payment_request.payment_request import (
|
||||||
|
update_payment_requests_as_per_pe_references,
|
||||||
|
)
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|||||||
Reference in New Issue
Block a user