From 2f70cf0f44ac45a3c882c55b0398c14ddcb9ffb7 Mon Sep 17 00:00:00 2001 From: Aysha Date: Wed, 15 Jan 2025 16:19:04 +0530 Subject: [PATCH 1/4] fix: handle loan repayment on fnf submission (cherry picked from commit a0b56e1657363496851a7f9239a52a92f4bcb626) --- .../full_and_final_statement.py | 5 ++ .../full_and_final_statement_loan_utils.py | 78 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 hrms/hr/doctype/full_and_final_statement/full_and_final_statement_loan_utils.py diff --git a/hrms/hr/doctype/full_and_final_statement/full_and_final_statement.py b/hrms/hr/doctype/full_and_final_statement/full_and_final_statement.py index dd1a4ba2e6..82a2deeff8 100644 --- a/hrms/hr/doctype/full_and_final_statement/full_and_final_statement.py +++ b/hrms/hr/doctype/full_and_final_statement/full_and_final_statement.py @@ -6,6 +6,8 @@ from frappe.model.document import Document from frappe.utils import flt, get_link_to_form, today +from hrms.hr.doctype.full_and_final_statement.full_and_final_statement_loan_utils import process_loan_accrual + class FullandFinalStatement(Document): def before_insert(self): @@ -22,6 +24,9 @@ def before_submit(self): self.validate_settlement("receivables") self.validate_assets() + def on_submit(self): + process_loan_accrual(self) + def on_cancel(self): self.ignore_linked_doctypes = ("GL Entry",) diff --git a/hrms/hr/doctype/full_and_final_statement/full_and_final_statement_loan_utils.py b/hrms/hr/doctype/full_and_final_statement/full_and_final_statement_loan_utils.py new file mode 100644 index 0000000000..50603e5449 --- /dev/null +++ b/hrms/hr/doctype/full_and_final_statement/full_and_final_statement_loan_utils.py @@ -0,0 +1,78 @@ +# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from typing import TYPE_CHECKING + +import frappe +from frappe import _ + +from hrms.payroll.doctype.salary_slip.salary_slip_loan_utils import if_lending_app_installed + +if TYPE_CHECKING: + from hrms.payroll.doctype.full_and_final_statement.full_and_final_statement import FullandFinalStatement + + +@if_lending_app_installed +def process_loan_accrual(doc: "FullandFinalStatement"): + from lending.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import ( + make_loan_interest_accrual_entry, + ) + from lending.loan_management.doctype.loan_repayment.loan_repayment import ( + calculate_amounts, + create_repayment_entry, + get_pending_principal_amount, + ) + + loan_receivables = [] + for receivable in doc.receivables: + if receivable.component != "Loan": + continue + + loan_receivables.append(receivable.reference_document) + + loan_receivables = list(set(loan_receivables)) + + for loan in loan_receivables: + loan_doc = frappe.get_doc("Loan", loan) + loan_repayment_schedule = frappe.get_doc("Loan Repayment Schedule", {"loan": loan, "docstatus": 1}) + if loan_repayment_schedule.repayment_schedule: + amounts = [] + for repayment_schedule in loan_repayment_schedule.repayment_schedule: + amounts = calculate_amounts(loan, doc.transaction_date, "Normal Repayment") + pending_principal_amount = get_pending_principal_amount(loan_doc) + if not repayment_schedule.is_accrued: + args = frappe._dict( + { + "loan": loan, + "applicant_type": loan_doc.applicant_type, + "applicant": loan_doc.applicant, + "interest_income_account": loan_doc.interest_income_account, + "loan_account": loan_doc.loan_account, + "pending_principal_amount": amounts["pending_principal_amount"], + "payable_principal": repayment_schedule.principal_amount, + "interest_amount": repayment_schedule.interest_amount, + "total_pending_interest_amount": pending_principal_amount, + "penalty_amount": amounts["penalty_amount"], + "posting_date": doc.transaction_date, + "repayment_schedule_name": repayment_schedule.name, + "accrual_type": "Regular", + "due_date": doc.transaction_date, + } + ) + make_loan_interest_accrual_entry(args) + frappe.db.set_value("Repayment Schedule", repayment_schedule.name, "is_accrued", 1) + + repayment_entry = create_repayment_entry( + loan, + doc.employee, + doc.company, + doc.transaction_date, + loan_doc.loan_product, + "Normal Repayment", + amounts["interest_amount"], + amounts["pending_principal_amount"], + receivable.amount, + ) + + repayment_entry.save() + repayment_entry.submit() From 0c62a3b81235d3b099842a130486724c6a0206ed Mon Sep 17 00:00:00 2001 From: Aysha Date: Wed, 15 Jan 2025 16:54:38 +0530 Subject: [PATCH 2/4] fix: cancell loan repayment on fnf cancellation (cherry picked from commit a77be530109da5d32ae81027e0957952d481b1d5) --- .../full_and_final_statement.py | 8 ++++-- .../full_and_final_statement_loan_utils.py | 28 +++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/hrms/hr/doctype/full_and_final_statement/full_and_final_statement.py b/hrms/hr/doctype/full_and_final_statement/full_and_final_statement.py index 82a2deeff8..83f607db17 100644 --- a/hrms/hr/doctype/full_and_final_statement/full_and_final_statement.py +++ b/hrms/hr/doctype/full_and_final_statement/full_and_final_statement.py @@ -6,7 +6,10 @@ from frappe.model.document import Document from frappe.utils import flt, get_link_to_form, today -from hrms.hr.doctype.full_and_final_statement.full_and_final_statement_loan_utils import process_loan_accrual +from hrms.hr.doctype.full_and_final_statement.full_and_final_statement_loan_utils import ( + cancel_loan_repayment, + process_loan_accrual, +) class FullandFinalStatement(Document): @@ -28,7 +31,8 @@ def on_submit(self): process_loan_accrual(self) def on_cancel(self): - self.ignore_linked_doctypes = ("GL Entry",) + self.ignore_linked_doctypes = "GL Entry" + cancel_loan_repayment(self) def validate_relieving_date(self): if not self.relieving_date: diff --git a/hrms/hr/doctype/full_and_final_statement/full_and_final_statement_loan_utils.py b/hrms/hr/doctype/full_and_final_statement/full_and_final_statement_loan_utils.py index 50603e5449..e20332ca69 100644 --- a/hrms/hr/doctype/full_and_final_statement/full_and_final_statement_loan_utils.py +++ b/hrms/hr/doctype/full_and_final_statement/full_and_final_statement_loan_utils.py @@ -30,8 +30,6 @@ def process_loan_accrual(doc: "FullandFinalStatement"): loan_receivables.append(receivable.reference_document) - loan_receivables = list(set(loan_receivables)) - for loan in loan_receivables: loan_doc = frappe.get_doc("Loan", loan) loan_repayment_schedule = frappe.get_doc("Loan Repayment Schedule", {"loan": loan, "docstatus": 1}) @@ -76,3 +74,29 @@ def process_loan_accrual(doc: "FullandFinalStatement"): repayment_entry.save() repayment_entry.submit() + + +@if_lending_app_installed +def cancel_loan_repayment(doc: "FullandFinalStatement"): + loan_receivables = [] + for receivable in doc.receivables: + if receivable.component != "Loan": + continue + + loan_receivables.append(receivable.reference_document) + + # loan_receivables = list(set(loan_receivables)) + for loan in loan_receivables: + posting_date = frappe.utils.getdate(doc.transaction_date) + loan_repayment = frappe.get_doc( + "Loan Repayment", {"against_loan": loan, "docstatus": 1, "posting_date": posting_date} + ) + + if loan_repayment: + loan_repayment.cancel() + + loan_interest_accruals = frappe.get_all( + "Loan Interest Accrual", filters={"loan": loan, "docstatus": 1, "posting_date": posting_date} + ) + for accrual in loan_interest_accruals: + frappe.get_doc("Loan Interest Accrual", accrual.name).cancel() From 148d73da4816c741de3aecb4d2a41d5bde946e59 Mon Sep 17 00:00:00 2001 From: Aysha Date: Wed, 15 Jan 2025 16:57:51 +0530 Subject: [PATCH 3/4] fix: undo change (cherry picked from commit 054d0219aac33d838f9e549c314f306bca135ab9) --- .../full_and_final_statement/full_and_final_statement.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrms/hr/doctype/full_and_final_statement/full_and_final_statement.py b/hrms/hr/doctype/full_and_final_statement/full_and_final_statement.py index 83f607db17..4d334c6ecd 100644 --- a/hrms/hr/doctype/full_and_final_statement/full_and_final_statement.py +++ b/hrms/hr/doctype/full_and_final_statement/full_and_final_statement.py @@ -31,7 +31,7 @@ def on_submit(self): process_loan_accrual(self) def on_cancel(self): - self.ignore_linked_doctypes = "GL Entry" + self.ignore_linked_doctypes = ("GL Entry",) cancel_loan_repayment(self) def validate_relieving_date(self): From b420fe800988d207b70807044b8b915c7b8673a8 Mon Sep 17 00:00:00 2001 From: Aysha Date: Wed, 15 Jan 2025 17:00:10 +0530 Subject: [PATCH 4/4] chore: remove commented code (cherry picked from commit 2f8014dcd1dfb95a17fc21f48ae9b59d2e3c18f4) --- .../full_and_final_statement_loan_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/hrms/hr/doctype/full_and_final_statement/full_and_final_statement_loan_utils.py b/hrms/hr/doctype/full_and_final_statement/full_and_final_statement_loan_utils.py index e20332ca69..530e6ece2b 100644 --- a/hrms/hr/doctype/full_and_final_statement/full_and_final_statement_loan_utils.py +++ b/hrms/hr/doctype/full_and_final_statement/full_and_final_statement_loan_utils.py @@ -85,7 +85,6 @@ def cancel_loan_repayment(doc: "FullandFinalStatement"): loan_receivables.append(receivable.reference_document) - # loan_receivables = list(set(loan_receivables)) for loan in loan_receivables: posting_date = frappe.utils.getdate(doc.transaction_date) loan_repayment = frappe.get_doc(