Merge pull request #23221 from deepeshgarg007/pending_principal

fix: Pending amount after loan closure request
This commit is contained in:
Deepesh Garg 2020-08-31 21:25:53 +05:30 committed by GitHub
commit 26eab47851
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 13 deletions

View File

@ -18,6 +18,7 @@ from erpnext.loan_management.doctype.loan.loan import create_loan_security_unple
from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge
from erpnext.loan_management.doctype.loan_disbursement.loan_disbursement import get_disbursal_amount from erpnext.loan_management.doctype.loan_disbursement.loan_disbursement import get_disbursal_amount
from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts
class TestLoan(unittest.TestCase): class TestLoan(unittest.TestCase):
def setUp(self): def setUp(self):
@ -194,18 +195,14 @@ class TestLoan(unittest.TestCase):
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date) make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
process_loan_interest_accrual_for_demand_loans(posting_date = last_date) process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5), repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6),
"Loan Closure", flt(loan.loan_amount + accrued_interest_amount)) "Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
repayment_entry.submit() repayment_entry.submit()
amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount', amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
'paid_principal_amount']) 'paid_principal_amount'])
unaccrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * 6) \ self.assertEquals(flt(amounts[0], 2),flt(accrued_interest_amount, 2))
/ (days_in_year(get_datetime(first_date).year) * 100)
self.assertEquals(flt(amounts[0] + unaccrued_interest_amount, 3),
flt(accrued_interest_amount, 3))
self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0) self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
loan.load_from_db() loan.load_from_db()
@ -307,9 +304,6 @@ class TestLoan(unittest.TestCase):
"Loan Closure", flt(loan.loan_amount + accrued_interest_amount)) "Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
repayment_entry.submit() repayment_entry.submit()
amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
'paid_principal_amount'])
loan.load_from_db() loan.load_from_db()
self.assertEquals(loan.status, "Loan Closure Requested") self.assertEquals(loan.status, "Loan Closure Requested")
@ -374,6 +368,47 @@ class TestLoan(unittest.TestCase):
self.assertEqual(get_disbursal_amount(loan.name), 300000) self.assertEqual(get_disbursal_amount(loan.name), 300000)
def test_pending_loan_amount_after_closure_request(self):
pledge = [{
"loan_security": "Test Security 1",
"qty": 4000.00
}]
loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
create_pledge(loan_application)
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date=get_first_day(nowdate()))
loan.submit()
self.assertEquals(loan.loan_amount, 1000000)
first_date = '2019-10-01'
last_date = '2019-10-30'
no_of_days = date_diff(last_date, first_date) + 1
no_of_days += 6
accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
/ (days_in_year(get_datetime(first_date).year) * 100)
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
amounts = calculate_amounts(loan.name, add_days(last_date, 6), "Regular Repayment")
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6),
"Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
repayment_entry.submit()
amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
'paid_principal_amount'])
loan.load_from_db()
self.assertEquals(loan.status, "Loan Closure Requested")
amounts = calculate_amounts(loan.name, add_days(last_date, 6), "Regular Repayment")
self.assertEquals(amounts['pending_principal_amount'], 0.0)
def create_loan_accounts(): def create_loan_accounts():
if not frappe.db.exists("Account", "Loans and Advances (Assets) - _TC"): if not frappe.db.exists("Account", "Loans and Advances (Assets) - _TC"):

View File

@ -116,6 +116,7 @@ class LoanRepayment(AccountsController):
def allocate_amounts(self, paid_entries): def allocate_amounts(self, paid_entries):
self.set('repayment_details', []) self.set('repayment_details', [])
self.principal_amount_paid = 0 self.principal_amount_paid = 0
total_interest_paid = 0
interest_paid = self.amount_paid - self.penalty_amount interest_paid = self.amount_paid - self.penalty_amount
if self.amount_paid - self.penalty_amount > 0 and paid_entries: if self.amount_paid - self.penalty_amount > 0 and paid_entries:
@ -137,12 +138,19 @@ class LoanRepayment(AccountsController):
interest_paid = 0 interest_paid = 0
paid_principal=0 paid_principal=0
total_interest_paid += interest_amount
self.append('repayment_details', { self.append('repayment_details', {
'loan_interest_accrual': lia, 'loan_interest_accrual': lia,
'paid_interest_amount': interest_amount, 'paid_interest_amount': interest_amount,
'paid_principal_amount': paid_principal 'paid_principal_amount': paid_principal
}) })
if self.payment_type == 'Loan Closure' and total_interest_paid < self.interest_payable:
unaccrued_interest = self.interest_payable - total_interest_paid
interest_paid -= unaccrued_interest
if self.repayment_details:
self.repayment_details[-1].paid_interest_amount += unaccrued_interest
if interest_paid: if interest_paid:
self.principal_amount_paid += interest_paid self.principal_amount_paid += interest_paid
@ -297,7 +305,7 @@ def get_amounts(amounts, against_loan, posting_date, payment_type):
if not final_due_date: if not final_due_date:
final_due_date = add_days(due_date, loan_type_details.grace_period_in_days) final_due_date = add_days(due_date, loan_type_details.grace_period_in_days)
if against_loan_doc.status == 'Disbursed': if against_loan_doc.status in ('Disbursed', 'Loan Closure Requested'):
pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid - against_loan_doc.total_interest_payable pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid - against_loan_doc.total_interest_payable
else: else:
pending_principal_amount = against_loan_doc.disbursed_amount pending_principal_amount = against_loan_doc.disbursed_amount

View File

@ -43,8 +43,10 @@ class LoanSecurityUnpledge(Document):
"valid_upto": (">=", get_datetime()) "valid_upto": (">=", get_datetime())
}, as_list=1)) }, as_list=1))
loan_amount, principal_paid = frappe.get_value("Loan", self.loan, ['loan_amount', 'total_principal_paid']) total_payment, principal_paid, interest_payable = frappe.get_value("Loan", self.loan, ['total_payment', 'total_principal_paid',
pending_principal_amount = loan_amount - principal_paid 'total_interest_payable'])
pending_principal_amount = flt(total_payment) - flt(interest_payable) - flt(principal_paid)
security_value = 0 security_value = 0
for security in self.securities: for security in self.securities:
@ -60,7 +62,7 @@ class LoanSecurityUnpledge(Document):
security_value += qty_after_unpledge * loan_security_price_map.get(security.loan_security) security_value += qty_after_unpledge * loan_security_price_map.get(security.loan_security)
if not security_value and pending_principal_amount > 0: if not security_value and flt(pending_principal_amount, 2) > 0:
frappe.throw("Cannot Unpledge, loan to value ratio is breaching") frappe.throw("Cannot Unpledge, loan to value ratio is breaching")
if security_value and (pending_principal_amount/security_value) * 100 > ltv_ratio: if security_value and (pending_principal_amount/security_value) * 100 > ltv_ratio: