From 8d8027d4233f9181a34ee00b33ff15da2cae2da4 Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Tue, 26 Nov 2024 13:58:52 +0530 Subject: [PATCH 1/4] fix: set outstanding amount while creating payment request for invoices (cherry picked from commit 38e7d0a41e2a55ef98f2c6147c34b64708929854) --- erpnext/accounts/doctype/payment_request/payment_request.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index ae974a8cf0e..aaae8204a9b 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -667,11 +667,9 @@ def get_amount(ref_doc, payment_account=None): elif dt in ["Sales Invoice", "Purchase Invoice"]: if not ref_doc.get("is_pos"): if ref_doc.party_account_currency == ref_doc.currency: - grand_total = flt(ref_doc.rounded_total or ref_doc.grand_total) + grand_total = flt(ref_doc.outstanding_amount) else: - grand_total = flt( - flt(ref_doc.base_rounded_total or ref_doc.base_grand_total) / ref_doc.conversion_rate - ) + grand_total = flt(flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate) elif dt == "Sales Invoice": for pay in ref_doc.payments: if pay.type == "Phone" and pay.account == payment_account: From 81b9832917ebf5487f5471b007d47278252cde02 Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Tue, 26 Nov 2024 13:59:45 +0530 Subject: [PATCH 2/4] test: add unit test to validate outstanding amount in payment request (cherry picked from commit bbe3bc95d08950bebc9ede64c11c9660a564a8a6) # Conflicts: # erpnext/accounts/doctype/payment_request/test_payment_request.py --- .../payment_request/test_payment_request.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/erpnext/accounts/doctype/payment_request/test_payment_request.py b/erpnext/accounts/doctype/payment_request/test_payment_request.py index b0c3dbf4d5b..cd5a1a26575 100644 --- a/erpnext/accounts/doctype/payment_request/test_payment_request.py +++ b/erpnext/accounts/doctype/payment_request/test_payment_request.py @@ -7,6 +7,7 @@ import unittest import frappe from frappe.tests.utils import FrappeTestCase, change_settings +from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_terms_template from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice @@ -524,3 +525,25 @@ class TestPaymentRequest(FrappeTestCase): self.assertEqual(pr.grand_total, 1000) 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) +>>>>>>> bbe3bc95d0 (test: add unit test to validate outstanding amount in payment request) From d0d97c26a05ab961f88ece2609698ff37f3a5273 Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Wed, 27 Nov 2024 17:41:16 +0530 Subject: [PATCH 3/4] fix: reduce paid amount from grand total (cherry picked from commit 82907672d938b2b447f0f7382e8fc4e4c343e708) --- .../payment_request/payment_request.py | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py index aaae8204a9b..1d31fd4b67b 100644 --- a/erpnext/accounts/doctype/payment_request/payment_request.py +++ b/erpnext/accounts/doctype/payment_request/payment_request.py @@ -3,7 +3,7 @@ import json import frappe from frappe import _, qb from frappe.model.document import Document -from frappe.query_builder.functions import Sum +from frappe.query_builder.functions import Abs, Sum from frappe.utils import flt, nowdate from frappe.utils.background_jobs import enqueue @@ -564,6 +564,8 @@ def make_payment_request(**args): # fetches existing payment request `grand_total` amount existing_payment_request_amount = get_existing_payment_request_amount(ref_doc.doctype, ref_doc.name) + existing_paid_amount = get_existing_paid_amount(ref_doc.doctype, ref_doc.name) + def validate_and_calculate_grand_total(grand_total, existing_payment_request_amount): grand_total -= existing_payment_request_amount if not grand_total: @@ -583,6 +585,15 @@ def make_payment_request(**args): else: grand_total = validate_and_calculate_grand_total(grand_total, existing_payment_request_amount) + if existing_paid_amount: + if ref_doc.party_account_currency == ref_doc.currency: + if ref_doc.conversion_rate: + grand_total -= flt(existing_paid_amount / ref_doc.conversion_rate) + else: + grand_total -= flt(existing_paid_amount) + else: + grand_total -= flt(existing_paid_amount / ref_doc.conversion_rate) + if draft_payment_request: frappe.db.set_value( "Payment Request", draft_payment_request, "grand_total", grand_total, update_modified=False @@ -667,9 +678,11 @@ def get_amount(ref_doc, payment_account=None): elif dt in ["Sales Invoice", "Purchase Invoice"]: if not ref_doc.get("is_pos"): if ref_doc.party_account_currency == ref_doc.currency: - grand_total = flt(ref_doc.outstanding_amount) + grand_total = flt(ref_doc.rounded_total or ref_doc.grand_total) else: - grand_total = flt(flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate) + grand_total = flt( + flt(ref_doc.base_rounded_total or ref_doc.base_grand_total) / ref_doc.conversion_rate + ) elif dt == "Sales Invoice": for pay in ref_doc.payments: if pay.type == "Phone" and pay.account == payment_account: @@ -751,6 +764,27 @@ def get_existing_payment_request_amount(ref_dt, ref_dn, statuses: list | None = return response[0][0] if response[0] else 0 +def get_existing_paid_amount(doctype, name): + PL = frappe.qb.DocType("Payment Ledger Entry") + PER = frappe.qb.DocType("Payment Entry Reference") + + query = ( + frappe.qb.from_(PL) + .left_join(PER) + .on( + (PER.reference_doctype == PL.against_voucher_type) & (PER.reference_name == PL.against_voucher_no) + ) + .select(Abs(Sum(PL.amount)).as_("total_paid_amount")) + .where(PL.against_voucher_type.eq(doctype)) + .where(PL.against_voucher_no.eq(name)) + .where(PL.amount < 0) + .where(PER.payment_request.isnull()) + ) + response = query.run() + + return response[0][0] if response[0] else 0 + + def get_gateway_details(args): # nosemgrep """ Return gateway and payment account of default payment gateway From 0ab0b4f716acee6837e7c62f875a99c2d11881ef Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 27 Nov 2024 20:29:36 +0530 Subject: [PATCH 4/4] chore: resolve conflict --- .../accounts/doctype/payment_request/test_payment_request.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/erpnext/accounts/doctype/payment_request/test_payment_request.py b/erpnext/accounts/doctype/payment_request/test_payment_request.py index cd5a1a26575..4442dbdd7ea 100644 --- a/erpnext/accounts/doctype/payment_request/test_payment_request.py +++ b/erpnext/accounts/doctype/payment_request/test_payment_request.py @@ -525,9 +525,6 @@ class TestPaymentRequest(FrappeTestCase): self.assertEqual(pr.grand_total, 1000) 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) @@ -546,4 +543,3 @@ class TestPaymentRequest(FrappeTestCase): pr = make_payment_request(dt="Sales Invoice", dn=si.name, mute_email=1) self.assertEqual(pr.grand_total, si.outstanding_amount) ->>>>>>> bbe3bc95d0 (test: add unit test to validate outstanding amount in payment request)