diff --git a/lending/loan_management/doctype/loan_repayment/loan_repayment.py b/lending/loan_management/doctype/loan_repayment/loan_repayment.py index 06d00a0aa..7dbed2c70 100644 --- a/lending/loan_management/doctype/loan_repayment/loan_repayment.py +++ b/lending/loan_management/doctype/loan_repayment/loan_repayment.py @@ -124,10 +124,14 @@ def validate(self): charges = None if self.get("payable_charges"): - if self.repayment_type == "Charge Payment" or (self.repayment_type in ("Charges Waiver", "Charges Capitalization") and self.loan_restructure): + if self.repayment_type == "Charge Payment" or (self.repayment_type in ("Charges Waiver", "Charges Capitalization", "Principal Capitalization") and self.loan_restructure): charges = [d.get("charge_code") for d in self.get("payable_charges")] else: - frappe.throw(_("Payable Charges can only be added if Charge Payment, or for Charges Waiver/Capitalization during Loan Restructure")) + frappe.throw( + _( + "Payable Charges can only be added for Charge Payment, or for Charges Waiver/Charges Capitalization/Principal Capitalization during Loan Restructure" + ) + ) amounts = calculate_amounts( self.against_loan, @@ -1533,7 +1537,14 @@ def allocate_amounts(self, amounts, on_submit=False): amounts = self.update_amounts_for_write_off_recovery(loan_status, amounts) amount_paid = self.amount_paid - if self.repayment_type == "Charge Payment" or (self.repayment_type in ("Charges Waiver", "Charges Capitalization") and self.loan_restructure): + if self.repayment_type == "Charge Payment" or ( + self.repayment_type in ("Charges Waiver", "Charges Capitalization") + and self.loan_restructure + ) or ( + self.repayment_type == "Principal Capitalization" + and self.loan_restructure + and self.get("payable_charges") + ): amount_paid = self.allocate_charges(amount_paid, amounts.get("unpaid_demands")) else: amount_paid = self.allocate_amount_against_demands(loan_status, amounts, amount_paid) @@ -2019,7 +2030,9 @@ def make_gl_entries(self, cancel=0, adv_adj=0): ) return - if self.repayment_type == "Principal Capitalization" and self.loan_restructure: + if self.repayment_type == "Principal Capitalization" and self.loan_restructure and not any( + d.sales_invoice for d in self.get("repayment_details") + ): return if cancel: @@ -2346,6 +2359,7 @@ def get_payment_account(self): "Interest Capitalization": "loan_account", "Penalty Capitalization": "loan_account", "Charges Capitalization": "loan_account", + "Principal Capitalization": "loan_account", } if self.repayment_type in ( diff --git a/lending/loan_management/doctype/loan_restructure/loan_restructure.py b/lending/loan_management/doctype/loan_restructure/loan_restructure.py index c371738f1..bd0e6a09b 100644 --- a/lending/loan_management/doctype/loan_restructure/loan_restructure.py +++ b/lending/loan_management/doctype/loan_restructure/loan_restructure.py @@ -814,7 +814,7 @@ def make_post_restructure_charge_demands(self): ] if post_restructure_charges: - make_sales_invoice_for_charge( + sales_invoice = make_sales_invoice_for_charge( self.loan, "loan_restructure", self.name, @@ -823,6 +823,15 @@ def make_post_restructure_charge_demands(self): self.company, post_restructure_charges, ) + if sales_invoice: + create_loan_repayment( + self.loan, + self.restructure_date, + "Principal Capitalization", + sales_invoice.grand_total, + restructure_name=self.name, + charge_code=post_restructure_charges + ) def make_loan_repayment_for_adjustment(self): if self.principal_adjusted: @@ -874,10 +883,17 @@ def create_loan_repayment( repayment.loan_disbursement = loan_disbursement if charge_code and waiver_amount > 0: - repayment.append("payable_charges", { - "charge_code": charge_code, - "amount": waiver_amount - }) + if isinstance(charge_code, list): + for charge in charge_code: + repayment.append("payable_charges", { + "charge_code": charge.get("charge"), + "amount": charge.get("amount") + }) + else: + repayment.append("payable_charges", { + "charge_code": charge_code, + "amount": waiver_amount + }) repayment.save() repayment.submit() diff --git a/lending/loan_management/doctype/loan_restructure/test_loan_restructure.py b/lending/loan_management/doctype/loan_restructure/test_loan_restructure.py index 8ff6e6dc0..d7d50d08c 100644 --- a/lending/loan_management/doctype/loan_restructure/test_loan_restructure.py +++ b/lending/loan_management/doctype/loan_restructure/test_loan_restructure.py @@ -195,7 +195,7 @@ def test_loan_restructure_charges_waiver_and_capitalization(self): process_daily_loan_demands(loan=loan.name, posting_date="2024-04-05") - sales_invoice = frappe.get_doc( + frappe.get_doc( { "doctype": "Sales Invoice", "customer": "_Test Customer 1", @@ -212,10 +212,9 @@ def test_loan_restructure_charges_waiver_and_capitalization(self): {"item_code": "Documentation Charge", "qty": 1, "rate": 3000}, ], } - ) - sales_invoice.submit() + ).submit() - sales_invoice = frappe.get_doc( + frappe.get_doc( { "doctype": "Sales Invoice", "customer": "_Test Customer 1", @@ -227,8 +226,7 @@ def test_loan_restructure_charges_waiver_and_capitalization(self): "set_posting_time": 1, "items": [{"item_code": "Processing Fee", "qty": 1, "rate": 2000}], } - ) - sales_invoice.submit() + ).submit() loan_restructure = create_loan_restructure( loan=loan.name, @@ -244,26 +242,32 @@ def test_loan_restructure_charges_waiver_and_capitalization(self): loan_restructure.status = "Approved" loan_restructure.save() - invoices = frappe.db.get_all( - "Sales Invoice", - filters={"loan": loan.name, "docstatus": 1, "value_date": "2024-04-11"}, - pluck="name", - ) - self.assertEqual(len(invoices), 1, "Expected 1 Sales Invoice to be created for post-restructure charges.") - repayments = frappe.db.get_all( "Loan Repayment", filters={"loan_restructure": loan_restructure.name, "docstatus": 1}, pluck="repayment_type", ) - self.assertEqual(len(repayments), 7) + self.assertEqual(len(repayments), 8) counts = Counter(repayments) self.assertEqual(counts.get("Charges Capitalization", 0), 2) self.assertEqual(counts.get("Charges Waiver", 0), 1) + sales_invoice = frappe.db.get_value( + "Sales Invoice", + { + "loan": loan.name, + "docstatus": 1, + "value_date": "2024-04-11", + }, + ["outstanding_amount", "status"], + as_dict=True, + ) + self.assertEqual(flt(sales_invoice.outstanding_amount), 0, "Expected the Sales Invoice for post-restructure charges to be fully paid.") + self.assertEqual(sales_invoice.status, "Paid", "Expected the Sales Invoice for post-restructure charges to have status 'Paid'.") + def test_unaccrued_interest_capitalization_gl_entries(self): set_loan_accrual_frequency(loan_accrual_frequency="Daily") diff --git a/lending/patches.txt b/lending/patches.txt index 115456d2d..ca04f8dba 100644 --- a/lending/patches.txt +++ b/lending/patches.txt @@ -47,4 +47,4 @@ lending.patches.v1_0.update_value_date_in_loan_repayment lending.patches.v1_0.update_value_date_in_loan_refund lending.patches.v1_0.update_value_date_in_pending_doctypes lending.patches.v16_0.add_enable_loan_accounting_field -lending.patches.v16_0.update_is_invoice_generated_field +lending.patches.v16_0.update_is_invoice_generated_field \ No newline at end of file