Merge pull request #23221 from deepeshgarg007/pending_principal
fix: Pending amount after loan closure request
This commit is contained in:
commit
26eab47851
@ -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"):
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user