fix: Remove repayment type
This commit is contained in:
parent
6dccf79250
commit
d86b7c5537
@ -14,7 +14,7 @@ from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_
|
||||
process_loan_interest_accrual_for_term_loans)
|
||||
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year
|
||||
from erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall import create_process_loan_security_shortfall
|
||||
from erpnext.loan_management.doctype.loan.loan import unpledge_security
|
||||
from erpnext.loan_management.doctype.loan.loan import unpledge_security, request_loan_closure
|
||||
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_disbursement.loan_disbursement import get_disbursal_amount
|
||||
@ -132,7 +132,7 @@ class TestLoan(unittest.TestCase):
|
||||
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 = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||
loan.submit()
|
||||
|
||||
self.assertEquals(loan.loan_amount, 1000000)
|
||||
@ -149,23 +149,23 @@ class TestLoan(unittest.TestCase):
|
||||
|
||||
process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
|
||||
|
||||
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 10), "Regular Payment", 111118.68)
|
||||
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 10), 111118.68)
|
||||
repayment_entry.save()
|
||||
repayment_entry.submit()
|
||||
|
||||
penalty_amount = (accrued_interest_amount * 4 * 25) / (100 * days_in_year(get_datetime(first_date).year))
|
||||
self.assertEquals(flt(repayment_entry.penalty_amount, 2), flt(penalty_amount, 2))
|
||||
|
||||
amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
|
||||
'paid_principal_amount'])
|
||||
amounts = frappe.db.get_all('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount'])
|
||||
|
||||
loan.load_from_db()
|
||||
|
||||
self.assertEquals(amounts[0], repayment_entry.interest_payable)
|
||||
total_interest_paid = amounts[0]['paid_interest_amount'] + amounts[1]['paid_interest_amount']
|
||||
self.assertEquals(amounts[1]['paid_interest_amount'], repayment_entry.interest_payable)
|
||||
self.assertEquals(flt(loan.total_principal_paid, 2), flt(repayment_entry.amount_paid -
|
||||
penalty_amount - amounts[0], 2))
|
||||
penalty_amount - total_interest_paid, 2))
|
||||
|
||||
def test_loan_closure_repayment(self):
|
||||
def test_loan_closure(self):
|
||||
pledge = [{
|
||||
"loan_security": "Test Security 1",
|
||||
"qty": 4000.00
|
||||
@ -174,7 +174,7 @@ class TestLoan(unittest.TestCase):
|
||||
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 = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||
loan.submit()
|
||||
|
||||
self.assertEquals(loan.loan_amount, 1000000)
|
||||
@ -196,14 +196,16 @@ class TestLoan(unittest.TestCase):
|
||||
process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
|
||||
|
||||
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6),
|
||||
"Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
|
||||
flt(loan.loan_amount + accrued_interest_amount))
|
||||
|
||||
repayment_entry.submit()
|
||||
|
||||
amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
|
||||
|
||||
self.assertEquals(flt(amount, 2),flt(accrued_interest_amount, 2))
|
||||
self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
|
||||
self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
|
||||
|
||||
request_loan_closure(loan.name)
|
||||
loan.load_from_db()
|
||||
self.assertEquals(loan.status, "Loan Closure Requested")
|
||||
|
||||
@ -230,8 +232,7 @@ class TestLoan(unittest.TestCase):
|
||||
|
||||
process_loan_interest_accrual_for_term_loans(posting_date=nowdate())
|
||||
|
||||
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(nowdate(), 5),
|
||||
"Regular Payment", 89768.75)
|
||||
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(nowdate(), 5), 89768.75)
|
||||
|
||||
repayment_entry.submit()
|
||||
|
||||
@ -281,7 +282,7 @@ class TestLoan(unittest.TestCase):
|
||||
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 = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||
loan.submit()
|
||||
|
||||
self.assertEquals(loan.loan_amount, 1000000)
|
||||
@ -299,10 +300,10 @@ class TestLoan(unittest.TestCase):
|
||||
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_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, 6),
|
||||
"Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
|
||||
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6), flt(loan.loan_amount + accrued_interest_amount))
|
||||
repayment_entry.submit()
|
||||
|
||||
request_loan_closure(loan.name)
|
||||
loan.load_from_db()
|
||||
self.assertEquals(loan.status, "Loan Closure Requested")
|
||||
|
||||
@ -317,9 +318,9 @@ class TestLoan(unittest.TestCase):
|
||||
self.assertEqual(loan.status, 'Closed')
|
||||
self.assertEquals(sum(pledged_qty.values()), 0)
|
||||
|
||||
amounts = amounts = calculate_amounts(loan.name, add_days(last_date, 6), "Regular Repayment")
|
||||
self.assertEqual(amounts['pending_principal_amount'], 0)
|
||||
self.assertEqual(amounts['payable_principal_amount'], 0)
|
||||
amounts = amounts = calculate_amounts(loan.name, add_days(last_date, 6))
|
||||
self.assertTrue(amounts['pending_principal_amount'] < 0)
|
||||
self.assertTrue(amounts['payable_principal_amount'] < 0)
|
||||
self.assertEqual(amounts['interest_amount'], 0)
|
||||
|
||||
def test_disbursal_check_with_shortfall(self):
|
||||
@ -381,7 +382,7 @@ class TestLoan(unittest.TestCase):
|
||||
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 = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||
loan.submit()
|
||||
|
||||
self.assertEquals(loan.loan_amount, 1000000)
|
||||
@ -399,20 +400,102 @@ class TestLoan(unittest.TestCase):
|
||||
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")
|
||||
amounts = calculate_amounts(loan.name, add_days(last_date, 6))
|
||||
|
||||
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 = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6), 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'])
|
||||
|
||||
request_loan_closure(loan.name)
|
||||
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)
|
||||
amounts = calculate_amounts(loan.name, add_days(last_date, 6))
|
||||
self.assertTrue(amounts['pending_principal_amount'] < 0.0)
|
||||
|
||||
def test_partial_unaccrued_interest_payment(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='2019-10-01')
|
||||
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 += 5.5
|
||||
|
||||
# get partial unaccrued interest amount
|
||||
paid_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))
|
||||
|
||||
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6),
|
||||
paid_amount)
|
||||
|
||||
repayment_entry.submit()
|
||||
repayment_entry.load_from_db()
|
||||
|
||||
partial_accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * 5) \
|
||||
/ (days_in_year(get_datetime(first_date).year) * 100)
|
||||
|
||||
interest_amount = flt(amounts['interest_amount'] + partial_accrued_interest_amount, 2)
|
||||
self.assertEqual(flt(repayment_entry.total_interest_paid, 0), flt(interest_amount, 0))
|
||||
|
||||
def test_penalty(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='2019-10-01')
|
||||
loan.submit()
|
||||
|
||||
self.assertEquals(loan.loan_amount, 1000000)
|
||||
|
||||
first_date = '2019-10-01'
|
||||
last_date = '2019-10-30'
|
||||
|
||||
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, 1))
|
||||
paid_amount = amounts['interest_amount']/2
|
||||
|
||||
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6),
|
||||
paid_amount)
|
||||
|
||||
repayment_entry.submit()
|
||||
|
||||
# 30 days - grace period
|
||||
penalty_days = 30 - 5
|
||||
penalty_applicable_amount = flt(amounts['interest_amount']/2, 2)
|
||||
penalty_amount = flt((((penalty_applicable_amount * 25) / 100) * penalty_days)/365, 2)
|
||||
process = process_loan_interest_accrual_for_demand_loans(posting_date = '2019-11-30')
|
||||
|
||||
calculated_penalty_amount = frappe.db.get_value('Loan Interest Accrual',
|
||||
{'process_loan_interest_accrual': process, 'loan': loan.name}, 'penalty_amount')
|
||||
|
||||
self.assertEquals(calculated_penalty_amount, penalty_amount)
|
||||
|
||||
|
||||
def create_loan_accounts():
|
||||
if not frappe.db.exists("Account", "Loans and Advances (Assets) - _TC"):
|
||||
@ -582,12 +665,11 @@ def create_loan_security_price(loan_security, loan_security_price, uom, from_dat
|
||||
"valid_upto": to_date
|
||||
}).insert(ignore_permissions=True)
|
||||
|
||||
def create_repayment_entry(loan, applicant, posting_date, payment_type, paid_amount):
|
||||
def create_repayment_entry(loan, applicant, posting_date, paid_amount):
|
||||
|
||||
lr = frappe.get_doc({
|
||||
"doctype": "Loan Repayment",
|
||||
"against_loan": loan,
|
||||
"payment_type": payment_type,
|
||||
"company": "_Test Company",
|
||||
"posting_date": posting_date or nowdate(),
|
||||
"applicant": applicant,
|
||||
|
@ -22,7 +22,6 @@ class LoanInterestAccrual(AccountsController):
|
||||
if not self.interest_amount and not self.payable_principal_amount:
|
||||
frappe.throw(_("Interest Amount or Principal Amount is mandatory"))
|
||||
|
||||
|
||||
def on_submit(self):
|
||||
self.make_gl_entries()
|
||||
|
||||
@ -79,8 +78,11 @@ class LoanInterestAccrual(AccountsController):
|
||||
# For Eg: If Loan disbursement date is '01-09-2019' and disbursed amount is 1000000 and
|
||||
# rate of interest is 13.5 then first loan interest accural will be on '01-10-2019'
|
||||
# which means interest will be accrued for 30 days which should be equal to 11095.89
|
||||
def calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest):
|
||||
def calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest, accrual_type):
|
||||
from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts
|
||||
|
||||
no_of_days = get_no_of_days_for_interest_accural(loan, posting_date)
|
||||
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||
|
||||
if no_of_days <= 0:
|
||||
return
|
||||
@ -91,7 +93,7 @@ def calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_i
|
||||
else:
|
||||
pending_principal_amount = loan.disbursed_amount
|
||||
|
||||
interest_per_day = (pending_principal_amount * loan.rate_of_interest) / (days_in_year(get_datetime(posting_date).year) * 100)
|
||||
interest_per_day = get_per_day_interest(pending_principal_amount, loan.rate_of_interest, posting_date)
|
||||
payable_interest = interest_per_day * no_of_days
|
||||
|
||||
args = frappe._dict({
|
||||
@ -102,13 +104,16 @@ def calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_i
|
||||
'loan_account': loan.loan_account,
|
||||
'pending_principal_amount': pending_principal_amount,
|
||||
'interest_amount': payable_interest,
|
||||
'penalty_amount': calculate_amounts(loan.name, posting_date)['penalty_amount'],
|
||||
'process_loan_interest': process_loan_interest,
|
||||
'posting_date': posting_date
|
||||
'posting_date': posting_date,
|
||||
'accrual_type': accrual_type
|
||||
})
|
||||
|
||||
make_loan_interest_accrual_entry(args)
|
||||
if flt(payable_interest, precision) > 0.0:
|
||||
make_loan_interest_accrual_entry(args)
|
||||
|
||||
def make_accrual_interest_entry_for_demand_loans(posting_date, process_loan_interest, open_loans=None, loan_type=None):
|
||||
def make_accrual_interest_entry_for_demand_loans(posting_date, process_loan_interest, open_loans=None, loan_type=None, accrual_type="Regular"):
|
||||
query_filters = {
|
||||
"status": ('in', ['Disbursed', 'Partially Disbursed']),
|
||||
"docstatus": 1
|
||||
@ -127,7 +132,7 @@ def make_accrual_interest_entry_for_demand_loans(posting_date, process_loan_inte
|
||||
filters=query_filters)
|
||||
|
||||
for loan in open_loans:
|
||||
calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest)
|
||||
calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest, accrual_type)
|
||||
|
||||
def make_accrual_interest_entry_for_term_loans(posting_date, process_loan_interest, term_loan=None, loan_type=None):
|
||||
curr_date = posting_date or add_days(nowdate(), 1)
|
||||
@ -192,10 +197,12 @@ def make_loan_interest_accrual_entry(args):
|
||||
loan_interest_accrual.loan_account = args.loan_account
|
||||
loan_interest_accrual.pending_principal_amount = flt(args.pending_principal_amount, precision)
|
||||
loan_interest_accrual.interest_amount = flt(args.interest_amount, precision)
|
||||
loan_interest_accrual.penalty_amount = flt(args.penalty_amount, precision)
|
||||
loan_interest_accrual.posting_date = args.posting_date or nowdate()
|
||||
loan_interest_accrual.process_loan_interest_accrual = args.process_loan_interest
|
||||
loan_interest_accrual.repayment_schedule_name = args.repayment_schedule_name
|
||||
loan_interest_accrual.payable_principal_amount = args.payable_principal
|
||||
loan_interest_accrual.accrual_type = args.accrual_type
|
||||
|
||||
loan_interest_accrual.save()
|
||||
loan_interest_accrual.submit()
|
||||
@ -226,3 +233,11 @@ def days_in_year(year):
|
||||
|
||||
return days
|
||||
|
||||
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), 2)
|
||||
|
||||
|
@ -10,11 +10,11 @@
|
||||
"applicant_type",
|
||||
"applicant",
|
||||
"loan_type",
|
||||
"payment_type",
|
||||
"column_break_3",
|
||||
"company",
|
||||
"posting_date",
|
||||
"is_term_loan",
|
||||
"rate_of_interest",
|
||||
"payment_details_section",
|
||||
"due_date",
|
||||
"pending_principal_amount",
|
||||
@ -31,6 +31,7 @@
|
||||
"column_break_21",
|
||||
"reference_date",
|
||||
"principal_amount_paid",
|
||||
"total_interest_paid",
|
||||
"repayment_details",
|
||||
"amended_from"
|
||||
],
|
||||
@ -95,15 +96,6 @@
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"default": "Regular Payment",
|
||||
"fieldname": "payment_type",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Payment Type",
|
||||
"options": "\nRegular Payment\nLoan Closure",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "payable_amount",
|
||||
"fieldtype": "Currency",
|
||||
@ -195,6 +187,7 @@
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 1,
|
||||
"label": "Principal Amount Paid",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
@ -217,11 +210,27 @@
|
||||
"hidden": 1,
|
||||
"label": "Repayment Details",
|
||||
"options": "Loan Repayment Detail"
|
||||
},
|
||||
{
|
||||
"fieldname": "total_interest_paid",
|
||||
"fieldtype": "Currency",
|
||||
"hidden": 1,
|
||||
"label": "Total Interest Paid",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "loan_type.rate_of_interest",
|
||||
"fieldname": "rate_of_interest",
|
||||
"fieldtype": "Percent",
|
||||
"label": "Rate Of Interest",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-16 09:40:15.581165",
|
||||
"modified": "2020-10-10 03:49:01.827593",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Loan Management",
|
||||
"name": "Loan Repayment",
|
||||
|
@ -14,19 +14,18 @@ from erpnext.controllers.accounts_controller import AccountsController
|
||||
from erpnext.accounts.general_ledger import make_gl_entries
|
||||
from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import update_shortfall_status
|
||||
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans
|
||||
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import get_per_day_interest
|
||||
|
||||
class LoanRepayment(AccountsController):
|
||||
|
||||
def validate(self):
|
||||
amounts = calculate_amounts(self.against_loan, self.posting_date, self.payment_type)
|
||||
amounts = calculate_amounts(self.against_loan, self.posting_date)
|
||||
self.set_missing_values(amounts)
|
||||
self.validate_amount()
|
||||
self.allocate_amounts(amounts['pending_accrual_entries'])
|
||||
|
||||
def before_submit(self):
|
||||
self.book_unaccrued_interest()
|
||||
self.allocate_amounts(amounts)
|
||||
|
||||
def on_submit(self):
|
||||
self.book_unaccrued_interest()
|
||||
self.update_paid_amount()
|
||||
self.make_gl_entries()
|
||||
|
||||
@ -72,29 +71,35 @@ class LoanRepayment(AccountsController):
|
||||
msg = _("Paid amount cannot be less than {0}").format(self.penalty_amount)
|
||||
frappe.throw(msg)
|
||||
|
||||
if self.payment_type == "Loan Closure" and flt(self.amount_paid, precision) < flt(self.payable_amount, precision):
|
||||
msg = _("Amount of {0} is required for Loan closure").format(self.payable_amount)
|
||||
frappe.throw(msg)
|
||||
|
||||
def book_unaccrued_interest(self):
|
||||
if self.payment_type == 'Loan Closure':
|
||||
total_interest_paid = 0
|
||||
for payment in self.repayment_details:
|
||||
total_interest_paid += payment.paid_interest_amount
|
||||
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||
if self.total_interest_paid > self.interest_payable:
|
||||
if not self.is_term_loan:
|
||||
# get last loan interest accrual date
|
||||
last_accrual_date = frappe.get_value('Loan Interest Accrual', {'loan': self.against_loan}, 'MAX(posting_date)')
|
||||
|
||||
if total_interest_paid < self.interest_payable:
|
||||
if not self.is_term_loan:
|
||||
process = process_loan_interest_accrual_for_demand_loans(posting_date=self.posting_date,
|
||||
loan=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)
|
||||
|
||||
lia = frappe.db.get_value('Loan Interest Accrual', {'process_loan_interest_accrual':
|
||||
process}, ['name', 'interest_amount', 'payable_principal_amount'], as_dict=1)
|
||||
no_of_days = flt(flt(self.total_interest_paid - self.interest_payable,
|
||||
precision)/per_day_interest, 0)
|
||||
|
||||
self.append('repayment_details', {
|
||||
'loan_interest_accrual': lia.name,
|
||||
'paid_interest_amount': lia.interest_amount,
|
||||
'paid_principal_amount': lia.payable_principal_amount
|
||||
})
|
||||
posting_date = add_days(last_accrual_date, no_of_days)
|
||||
|
||||
# book excess interest paid
|
||||
process = process_loan_interest_accrual_for_demand_loans(posting_date=posting_date,
|
||||
loan=self.against_loan, accrual_type="Repayment")
|
||||
|
||||
# get loan interest accrual to update paid amount
|
||||
lia = frappe.db.get_value('Loan Interest Accrual', {'process_loan_interest_accrual':
|
||||
process}, ['name', 'interest_amount', 'payable_principal_amount'], as_dict=1)
|
||||
|
||||
self.append('repayment_details', {
|
||||
'loan_interest_accrual': lia.name,
|
||||
'paid_interest_amount': flt(self.total_interest_paid - self.interest_payable, precision),
|
||||
'paid_principal_amount': 0.0
|
||||
})
|
||||
|
||||
def update_paid_amount(self):
|
||||
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||
@ -108,12 +113,6 @@ class LoanRepayment(AccountsController):
|
||||
WHERE name = %s""",
|
||||
(flt(payment.paid_principal_amount, precision), flt(payment.paid_interest_amount, precision), payment.loan_interest_accrual))
|
||||
|
||||
if flt(loan.total_principal_paid + self.principal_amount_paid, precision) >= flt(loan.total_payment, precision):
|
||||
if loan.is_secured_loan:
|
||||
frappe.db.set_value("Loan", self.against_loan, "status", "Loan Closure Requested")
|
||||
else:
|
||||
frappe.db.set_value("Loan", self.against_loan, "status", "Closed")
|
||||
|
||||
frappe.db.sql(""" UPDATE `tabLoan` SET total_amount_paid = %s, total_principal_paid = %s
|
||||
WHERE name = %s """, (loan.total_amount_paid + self.amount_paid,
|
||||
loan.total_principal_paid + self.principal_amount_paid, self.against_loan))
|
||||
@ -137,15 +136,17 @@ class LoanRepayment(AccountsController):
|
||||
if loan.status == "Loan Closure Requested":
|
||||
frappe.db.set_value("Loan", self.against_loan, "status", "Disbursed")
|
||||
|
||||
def allocate_amounts(self, paid_entries):
|
||||
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
|
||||
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:
|
||||
interest_paid = self.amount_paid - self.penalty_amount
|
||||
for lia, amounts in iteritems(paid_entries):
|
||||
for lia, amounts in iteritems(repayment_details.get('pending_accrual_entries', [])):
|
||||
if amounts['interest_amount'] + amounts['payable_principal_amount'] <= interest_paid:
|
||||
interest_amount = amounts['interest_amount']
|
||||
paid_principal = amounts['payable_principal_amount']
|
||||
@ -169,9 +170,24 @@ class LoanRepayment(AccountsController):
|
||||
'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 repayment_details['unaccrued_interest'] and interest_paid:
|
||||
# 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)
|
||||
|
||||
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
|
||||
@ -289,7 +305,7 @@ def get_accrued_interest_entries(against_loan):
|
||||
# This function returns the amounts that are payable at the time of loan repayment based on posting date
|
||||
# So it pulls all the unpaid Loan Interest Accrual Entries and calculates the penalty if applicable
|
||||
|
||||
def get_amounts(amounts, against_loan, posting_date, payment_type):
|
||||
def get_amounts(amounts, against_loan, posting_date):
|
||||
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||
|
||||
against_loan_doc = frappe.get_doc("Loan", against_loan)
|
||||
@ -332,15 +348,16 @@ def get_amounts(amounts, against_loan, posting_date, payment_type):
|
||||
else:
|
||||
pending_principal_amount = against_loan_doc.disbursed_amount
|
||||
|
||||
if payment_type == "Loan Closure":
|
||||
if due_date:
|
||||
pending_days = date_diff(posting_date, due_date) + 1
|
||||
else:
|
||||
pending_days = date_diff(posting_date, against_loan_doc.disbursement_date) + 1
|
||||
unaccrued_interest = 0
|
||||
if due_date:
|
||||
pending_days = date_diff(posting_date, due_date) + 1
|
||||
else:
|
||||
pending_days = date_diff(posting_date, against_loan_doc.disbursement_date) + 1
|
||||
|
||||
payable_principal_amount = pending_principal_amount
|
||||
per_day_interest = (payable_principal_amount * (loan_type_details.rate_of_interest / 100))/365
|
||||
total_pending_interest += (pending_days * per_day_interest)
|
||||
if pending_days > 0:
|
||||
payable_principal_amount = flt(pending_principal_amount, precision)
|
||||
per_day_interest = get_per_day_interest(payable_principal_amount, loan_type_details.rate_of_interest, posting_date)
|
||||
unaccrued_interest += (pending_days * flt(per_day_interest, precision))
|
||||
|
||||
amounts["pending_principal_amount"] = flt(pending_principal_amount, precision)
|
||||
amounts["payable_principal_amount"] = flt(payable_principal_amount, precision)
|
||||
@ -348,6 +365,7 @@ def get_amounts(amounts, against_loan, posting_date, payment_type):
|
||||
amounts["penalty_amount"] = flt(penalty_amount, precision)
|
||||
amounts["payable_amount"] = flt(payable_principal_amount + total_pending_interest + penalty_amount, precision)
|
||||
amounts["pending_accrual_entries"] = pending_accrual_entries
|
||||
amounts["unaccrued_interest"] = unaccrued_interest
|
||||
|
||||
if final_due_date:
|
||||
amounts["due_date"] = final_due_date
|
||||
@ -355,7 +373,7 @@ def get_amounts(amounts, against_loan, posting_date, payment_type):
|
||||
return amounts
|
||||
|
||||
@frappe.whitelist()
|
||||
def calculate_amounts(against_loan, posting_date, payment_type):
|
||||
def calculate_amounts(against_loan, posting_date, payment_type=''):
|
||||
|
||||
amounts = {
|
||||
'penalty_amount': 0.0,
|
||||
@ -363,10 +381,14 @@ def calculate_amounts(against_loan, posting_date, payment_type):
|
||||
'pending_principal_amount': 0.0,
|
||||
'payable_principal_amount': 0.0,
|
||||
'payable_amount': 0.0,
|
||||
'unaccrued_interest': 0.0,
|
||||
'due_date': ''
|
||||
}
|
||||
|
||||
amounts = get_amounts(amounts, against_loan, posting_date, payment_type)
|
||||
amounts = get_amounts(amounts, against_loan, posting_date)
|
||||
|
||||
if payment_type == 'Loan Closure':
|
||||
amounts['payable_amount'] += amounts['unaccrued_interest']
|
||||
|
||||
return amounts
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user