From b5a2320b33dccd30f66a3ad4e48c335938e24d76 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 22 Feb 2021 23:04:48 +0530 Subject: [PATCH] fix: Precision fixes in loans --- erpnext/loan_management/doctype/loan/loan.py | 4 +++- .../loan_management/doctype/loan/test_loan.py | 2 +- .../loan_application/loan_application.py | 2 +- .../loan_interest_accrual.py | 4 +--- .../doctype/loan_repayment/loan_repayment.py | 19 ++++++------------- .../loan_security_exposure.py | 2 +- 6 files changed, 13 insertions(+), 20 deletions(-) diff --git a/erpnext/loan_management/doctype/loan/loan.py b/erpnext/loan_management/doctype/loan/loan.py index e607d4f3cb..0a6507783e 100644 --- a/erpnext/loan_management/doctype/loan/loan.py +++ b/erpnext/loan_management/doctype/loan/loan.py @@ -201,7 +201,9 @@ def request_loan_closure(loan, posting_date=None): write_off_limit = frappe.get_value('Loan Type', loan_type, 'write_off_amount') # checking greater than 0 as there may be some minor precision error - if pending_amount < write_off_limit: + if not pending_amount: + frappe.db.set_value('Loan', loan, 'status', 'Loan Closure Requested') + elif pending_amount < write_off_limit: # Auto create loan write off and update status as loan closure requested write_off = make_loan_write_off(loan) write_off.submit() diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py index f3c9db6233..13a209418d 100644 --- a/erpnext/loan_management/doctype/loan/test_loan.py +++ b/erpnext/loan_management/doctype/loan/test_loan.py @@ -547,7 +547,7 @@ class TestLoan(unittest.TestCase): # 30 days - grace period penalty_days = 30 - 4 - penalty_applicable_amount = flt(amounts['interest_amount']/2, 2) + penalty_applicable_amount = flt(amounts['interest_amount']/2) penalty_amount = flt((((penalty_applicable_amount * 25) / 100) * penalty_days), 2) process = process_loan_interest_accrual_for_demand_loans(posting_date = '2019-11-30') diff --git a/erpnext/loan_management/doctype/loan_application/loan_application.py b/erpnext/loan_management/doctype/loan_application/loan_application.py index e59db4c12d..9c0147e55b 100644 --- a/erpnext/loan_management/doctype/loan_application/loan_application.py +++ b/erpnext/loan_management/doctype/loan_application/loan_application.py @@ -197,7 +197,7 @@ def get_proposed_pledge(securities): security.qty = cint(security.amount/security.loan_security_price) security.amount = security.qty * security.loan_security_price - security.post_haircut_amount = security.amount - (security.amount * security.haircut/100) + security.post_haircut_amount = cint(security.amount - (security.amount * security.haircut/100)) maximum_loan_amount += security.post_haircut_amount diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py index 7d7992d40a..7978350adf 100644 --- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py +++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py @@ -246,7 +246,5 @@ def get_per_day_interest(principal_amount, rate_of_interest, posting_date=None): if not posting_date: posting_date = getdate() - precision = cint(frappe.db.get_default("currency_precision")) or 2 - - return flt((principal_amount * rate_of_interest) / (days_in_year(get_datetime(posting_date).year) * 100), precision) + return flt((principal_amount * rate_of_interest) / (days_in_year(get_datetime(posting_date).year) * 100)) diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py index ac30c91b67..bac06c4e9e 100644 --- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py +++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py @@ -81,8 +81,8 @@ class LoanRepayment(AccountsController): last_accrual_date = get_last_accrual_date(self.against_loan) # get posting date upto which interest has to be accrued - per_day_interest = flt(get_per_day_interest(self.pending_principal_amount, - self.rate_of_interest, self.posting_date), 2) + per_day_interest = get_per_day_interest(self.pending_principal_amount, + self.rate_of_interest, self.posting_date) no_of_days = flt(flt(self.total_interest_paid - self.interest_payable, precision)/per_day_interest, 0) - 1 @@ -105,8 +105,6 @@ class LoanRepayment(AccountsController): }) def update_paid_amount(self): - precision = cint(frappe.db.get_default("currency_precision")) or 2 - loan = frappe.get_doc("Loan", self.against_loan) for payment in self.repayment_details: @@ -114,7 +112,7 @@ class LoanRepayment(AccountsController): SET paid_principal_amount = `paid_principal_amount` + %s, paid_interest_amount = `paid_interest_amount` + %s WHERE name = %s""", - (flt(payment.paid_principal_amount, precision), flt(payment.paid_interest_amount, precision), payment.loan_interest_accrual)) + (flt(payment.paid_principal_amount), flt(payment.paid_interest_amount), payment.loan_interest_accrual)) frappe.db.sql(""" UPDATE `tabLoan` SET total_amount_paid = %s, total_principal_paid = %s WHERE name = %s """, (loan.total_amount_paid + self.amount_paid, @@ -148,8 +146,6 @@ class LoanRepayment(AccountsController): frappe.db.set_value("Loan", self.against_loan, "status", "Disbursed") def allocate_amounts(self, repayment_details): - precision = cint(frappe.db.get_default("currency_precision")) or 2 - self.set('repayment_details', []) self.principal_amount_paid = 0 total_interest_paid = 0 @@ -185,21 +181,18 @@ class LoanRepayment(AccountsController): # no of days for which to accrue interest # Interest can only be accrued for an entire day and not partial if interest_paid > repayment_details['unaccrued_interest']: - per_day_interest = flt(get_per_day_interest(self.pending_principal_amount, - self.rate_of_interest, self.posting_date), precision) interest_paid -= repayment_details['unaccrued_interest'] total_interest_paid += repayment_details['unaccrued_interest'] else: # get no of days for which interest can be paid - per_day_interest = flt(get_per_day_interest(self.pending_principal_amount, - self.rate_of_interest, self.posting_date), precision) + per_day_interest = get_per_day_interest(self.pending_principal_amount, + self.rate_of_interest, self.posting_date) no_of_days = cint(interest_paid/per_day_interest) total_interest_paid += no_of_days * per_day_interest interest_paid -= no_of_days * per_day_interest self.total_interest_paid = total_interest_paid - if interest_paid: self.principal_amount_paid += interest_paid @@ -369,7 +362,7 @@ def get_amounts(amounts, against_loan, posting_date): if pending_days > 0: principal_amount = flt(pending_principal_amount, precision) per_day_interest = get_per_day_interest(principal_amount, loan_type_details.rate_of_interest, posting_date) - unaccrued_interest += (pending_days * flt(per_day_interest, precision)) + unaccrued_interest += (pending_days * per_day_interest) amounts["pending_principal_amount"] = flt(pending_principal_amount, precision) amounts["payable_principal_amount"] = flt(payable_principal_amount, precision) diff --git a/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py b/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py index adc8013c68..8b6ea869a3 100644 --- a/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py +++ b/erpnext/loan_management/report/loan_security_exposure/loan_security_exposure.py @@ -76,7 +76,7 @@ def get_company_wise_loan_security_details(filters, loan_security_details): if qty: security_wise_map[key[1]]['applicant_count'] += 1 - total_portfolio_value += flt(qty * loan_security_details.get(key[1])['latest_price']) + total_portfolio_value += flt(qty * loan_security_details.get(key[1], {}).get('latest_price', 0)) return security_wise_map, total_portfolio_value