From 25b43d5f35cf766b8e2bb0b13ec5845d6e4f58f6 Mon Sep 17 00:00:00 2001 From: HemilSangani Date: Tue, 26 May 2026 12:17:25 +0530 Subject: [PATCH 1/3] fix: handle missing repayment schedule in advance payment validation --- .../doctype/loan_repayment/loan_repayment.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lending/loan_management/doctype/loan_repayment/loan_repayment.py b/lending/loan_management/doctype/loan_repayment/loan_repayment.py index 7dbed2c70..4e1519884 100644 --- a/lending/loan_management/doctype/loan_repayment/loan_repayment.py +++ b/lending/loan_management/doctype/loan_repayment/loan_repayment.py @@ -1735,14 +1735,19 @@ def validate_advance_payment(self, amount_paid, amounts, on_submit): if self.loan_disbursement: filters["loan_disbursement"] = self.loan_disbursement - monthly_repayment_amount = frappe.db.get_value( - "Loan Repayment Schedule", - filters, - "monthly_repayment_amount", + monthly_repayment_amount = flt( + frappe.db.get_value( + "Loan Repayment Schedule", + filters, + "monthly_repayment_amount", + ), + precision ) - if (flt(amount_paid, precision) < monthly_repayment_amount) or ( - flt(amount_paid, precision) > (2 * monthly_repayment_amount) + amount_paid = flt(amount_paid, precision) + + if (amount_paid < monthly_repayment_amount) or ( + amount_paid > (2 * monthly_repayment_amount) ): frappe.throw(_("Amount for advance payment must be between one to two EMI amount")) From 765680831fb4b31cb46f83572ffe83d6485d17bf Mon Sep 17 00:00:00 2001 From: HemilSangani Date: Tue, 26 May 2026 16:59:01 +0530 Subject: [PATCH 2/3] fix: handle missing Loan Repayment Schedule in advance payment validation --- .../doctype/loan_repayment/loan_repayment.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lending/loan_management/doctype/loan_repayment/loan_repayment.py b/lending/loan_management/doctype/loan_repayment/loan_repayment.py index 4e1519884..78cbaad9c 100644 --- a/lending/loan_management/doctype/loan_repayment/loan_repayment.py +++ b/lending/loan_management/doctype/loan_repayment/loan_repayment.py @@ -1735,15 +1735,16 @@ def validate_advance_payment(self, amount_paid, amounts, on_submit): if self.loan_disbursement: filters["loan_disbursement"] = self.loan_disbursement - monthly_repayment_amount = flt( - frappe.db.get_value( - "Loan Repayment Schedule", - filters, - "monthly_repayment_amount", - ), - precision + monthly_repayment_amount = frappe.db.get_value( + "Loan Repayment Schedule", + filters, + "monthly_repayment_amount", ) + if not monthly_repayment_amount: + frappe.throw(_("Cannot process Advance Payment: No active Loan Repayment Schedule found for this loan")) + + monthly_repayment_amount = flt(monthly_repayment_amount, precision) amount_paid = flt(amount_paid, precision) if (amount_paid < monthly_repayment_amount) or ( From ac867bbf6fc47cbdd76a1f691cbf17a11ca130d6 Mon Sep 17 00:00:00 2001 From: Hemil-Sangani Date: Tue, 2 Jun 2026 19:30:34 +0530 Subject: [PATCH 3/3] test(loan_repayment): add test for advance payment when no active repayment schedule exists --- .../loan_repayment/test_loan_repayment.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/lending/loan_management/doctype/loan_repayment/test_loan_repayment.py b/lending/loan_management/doctype/loan_repayment/test_loan_repayment.py index 8418e7ecf..52fe43cc9 100644 --- a/lending/loan_management/doctype/loan_repayment/test_loan_repayment.py +++ b/lending/loan_management/doctype/loan_repayment/test_loan_repayment.py @@ -2,6 +2,7 @@ # See license.txt import frappe +from frappe import _ from frappe.query_builder import DocType from frappe.query_builder import functions as fn from frappe.utils import add_days, add_months, date_diff, flt, get_datetime, getdate @@ -1938,3 +1939,44 @@ def test_no_repayment_after_full_settlement_except_waivers(self): create_repayment_entry( loan.name, "2025-09-06", 5000, repayment_type="Normal Repayment" ) + + def test_advance_payment_no_active_schedule(self): + set_loan_accrual_frequency(loan_accrual_frequency="Daily") + + loan = create_loan( + "_Test Customer 1", + "Term Loan Product 4", + 200000, + "Repay Over Number of Periods", + 12, + repayment_start_date="2025-01-05", + posting_date="2024-12-26", + rate_of_interest=31, + applicant_type="Customer", + ) + loan.submit() + + make_loan_disbursement_entry( + loan.name, + loan.loan_amount, + disbursement_date="2024-12-26", + repayment_start_date="2025-01-05", + ) + + # Deactivate the repayment schedule to simulate no active schedule + schedule_name = frappe.db.get_value( + "Loan Repayment Schedule", + {"loan": loan.name, "docstatus": 1, "status": "Active"}, + "name", + ) + frappe.db.set_value("Loan Repayment Schedule", schedule_name, "status", "Closed") + + with self.assertRaises(frappe.ValidationError) as ctx: + create_repayment_entry( + loan.name, "2025-01-03", paid_amount=19596, repayment_type="Advance Payment" + ) + + self.assertIn( + _("Cannot process Advance Payment: No active Loan Repayment Schedule found for this loan"), + str(ctx.exception), + )