Skip to content

Commit

Permalink
chore: Update test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
deepeshgarg007 committed Jan 1, 2024
1 parent e00f64b commit de34422
Show file tree
Hide file tree
Showing 14 changed files with 218 additions and 122 deletions.
105 changes: 83 additions & 22 deletions lending/loan_management/doctype/loan/test_loan.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
)
from lending.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (
process_loan_interest_accrual_for_loans,
process_loan_interest_accrual_for_term_loans,
)
from lending.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall import (
create_process_loan_security_shortfall,
Expand All @@ -47,6 +46,8 @@ class TestLoan(unittest.TestCase):
def setUp(self):
set_loan_settings_in_company()
create_loan_accounts()
setup_loan_demand_offset_order()

simple_terms_loans = [
["Personal Loan", 500000, 8.4, "Monthly as per repayment start date"],
["Term Loan Product 1", 12000, 7.5, "Monthly as per repayment start date"],
Expand Down Expand Up @@ -129,14 +130,18 @@ def setUp(self):
self.applicant2 = frappe.db.get_value("Customer", {"name": "_Test Loan Customer"}, "name")
self.applicant3 = frappe.db.get_value("Customer", {"name": "_Test Loan Customer 1"}, "name")

def test_loan(self):
def test_loan_with_repayment_periods(self):
loan = create_loan(self.applicant1, "Personal Loan", 280000, "Repay Over Number of Periods", 20)
loan.submit()

make_loan_disbursement_entry(loan.name, 280000)

loan_repayment_schedule = frappe.get_doc(
"Loan Repayment Schedule", {"loan": loan.name, "docstatus": 0}
"Loan Repayment Schedule", {"loan": loan.name, "docstatus": 1, "status": "Active"}
)
schedule = loan_repayment_schedule.repayment_schedule

loan.load_from_db()
self.assertEqual(loan_repayment_schedule.monthly_repayment_amount, 15052)
self.assertEqual(flt(loan.total_interest_payable, 0), 21034)
self.assertEqual(flt(loan.total_payment, 0), 301034)
Expand All @@ -151,14 +156,19 @@ def test_loan(self):
self.assertEqual(flt(schedule[idx].interest_amount, 0), interest_amount)
self.assertEqual(flt(schedule[idx].balance_loan_amount, 0), balance_loan_amount)

def test_loan_with_fixed_amount_per_period(self):
loan = create_loan(self.applicant1, "Personal Loan", 280000, "Repay Over Number of Periods", 20)
loan.repayment_method = "Repay Fixed Amount per Period"
loan.monthly_repayment_amount = 14000
loan.save()
loan.submit()

make_loan_disbursement_entry(loan.name, 280000)

loan_repayment_schedule = frappe.get_doc(
"Loan Repayment Schedule", {"loan": loan.name, "docstatus": 0}
"Loan Repayment Schedule", {"loan": loan.name, "docstatus": 1, "status": "Active"}
)

loan.load_from_db()
self.assertEqual(len(loan_repayment_schedule.repayment_schedule), 22)
self.assertEqual(flt(loan.total_interest_payable, 0), 22712)
self.assertEqual(flt(loan.total_payment, 0), 302712)
Expand Down Expand Up @@ -278,7 +288,7 @@ def test_regular_loan_repayment(self):
first_date = "2019-10-01"
last_date = "2019-10-30"

no_of_days = date_diff(last_date, first_date) + 1
no_of_days = date_diff(last_date, first_date)

accrued_interest_amount = flt(
(loan.loan_amount * loan.rate_of_interest * no_of_days)
Expand All @@ -287,9 +297,10 @@ def test_regular_loan_repayment(self):
)

make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)

process_loan_interest_accrual_for_loans(posting_date=last_date)

process_loan_interest_accrual_for_loans(posting_date=add_days(last_date, 10))

repayment_entry = create_repayment_entry(
loan.name, self.applicant2, add_days(last_date, 10), 111119
)
Expand All @@ -300,24 +311,24 @@ def test_regular_loan_repayment(self):
self.assertEqual(flt(repayment_entry.penalty_amount, 0), flt(penalty_amount, 0))

amounts = frappe.db.get_all(
"Loan Interest Accrual", {"loan": loan.name}, ["paid_interest_amount"]
"Loan Demand",
{"loan": loan.name, "demand_type": "Normal", "demand_subtype": "Interest"},
["SUM(paid_amount) as paid_amount", "SUM(demand_amount) as payable_amount"],
)

loan.load_from_db()

total_interest_paid = amounts[0]["paid_interest_amount"] + amounts[1]["paid_interest_amount"]
self.assertEqual(amounts[1]["paid_interest_amount"], repayment_entry.interest_payable)
total_interest_paid = flt(amounts[0]["paid_amount"], 2)
self.assertEqual(flt(amounts[0]["payable_amount"], 2), repayment_entry.interest_payable)
self.assertEqual(
flt(loan.total_principal_paid, 0),
flt(repayment_entry.amount_paid - penalty_amount - total_interest_paid, 0),
)

# Check Repayment Entry cancel
# # Check Repayment Entry cancel
repayment_entry.load_from_db()
repayment_entry.cancel()

loan.load_from_db()
self.assertEqual(loan.total_principal_paid, 0)

self.assertEqual(loan.total_principal_paid, 0)

def test_loan_closure(self):
Expand Down Expand Up @@ -361,11 +372,13 @@ def test_loan_closure(self):

repayment_entry.submit()

amount = frappe.db.get_value(
"Loan Interest Accrual", {"loan": loan.name}, ["sum(paid_interest_amount)"]
amounts = frappe.db.get_all(
"Loan Demand",
{"loan": loan.name, "demand_type": "Normal", "demand_subtype": "Interest"},
["SUM(demand_amount) as payable_amount"],
)

self.assertEqual(flt(amount, 0), flt(accrued_interest_amount, 0))
self.assertEqual(flt(amounts[0].payable_amount, 0), flt(accrued_interest_amount, 0))
self.assertEqual(flt(repayment_entry.penalty_amount, 5), 0)

request_loan_closure(loan.name)
Expand Down Expand Up @@ -398,20 +411,26 @@ def test_loan_repayment_for_term_loan(self):
loan.name, loan.loan_amount, disbursement_date=add_months(nowdate(), -1)
)

process_loan_interest_accrual_for_term_loans(posting_date=nowdate())
process_loan_interest_accrual_for_loans(posting_date=nowdate())

repayment_entry = create_repayment_entry(
loan.name, self.applicant2, add_days(nowdate(), 5), 89768.75
)

repayment_entry.submit()

amounts = frappe.db.get_value(
"Loan Interest Accrual", {"loan": loan.name}, ["paid_interest_amount", "paid_principal_amount"]
# amounts = frappe.db.get_value(
# "Loan Interest Accrual", {"loan": loan.name}, ["paid_interest_amount", "paid_principal_amount"]
# )

amounts = frappe.db.get_all(
"Loan Demand",
{"loan": loan.name, "demand_type": "Normal", "demand_subtype": "Interest"},
["SUM(paid_amount) as paid_amount"],
)

self.assertEqual(amounts[0], 11250.00)
self.assertEqual(amounts[1], 78303.00)
# self.assertEqual(amounts[0].paid_amount, 11250.00)
self.assertEqual(repayment_entry.principal_amount_paid, 78303.00)

def test_security_shortfall(self):
pledges = [
Expand Down Expand Up @@ -1351,3 +1370,45 @@ def set_loan_settings_in_company(company=None):
company = frappe.get_doc("Company", company)
company.min_days_bw_disbursement_first_repayment = 15
company.save()


def setup_loan_demand_offset_order(company=None):
if not company:
company = "_Test Company"

if not frappe.db.get_value(
"Loan Demand Offset Order", {"title": "Test Loan Demand Offset Order"}
):
frappe.get_doc(
{
"doctype": "Loan Demand Offset Order",
"title": "Test Loan Demand Offset Order",
"components": [
{
"demand_type": "Penalty",
},
{
"demand_type": "Interest",
},
{
"demand_type": "Principal",
},
],
}
).insert()

doc = frappe.get_doc("Company", company)

if not doc.get("collection_offset_sequence_for_standard_asset"):
doc.collection_offset_sequence_for_standard_asset = "Test Loan Demand Offset Order"

if not doc.get("collection_offset_sequence_for_sub_standard_asset"):
doc.collection_offset_sequence_for_non_standard_asset = "Test Loan Demand Offset Order"

if not doc.get("collection_offset_sequence_for_written_off_asset"):
doc.collection_offset_sequence_for_written_off_asset = "Test Loan Demand Offset Order"

if not doc.get("collection_offset_sequence_for_settlement_collection"):
doc.collection_offset_sequence_for_settlement_collection = "Test Loan Demand Offset Order"

doc.save()
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def get_repayment_details(self):
if self.is_term_loan:
if self.repayment_method == "Repay Over Number of Periods":
self.repayment_amount = get_monthly_repayment_amount(
self.loan_amount, self.rate_of_interest, self.repayment_periods
self.loan_amount, self.rate_of_interest, self.repayment_periods, "Monthly"
)

if self.repayment_method == "Repay Fixed Amount per Period":
Expand Down
12 changes: 10 additions & 2 deletions lending/loan_management/doctype/loan_demand/loan_demand.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"waived_amount",
"outstanding_amount",
"sales_invoice",
"last_repayment_date"
"last_repayment_date",
"cost_center"
],
"fields": [
{
Expand Down Expand Up @@ -136,12 +137,19 @@
"fieldname": "last_repayment_date",
"fieldtype": "Date",
"label": "Last Repayment Date"
},
{
"fetch_from": "loan.cost_center",
"fieldname": "cost_center",
"fieldtype": "Link",
"label": "Cost Center",
"options": "Cost Center"
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2023-12-13 22:28:15.756117",
"modified": "2023-12-29 23:38:56.536380",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Demand",
Expand Down
2 changes: 2 additions & 0 deletions lending/loan_management/doctype/loan_demand/loan_demand.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def make_gl_entries(self, cancel=0):
"against_voucher": self.loan,
"party_type": self.applicant_type,
"party": self.applicant,
"cost_center": self.cost_center,
}
)
)
Expand All @@ -75,6 +76,7 @@ def make_gl_entries(self, cancel=0):
"credit": self.demand_amount,
"against_voucher_type": "Loan",
"against_voucher": self.loan,
"cost_center": self.cost_center,
}
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@
"options": "Loan Disbursement Charge"
},
{
"depends_on": "is_term_loan",
"fieldname": "repayment_frequency",
"fieldtype": "Select",
"label": "Repayment Frequency",
Expand All @@ -262,10 +263,12 @@
"mandatory_depends_on": "eval:doc.repayment_schedule_type==\"Line of Credit\""
},
{
"fetch_from": "against_loan.repayment_method",
"fetch_if_empty": 1,
"fieldname": "repayment_method",
"fieldtype": "Select",
"label": "Repayment Method",
"options": "Repay Over Number of Periods\nRepay Fixed Amount per Period"
"options": "\nRepay Over Number of Periods\nRepay Fixed Amount per Period"
},
{
"fetch_from": "against_loan.loan_amount",
Expand All @@ -291,7 +294,7 @@
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2023-12-10 18:58:36.390130",
"modified": "2023-12-29 20:32:10.687328",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Disbursement",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ def validate(self):
self.update_draft_schedule()

def after_insert(self):
self.make_draft_schedule()
if self.is_term_loan:
self.make_draft_schedule()

def on_trash(self):
if self.docstatus == 0:
if self.docstatus == 0 and self.is_term_loan:
draft_schedule = self.get_draft_schedule()
frappe.delete_doc("Loan Repayment Schedule", draft_schedule)

Expand Down Expand Up @@ -338,6 +339,8 @@ def get_values_on_cancel(self, loan_details):
for data in schedule.repayment_schedule:
total_payment -= data.total_payment
total_interest_payable -= data.interest_amount
else:
total_payment -= self.disbursed_amount

if (
loan_details.disbursed_amount > loan_details.loan_amount
Expand Down Expand Up @@ -399,6 +402,8 @@ def get_values_on_submit(self, loan_details):
if getdate(data.payment_date) >= getdate(self.repayment_start_date):
total_payment += data.total_payment
total_interest_payable += data.interest_amount
else:
total_payment = self.disbursed_amount

if disbursed_amount > loan_details.loan_amount:
topup_amount = disbursed_amount - loan_details.loan_amount
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,15 +152,17 @@ def calculate_penal_interest_for_loans(loan, posting_date, process_loan_interest

loan_product = frappe.get_value("Loan", loan.name, "loan_product")
penal_interest_rate = frappe.get_value("Loan Product", loan_product, "penalty_interest_rate")
grace_period_days = cint(frappe.get_value("Loan Product", loan_product, "grace_period_in_days"))
penal_interest_amount = 0

for demand in demands:
if demand.demand_subtype in ("Principal", "Interest"):
if getdate(demand.demand_date) < getdate(posting_date):
due_date = add_days(demand.demand_date, grace_period_days)
penal_interest_amount += (
demand.demand_amount
* penal_interest_rate
* date_diff(posting_date, demand.last_repayment_date or demand.demand_date)
* date_diff(posting_date, demand.last_repayment_date or due_date)
/ 36500
)

Expand Down Expand Up @@ -235,8 +237,8 @@ def make_accrual_interest_entry_for_loans(
open_loans += get_term_loans(term_loan=loan, loan_product=loan_product, posting_date=posting_date)

for loan in open_loans:
calculate_accrual_amount_for_loans(loan, posting_date, process_loan_interest, accrual_type)
calculate_penal_interest_for_loans(loan, posting_date, process_loan_interest, accrual_type)
calculate_accrual_amount_for_loans(loan, posting_date, process_loan_interest, accrual_type)


def generate_loan_demand(
Expand Down
Loading

0 comments on commit de34422

Please sign in to comment.