Merge pull request #24370 from deepeshgarg007/loan_report_and_enhancements
feat: Loan report and enhancements
This commit is contained in:
commit
c3d82a889a
@ -23,7 +23,7 @@
|
|||||||
{
|
{
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"label": "Reports",
|
"label": "Reports",
|
||||||
"links": "[\n {\n \"doctype\": \"Loan Repayment\",\n \"is_query_report\": true,\n \"label\": \"Loan Repayment and Closure\",\n \"name\": \"Loan Repayment and Closure\",\n \"route\": \"#query-report/Loan Repayment and Closure\",\n \"type\": \"report\"\n },\n {\n \"doctype\": \"Loan Security Pledge\",\n \"is_query_report\": true,\n \"label\": \"Loan Security Status\",\n \"name\": \"Loan Security Status\",\n \"route\": \"#query-report/Loan Security Status\",\n \"type\": \"report\"\n }\n]"
|
"links": "[\n {\n \"doctype\": \"Loan Repayment\",\n \"is_query_report\": true,\n \"label\": \"Loan Repayment and Closure\",\n \"name\": \"Loan Repayment and Closure\",\n \"route\": \"#query-report/Loan Repayment and Closure\",\n \"type\": \"report\"\n },\n {\n \"doctype\": \"Loan Security Pledge\",\n \"is_query_report\": true,\n \"label\": \"Loan Security Status\",\n \"name\": \"Loan Security Status\",\n \"route\": \"#query-report/Loan Security Status\",\n \"type\": \"report\"\n },\n {\n \"doctype\": \"Loan Interest Accrual\",\n \"is_query_report\": true,\n \"label\": \"Loan Interest Report\",\n \"name\": \"Loan Interest Report\",\n \"route\": \"#query-report/Loan Interest Report\",\n \"type\": \"report\"\n },\n {\n \"doctype\": \"Loan Security\",\n \"is_query_report\": true,\n \"label\": \"Loan Security Exposure\",\n \"name\": \"Loan Security Exposure\",\n \"route\": \"#query-report/Loan Security Exposure\",\n \"type\": \"report\"\n },\n {\n \"doctype\": \"Loan Security\",\n \"is_query_report\": true,\n \"label\": \"Applicant-Wise Loan Security Exposure\",\n \"name\": \"Applicant-Wise Loan Security Exposure\",\n \"route\": \"#query-report/Applicant-Wise Loan Security Exposure\",\n \"type\": \"report\"\n }\n]"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"category": "Modules",
|
"category": "Modules",
|
||||||
@ -38,7 +38,7 @@
|
|||||||
"idx": 0,
|
"idx": 0,
|
||||||
"is_standard": 1,
|
"is_standard": 1,
|
||||||
"label": "Loan",
|
"label": "Loan",
|
||||||
"modified": "2020-10-17 12:59:50.336085",
|
"modified": "2021-01-17 07:21:22.092184",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Loan",
|
"name": "Loan",
|
||||||
|
|||||||
@ -202,7 +202,9 @@ def request_loan_closure(loan, posting_date=None):
|
|||||||
|
|
||||||
# checking greater than 0 as there may be some minor precision error
|
# checking greater than 0 as there may be some minor precision error
|
||||||
if pending_amount < write_off_limit:
|
if pending_amount < write_off_limit:
|
||||||
# update status as loan closure requested
|
# Auto create loan write off and update status as loan closure requested
|
||||||
|
write_off = make_loan_write_off(loan)
|
||||||
|
write_off.submit()
|
||||||
frappe.db.set_value('Loan', loan, 'status', 'Loan Closure Requested')
|
frappe.db.set_value('Loan', loan, 'status', 'Loan Closure Requested')
|
||||||
else:
|
else:
|
||||||
frappe.throw(_("Cannot close loan as there is an outstanding of {0}").format(pending_amount))
|
frappe.throw(_("Cannot close loan as there is an outstanding of {0}").format(pending_amount))
|
||||||
|
|||||||
@ -321,7 +321,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
self.assertEquals(sum(pledged_qty.values()), 0)
|
self.assertEquals(sum(pledged_qty.values()), 0)
|
||||||
|
|
||||||
amounts = amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
amounts = amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
||||||
self.assertTrue(amounts['pending_principal_amount'] < 0)
|
self.assertEqual(amounts['pending_principal_amount'], 0)
|
||||||
self.assertEquals(amounts['payable_principal_amount'], 0.0)
|
self.assertEquals(amounts['payable_principal_amount'], 0.0)
|
||||||
self.assertEqual(amounts['interest_amount'], 0)
|
self.assertEqual(amounts['interest_amount'], 0)
|
||||||
|
|
||||||
@ -473,7 +473,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
self.assertEquals(loan.status, "Loan Closure Requested")
|
self.assertEquals(loan.status, "Loan Closure Requested")
|
||||||
|
|
||||||
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
amounts = calculate_amounts(loan.name, add_days(last_date, 5))
|
||||||
self.assertTrue(amounts['pending_principal_amount'] < 0.0)
|
self.assertEqual(amounts['pending_principal_amount'], 0.0)
|
||||||
|
|
||||||
def test_partial_unaccrued_interest_payment(self):
|
def test_partial_unaccrued_interest_payment(self):
|
||||||
pledge = [{
|
pledge = [{
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
"paid_principal_amount",
|
"paid_principal_amount",
|
||||||
"column_break_14",
|
"column_break_14",
|
||||||
"interest_amount",
|
"interest_amount",
|
||||||
|
"total_pending_interest_amount",
|
||||||
"paid_interest_amount",
|
"paid_interest_amount",
|
||||||
"penalty_amount",
|
"penalty_amount",
|
||||||
"section_break_15",
|
"section_break_15",
|
||||||
@ -172,13 +173,19 @@
|
|||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
"label": "Last Accrual Date",
|
"label": "Last Accrual Date",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "total_pending_interest_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Total Pending Interest Amount",
|
||||||
|
"options": "Company:company:default_currency"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"in_create": 1,
|
"in_create": 1,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-11-07 05:49:25.448875",
|
"modified": "2021-01-10 00:15:21.544140",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Loan Interest Accrual",
|
"name": "Loan Interest Accrual",
|
||||||
|
|||||||
@ -100,6 +100,8 @@ def calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_i
|
|||||||
interest_per_day = get_per_day_interest(pending_principal_amount, loan.rate_of_interest, posting_date)
|
interest_per_day = get_per_day_interest(pending_principal_amount, loan.rate_of_interest, posting_date)
|
||||||
payable_interest = interest_per_day * no_of_days
|
payable_interest = interest_per_day * no_of_days
|
||||||
|
|
||||||
|
pending_amounts = calculate_amounts(loan.name, posting_date, payment_type='Loan Closure')
|
||||||
|
|
||||||
args = frappe._dict({
|
args = frappe._dict({
|
||||||
'loan': loan.name,
|
'loan': loan.name,
|
||||||
'applicant_type': loan.applicant_type,
|
'applicant_type': loan.applicant_type,
|
||||||
@ -108,7 +110,8 @@ def calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_i
|
|||||||
'loan_account': loan.loan_account,
|
'loan_account': loan.loan_account,
|
||||||
'pending_principal_amount': pending_principal_amount,
|
'pending_principal_amount': pending_principal_amount,
|
||||||
'interest_amount': payable_interest,
|
'interest_amount': payable_interest,
|
||||||
'penalty_amount': calculate_amounts(loan.name, posting_date)['penalty_amount'],
|
'total_pending_interest_amount': pending_amounts['interest_amount'],
|
||||||
|
'penalty_amount': pending_amounts['penalty_amount'],
|
||||||
'process_loan_interest': process_loan_interest,
|
'process_loan_interest': process_loan_interest,
|
||||||
'posting_date': posting_date,
|
'posting_date': posting_date,
|
||||||
'accrual_type': accrual_type
|
'accrual_type': accrual_type
|
||||||
@ -202,6 +205,7 @@ def make_loan_interest_accrual_entry(args):
|
|||||||
loan_interest_accrual.loan_account = args.loan_account
|
loan_interest_accrual.loan_account = args.loan_account
|
||||||
loan_interest_accrual.pending_principal_amount = flt(args.pending_principal_amount, precision)
|
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.interest_amount = flt(args.interest_amount, precision)
|
||||||
|
loan_interest_accrual.total_pending_interest_amount = flt(args.total_pending_interest_amount, precision)
|
||||||
loan_interest_accrual.penalty_amount = flt(args.penalty_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.posting_date = args.posting_date or nowdate()
|
||||||
loan_interest_accrual.process_loan_interest_accrual = args.process_loan_interest
|
loan_interest_accrual.process_loan_interest_accrual = args.process_loan_interest
|
||||||
|
|||||||
@ -37,10 +37,8 @@ class TestLoanInterestAccrual(unittest.TestCase):
|
|||||||
|
|
||||||
loan_application = create_loan_application('_Test Company', self.applicant, 'Demand Loan', pledge)
|
loan_application = create_loan_application('_Test Company', self.applicant, 'Demand Loan', pledge)
|
||||||
create_pledge(loan_application)
|
create_pledge(loan_application)
|
||||||
|
|
||||||
loan = create_demand_loan(self.applicant, "Demand Loan", loan_application,
|
loan = create_demand_loan(self.applicant, "Demand Loan", loan_application,
|
||||||
posting_date=get_first_day(nowdate()))
|
posting_date=get_first_day(nowdate()))
|
||||||
|
|
||||||
loan.submit()
|
loan.submit()
|
||||||
|
|
||||||
first_date = '2019-10-01'
|
first_date = '2019-10-01'
|
||||||
@ -50,11 +48,46 @@ class TestLoanInterestAccrual(unittest.TestCase):
|
|||||||
|
|
||||||
accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
|
accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
|
||||||
/ (days_in_year(get_datetime(first_date).year) * 100)
|
/ (days_in_year(get_datetime(first_date).year) * 100)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
loan_interest_accural = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
|
loan_interest_accural = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
|
||||||
|
|
||||||
self.assertEquals(flt(loan_interest_accural.interest_amount, 0), flt(accrued_interest_amount, 0))
|
self.assertEquals(flt(loan_interest_accural.interest_amount, 0), flt(accrued_interest_amount, 0))
|
||||||
|
|
||||||
|
def test_accumulated_amounts(self):
|
||||||
|
pledge = [{
|
||||||
|
"loan_security": "Test Security 1",
|
||||||
|
"qty": 4000.00
|
||||||
|
}]
|
||||||
|
|
||||||
|
loan_application = create_loan_application('_Test Company', self.applicant, 'Demand Loan', pledge)
|
||||||
|
create_pledge(loan_application)
|
||||||
|
loan = create_demand_loan(self.applicant, "Demand Loan", loan_application,
|
||||||
|
posting_date=get_first_day(nowdate()))
|
||||||
|
loan.submit()
|
||||||
|
|
||||||
|
first_date = '2019-10-01'
|
||||||
|
last_date = '2019-10-30'
|
||||||
|
|
||||||
|
no_of_days = date_diff(last_date, first_date) + 1
|
||||||
|
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)
|
||||||
|
loan_interest_accrual = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
|
||||||
|
|
||||||
|
self.assertEquals(flt(loan_interest_accrual.interest_amount, 0), flt(accrued_interest_amount, 0))
|
||||||
|
|
||||||
|
next_start_date = '2019-10-31'
|
||||||
|
next_end_date = '2019-11-29'
|
||||||
|
|
||||||
|
no_of_days = date_diff(next_end_date, next_start_date) + 1
|
||||||
|
process = process_loan_interest_accrual_for_demand_loans(posting_date=next_end_date)
|
||||||
|
new_accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
|
||||||
|
/ (days_in_year(get_datetime(first_date).year) * 100)
|
||||||
|
|
||||||
|
total_pending_interest_amount = flt(accrued_interest_amount + new_accrued_interest_amount, 0)
|
||||||
|
|
||||||
|
loan_interest_accrual = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name,
|
||||||
|
'process_loan_interest_accrual': process})
|
||||||
|
self.assertEquals(flt(loan_interest_accrual.total_pending_interest_amount, 0), total_pending_interest_amount)
|
||||||
|
|||||||
@ -377,7 +377,7 @@ def get_amounts(amounts, against_loan, posting_date):
|
|||||||
amounts["penalty_amount"] = flt(penalty_amount, precision)
|
amounts["penalty_amount"] = flt(penalty_amount, precision)
|
||||||
amounts["payable_amount"] = flt(payable_principal_amount + total_pending_interest + penalty_amount, precision)
|
amounts["payable_amount"] = flt(payable_principal_amount + total_pending_interest + penalty_amount, precision)
|
||||||
amounts["pending_accrual_entries"] = pending_accrual_entries
|
amounts["pending_accrual_entries"] = pending_accrual_entries
|
||||||
amounts["unaccrued_interest"] = unaccrued_interest
|
amounts["unaccrued_interest"] = flt(unaccrued_interest, precision)
|
||||||
|
|
||||||
if final_due_date:
|
if final_due_date:
|
||||||
amounts["due_date"] = final_due_date
|
amounts["due_date"] = final_due_date
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"loan_security",
|
"loan_security",
|
||||||
|
"loan_security_name",
|
||||||
"loan_security_type",
|
"loan_security_type",
|
||||||
"column_break_2",
|
"column_break_2",
|
||||||
"uom",
|
"uom",
|
||||||
@ -79,10 +80,18 @@
|
|||||||
"label": "Loan Security Type",
|
"label": "Loan Security Type",
|
||||||
"options": "Loan Security Type",
|
"options": "Loan Security Type",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "loan_security.loan_security_name",
|
||||||
|
"fieldname": "loan_security_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Loan Security Name",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-06-11 03:41:33.900340",
|
"modified": "2021-01-17 07:41:49.598086",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Loan Security Price",
|
"name": "Loan Security Price",
|
||||||
|
|||||||
@ -144,17 +144,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"description": "Pending amount that will be automatically ignored on loan closure request ",
|
"description": "Loan Write Off will be automatically created on loan closure request if pending amount is below this limit",
|
||||||
"fieldname": "write_off_amount",
|
"fieldname": "write_off_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"label": "Write Off Amount ",
|
"label": "Auto Write Off Amount ",
|
||||||
"options": "Company:company:default_currency"
|
"options": "Company:company:default_currency"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-10-26 07:13:55.029811",
|
"modified": "2021-01-17 06:51:26.082879",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Loan Type",
|
"name": "Loan Type",
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"loan_security",
|
"loan_security",
|
||||||
|
"loan_security_name",
|
||||||
"loan_security_type",
|
"loan_security_type",
|
||||||
"loan_security_code",
|
"loan_security_code",
|
||||||
"uom",
|
"uom",
|
||||||
@ -85,11 +86,18 @@
|
|||||||
"label": "Post Haircut Amount",
|
"label": "Post Haircut Amount",
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "loan_security.loan_security_name",
|
||||||
|
"fieldname": "loan_security_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Loan Security Name",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-11-05 10:07:15.424937",
|
"modified": "2021-01-17 07:41:12.452514",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Pledge",
|
"name": "Pledge",
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-02-01 08:14:05.845161",
|
"modified": "2021-01-17 03:59:14.494557",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Process Loan Security Shortfall",
|
"name": "Process Loan Security Shortfall",
|
||||||
@ -45,7 +45,9 @@
|
|||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "System Manager",
|
"role": "System Manager",
|
||||||
|
"select": 1,
|
||||||
"share": 1,
|
"share": 1,
|
||||||
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -57,7 +59,9 @@
|
|||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Loan Manager",
|
"role": "Loan Manager",
|
||||||
|
"select": 1,
|
||||||
"share": 1,
|
"share": 1,
|
||||||
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"loan_security",
|
"loan_security",
|
||||||
|
"loan_security_name",
|
||||||
"qty",
|
"qty",
|
||||||
"loan_security_price",
|
"loan_security_price",
|
||||||
"amount",
|
"amount",
|
||||||
@ -56,12 +57,19 @@
|
|||||||
"label": "Post Haircut Amount",
|
"label": "Post Haircut Amount",
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "loan_security.loan_security_name",
|
||||||
|
"fieldname": "loan_security_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Loan Security Name",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-11-05 10:07:37.542344",
|
"modified": "2021-01-17 07:29:01.671722",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Proposed Pledge",
|
"name": "Proposed Pledge",
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"loan_security",
|
"loan_security",
|
||||||
|
"loan_security_name",
|
||||||
"loan_security_type",
|
"loan_security_type",
|
||||||
"loan_security_code",
|
"loan_security_code",
|
||||||
"haircut",
|
"haircut",
|
||||||
@ -61,12 +62,19 @@
|
|||||||
"fieldtype": "Percent",
|
"fieldtype": "Percent",
|
||||||
"label": "Haircut",
|
"label": "Haircut",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "loan_security.loan_security_name",
|
||||||
|
"fieldname": "loan_security_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Loan Security Name",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-11-05 10:07:28.106961",
|
"modified": "2021-01-17 07:36:20.212342",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Unpledge",
|
"name": "Unpledge",
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
frappe.query_reports["Applicant-Wise Loan Security Exposure"] = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"fieldname":"company",
|
||||||
|
"label": __("Company"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Company",
|
||||||
|
"default": frappe.defaults.get_user_default("Company"),
|
||||||
|
"reqd": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"add_total_row": 0,
|
||||||
|
"columns": [],
|
||||||
|
"creation": "2021-01-15 23:48:38.913514",
|
||||||
|
"disable_prepared_report": 0,
|
||||||
|
"disabled": 0,
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Report",
|
||||||
|
"filters": [],
|
||||||
|
"idx": 0,
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"modified": "2021-01-15 23:48:38.913514",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Loan Management",
|
||||||
|
"name": "Applicant-Wise Loan Security Exposure",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"prepared_report": 0,
|
||||||
|
"ref_doctype": "Loan Security",
|
||||||
|
"report_name": "Applicant-Wise Loan Security Exposure",
|
||||||
|
"report_type": "Script Report",
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "System Manager"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Loan Manager"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,123 @@
|
|||||||
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
import erpnext
|
||||||
|
from frappe import _
|
||||||
|
from frappe.utils import get_datetime, flt
|
||||||
|
from six import iteritems
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
columns = get_columns(filters)
|
||||||
|
data = get_data(filters)
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
|
||||||
|
def get_columns(filters):
|
||||||
|
columns = [
|
||||||
|
{"label": _("Applicant Type"), "fieldname": "applicant_type", "options": "DocType", "width": 100},
|
||||||
|
{"label": _("Applicant Name"), "fieldname": "applicant_name", "fieldtype": "Dynamic Link", "options": "applicant_type", "width": 150},
|
||||||
|
{"label": _("Loan Security"), "fieldname": "loan_security", "fieldtype": "Link", "options": "Loan Security", "width": 160},
|
||||||
|
{"label": _("Loan Security Code"), "fieldname": "loan_security_code", "fieldtype": "Data", "width": 100},
|
||||||
|
{"label": _("Loan Security Name"), "fieldname": "loan_security_name", "fieldtype": "Data", "width": 150},
|
||||||
|
{"label": _("Haircut"), "fieldname": "haircut", "fieldtype": "Percent", "width": 100},
|
||||||
|
{"label": _("Loan Security Type"), "fieldname": "loan_security_type", "fieldtype": "Link", "options": "Loan Security Type", "width": 120},
|
||||||
|
{"label": _("Disabled"), "fieldname": "disabled", "fieldtype": "Check", "width": 80},
|
||||||
|
{"label": _("Total Qty"), "fieldname": "total_qty", "fieldtype": "Float", "width": 100},
|
||||||
|
{"label": _("Latest Price"), "fieldname": "latest_price", "fieldtype": "Currency", "options": "currency", "width": 100},
|
||||||
|
{"label": _("Current Value"), "fieldname": "current_value", "fieldtype": "Currency", "options": "currency", "width": 100},
|
||||||
|
{"label": _("% Of Applicant Portfolio"), "fieldname": "portfolio_percent", "fieldtype": "Percentage", "width": 100},
|
||||||
|
{"label": _("Currency"), "fieldname": "currency", "fieldtype": "Currency", "options": "Currency", "hidden": 1, "width": 100},
|
||||||
|
]
|
||||||
|
|
||||||
|
return columns
|
||||||
|
|
||||||
|
def get_data(filters):
|
||||||
|
data = []
|
||||||
|
loan_security_details = get_loan_security_details(filters)
|
||||||
|
pledge_values, total_value_map, applicant_type_map = get_applicant_wise_total_loan_security_qty(filters,
|
||||||
|
loan_security_details)
|
||||||
|
|
||||||
|
currency = erpnext.get_company_currency(filters.get('company'))
|
||||||
|
|
||||||
|
for key, qty in iteritems(pledge_values):
|
||||||
|
row = {}
|
||||||
|
current_value = flt(qty * loan_security_details.get(key[1])['latest_price'])
|
||||||
|
row.update(loan_security_details.get(key[1]))
|
||||||
|
row.update({
|
||||||
|
'applicant_type': applicant_type_map.get(key[0]),
|
||||||
|
'applicant_name': key[0],
|
||||||
|
'total_qty': qty,
|
||||||
|
'current_value': current_value,
|
||||||
|
'portfolio_percent': flt(current_value * 100 / total_value_map.get(key[0]), 2),
|
||||||
|
'currency': currency
|
||||||
|
})
|
||||||
|
|
||||||
|
data.append(row)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def get_loan_security_details(filters):
|
||||||
|
security_detail_map = {}
|
||||||
|
|
||||||
|
loan_security_price_map = frappe._dict(frappe.db.sql("""
|
||||||
|
SELECT loan_security, loan_security_price
|
||||||
|
FROM `tabLoan Security Price` t1
|
||||||
|
WHERE valid_from >= (SELECT MAX(valid_from) FROM `tabLoan Security Price` t2
|
||||||
|
WHERE t1.loan_security = t2.loan_security)
|
||||||
|
""", as_list=1))
|
||||||
|
|
||||||
|
loan_security_details = frappe.get_all('Loan Security', fields=['name as loan_security',
|
||||||
|
'loan_security_code', 'loan_security_name', 'haircut', 'loan_security_type',
|
||||||
|
'disabled'])
|
||||||
|
|
||||||
|
for security in loan_security_details:
|
||||||
|
security.update({'latest_price': flt(loan_security_price_map.get(security.loan_security))})
|
||||||
|
security_detail_map.setdefault(security.loan_security, security)
|
||||||
|
|
||||||
|
return security_detail_map
|
||||||
|
|
||||||
|
def get_applicant_wise_total_loan_security_qty(filters, loan_security_details):
|
||||||
|
current_pledges = {}
|
||||||
|
total_value_map = {}
|
||||||
|
applicant_type_map = {}
|
||||||
|
applicant_wise_unpledges = {}
|
||||||
|
conditions = ""
|
||||||
|
|
||||||
|
if filters.get('company'):
|
||||||
|
conditions = "AND company = %(company)s"
|
||||||
|
|
||||||
|
unpledges = frappe.db.sql("""
|
||||||
|
SELECT up.applicant, u.loan_security, sum(u.qty) as qty
|
||||||
|
FROM `tabLoan Security Unpledge` up, `tabUnpledge` u
|
||||||
|
WHERE u.parent = up.name
|
||||||
|
AND up.status = 'Approved'
|
||||||
|
{conditions}
|
||||||
|
GROUP BY up.applicant, u.loan_security
|
||||||
|
""".format(conditions=conditions), filters, as_dict=1)
|
||||||
|
|
||||||
|
for unpledge in unpledges:
|
||||||
|
applicant_wise_unpledges.setdefault((unpledge.applicant, unpledge.loan_security), unpledge.qty)
|
||||||
|
|
||||||
|
pledges = frappe.db.sql("""
|
||||||
|
SELECT lp.applicant_type, lp.applicant, p.loan_security, sum(p.qty) as qty
|
||||||
|
FROM `tabLoan Security Pledge` lp, `tabPledge`p
|
||||||
|
WHERE p.parent = lp.name
|
||||||
|
AND lp.status = 'Pledged'
|
||||||
|
{conditions}
|
||||||
|
GROUP BY lp.applicant, p.loan_security
|
||||||
|
""".format(conditions=conditions), filters, as_dict=1)
|
||||||
|
|
||||||
|
for security in pledges:
|
||||||
|
current_pledges.setdefault((security.applicant, security.loan_security), security.qty)
|
||||||
|
total_value_map.setdefault(security.applicant, 0.0)
|
||||||
|
applicant_type_map.setdefault(security.applicant, security.applicant_type)
|
||||||
|
|
||||||
|
current_pledges[(security.applicant, security.loan_security)] -= \
|
||||||
|
applicant_wise_unpledges.get((security.applicant, security.loan_security), 0.0)
|
||||||
|
|
||||||
|
total_value_map[security.applicant] += current_pledges.get((security.applicant, security.loan_security)) \
|
||||||
|
* loan_security_details.get(security.loan_security)['latest_price']
|
||||||
|
|
||||||
|
return current_pledges, total_value_map, applicant_type_map
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
frappe.query_reports["Loan Interest Report"] = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"fieldname":"company",
|
||||||
|
"label": __("Company"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Company",
|
||||||
|
"default": frappe.defaults.get_user_default("Company"),
|
||||||
|
"reqd": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"add_total_row": 1,
|
||||||
|
"columns": [],
|
||||||
|
"creation": "2021-01-10 02:03:26.742693",
|
||||||
|
"disable_prepared_report": 0,
|
||||||
|
"disabled": 0,
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Report",
|
||||||
|
"filters": [],
|
||||||
|
"idx": 0,
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"modified": "2021-01-10 02:03:26.742693",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Loan Management",
|
||||||
|
"name": "Loan Interest Report",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"prepared_report": 0,
|
||||||
|
"ref_doctype": "Loan Interest Accrual",
|
||||||
|
"report_name": "Loan Interest Report",
|
||||||
|
"report_type": "Script Report",
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "System Manager"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Loan Manager"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,124 @@
|
|||||||
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
import erpnext
|
||||||
|
from frappe import _
|
||||||
|
from frappe.utils import flt, getdate, add_days
|
||||||
|
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
columns = get_columns(filters)
|
||||||
|
data = get_active_loan_details(filters)
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
def get_columns(filters):
|
||||||
|
columns = [
|
||||||
|
{"label": _("Loan"), "fieldname": "loan", "fieldtype": "Link", "options": "Loan", "width": 160},
|
||||||
|
{"label": _("Status"), "fieldname": "status", "fieldtype": "Data", "width": 160},
|
||||||
|
{"label": _("Applicant Type"), "fieldname": "applicant_type", "options": "DocType", "width": 100},
|
||||||
|
{"label": _("Applicant Name"), "fieldname": "applicant_name", "fieldtype": "Dynamic Link", "options": "applicant_type", "width": 150},
|
||||||
|
{"label": _("Loan Type"), "fieldname": "loan_type", "fieldtype": "Link", "options": "Loan Type", "width": 100},
|
||||||
|
{"label": _("Sanctioned Amount"), "fieldname": "sanctioned_amount", "fieldtype": "Currency", "options": "currency", "width": 120},
|
||||||
|
{"label": _("Disbursed Amount"), "fieldname": "disbursed_amount", "fieldtype": "Currency", "options": "currency", "width": 120},
|
||||||
|
{"label": _("Penalty Amount"), "fieldname": "penalty", "fieldtype": "Currency", "options": "currency", "width": 120},
|
||||||
|
{"label": _("Accrued Interest"), "fieldname": "accrued_interest", "fieldtype": "Currency", "options": "currency", "width": 120},
|
||||||
|
{"label": _("Total Repayment"), "fieldname": "total_repayment", "fieldtype": "Currency", "options": "currency", "width": 120},
|
||||||
|
{"label": _("Principal Outstanding"), "fieldname": "principal_outstanding", "fieldtype": "Currency", "options": "currency", "width": 120},
|
||||||
|
{"label": _("Interest Outstanding"), "fieldname": "interest_outstanding", "fieldtype": "Currency", "options": "currency", "width": 120},
|
||||||
|
{"label": _("Total Outstanding"), "fieldname": "total_outstanding", "fieldtype": "Currency", "options": "currency", "width": 120},
|
||||||
|
{"label": _("Undue Booked Interest"), "fieldname": "undue_interest", "fieldtype": "Currency", "options": "currency", "width": 120},
|
||||||
|
{"label": _("Interest %"), "fieldname": "rate_of_interest", "fieldtype": "Percent", "width": 100},
|
||||||
|
{"label": _("Penalty Interest %"), "fieldname": "penalty_interest", "fieldtype": "Percent", "width": 100},
|
||||||
|
{"label": _("Currency"), "fieldname": "currency", "fieldtype": "Currency", "options": "Currency", "hidden": 1, "width": 100},
|
||||||
|
]
|
||||||
|
|
||||||
|
return columns
|
||||||
|
|
||||||
|
def get_active_loan_details(filters):
|
||||||
|
|
||||||
|
filter_obj = {"status": ("!=", "Closed")}
|
||||||
|
if filters.get('company'):
|
||||||
|
filter_obj.update({'company': filters.get('company')})
|
||||||
|
|
||||||
|
loan_details = frappe.get_all("Loan",
|
||||||
|
fields=["name as loan", "applicant_type", "applicant as applicant_name", "loan_type",
|
||||||
|
"disbursed_amount", "rate_of_interest", "total_payment", "total_principal_paid",
|
||||||
|
"total_interest_payable", "written_off_amount", "status"],
|
||||||
|
filters=filter_obj)
|
||||||
|
|
||||||
|
loan_list = [d.loan for d in loan_details]
|
||||||
|
|
||||||
|
sanctioned_amount_map = get_sanctioned_amount_map()
|
||||||
|
penal_interest_rate_map = get_penal_interest_rate_map()
|
||||||
|
payments = get_payments(loan_list)
|
||||||
|
accrual_map = get_interest_accruals(loan_list)
|
||||||
|
currency = erpnext.get_company_currency(filters.get('company'))
|
||||||
|
|
||||||
|
for loan in loan_details:
|
||||||
|
loan.update({
|
||||||
|
"sanctioned_amount": flt(sanctioned_amount_map.get(loan.applicant_name)),
|
||||||
|
"principal_outstanding": flt(loan.total_payment) - flt(loan.total_principal_paid) \
|
||||||
|
- flt(loan.total_interest_payable) - flt(loan.written_off_amount),
|
||||||
|
"total_repayment": flt(payments.get(loan.loan)),
|
||||||
|
"accrued_interest": flt(accrual_map.get(loan.loan, {}).get("accrued_interest")),
|
||||||
|
"interest_outstanding": flt(accrual_map.get(loan.loan, {}).get("interest_outstanding")),
|
||||||
|
"penalty": flt(accrual_map.get(loan.loan, {}).get("penalty")),
|
||||||
|
"penalty_interest": penal_interest_rate_map.get(loan.loan_type),
|
||||||
|
"undue_interest": flt(accrual_map.get(loan.loan, {}).get("undue_interest")),
|
||||||
|
"currency": currency
|
||||||
|
})
|
||||||
|
|
||||||
|
loan['total_outstanding'] = loan['principal_outstanding'] + loan['interest_outstanding'] \
|
||||||
|
+ loan['penalty']
|
||||||
|
|
||||||
|
return loan_details
|
||||||
|
|
||||||
|
def get_sanctioned_amount_map():
|
||||||
|
return frappe._dict(frappe.get_all("Sanctioned Loan Amount", fields=["applicant", "sanctioned_amount_limit"],
|
||||||
|
as_list=1))
|
||||||
|
|
||||||
|
def get_payments(loans):
|
||||||
|
return frappe._dict(frappe.get_all("Loan Repayment", fields=["against_loan", "sum(amount_paid)"],
|
||||||
|
filters={"against_loan": ("in", loans)}, group_by="against_loan", as_list=1))
|
||||||
|
|
||||||
|
def get_interest_accruals(loans):
|
||||||
|
accrual_map = {}
|
||||||
|
|
||||||
|
interest_accruals = frappe.get_all("Loan Interest Accrual",
|
||||||
|
fields=["loan", "interest_amount", "posting_date", "penalty_amount",
|
||||||
|
"paid_interest_amount", "accrual_type"], filters={"loan": ("in", loans)}, order_by="posting_date desc")
|
||||||
|
|
||||||
|
for entry in interest_accruals:
|
||||||
|
accrual_map.setdefault(entry.loan, {
|
||||||
|
"accrued_interest": 0.0,
|
||||||
|
"undue_interest": 0.0,
|
||||||
|
"interest_outstanding": 0.0,
|
||||||
|
"last_accrual_date": '',
|
||||||
|
"due_date": ''
|
||||||
|
})
|
||||||
|
|
||||||
|
if entry.accrual_type == 'Regular':
|
||||||
|
if not accrual_map[entry.loan]['due_date']:
|
||||||
|
accrual_map[entry.loan]['due_date'] = add_days(entry.posting_date, 1)
|
||||||
|
if not accrual_map[entry.loan]['last_accrual_date']:
|
||||||
|
accrual_map[entry.loan]['last_accrual_date'] = entry.posting_date
|
||||||
|
|
||||||
|
due_date = accrual_map[entry.loan]['due_date']
|
||||||
|
last_accrual_date = accrual_map[entry.loan]['last_accrual_date']
|
||||||
|
|
||||||
|
if due_date and getdate(entry.posting_date) < getdate(due_date):
|
||||||
|
accrual_map[entry.loan]["interest_outstanding"] += entry.interest_amount - entry.paid_interest_amount
|
||||||
|
else:
|
||||||
|
accrual_map[entry.loan]['undue_interest'] += entry.interest_amount - entry.paid_interest_amount
|
||||||
|
|
||||||
|
accrual_map[entry.loan]["accrued_interest"] += entry.interest_amount
|
||||||
|
|
||||||
|
if last_accrual_date and getdate(entry.posting_date) == last_accrual_date:
|
||||||
|
accrual_map[entry.loan]["penalty"] = entry.penalty_amount
|
||||||
|
|
||||||
|
return accrual_map
|
||||||
|
|
||||||
|
def get_penal_interest_rate_map():
|
||||||
|
return frappe._dict(frappe.get_all("Loan Type", fields=["name", "penalty_interest_rate"], as_list=1))
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
frappe.query_reports["Loan Security Exposure"] = {
|
||||||
|
"filters": [
|
||||||
|
{
|
||||||
|
"fieldname":"company",
|
||||||
|
"label": __("Company"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Company",
|
||||||
|
"default": frappe.defaults.get_user_default("Company"),
|
||||||
|
"reqd": 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"add_total_row": 0,
|
||||||
|
"columns": [],
|
||||||
|
"creation": "2021-01-16 08:08:01.694583",
|
||||||
|
"disable_prepared_report": 0,
|
||||||
|
"disabled": 0,
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Report",
|
||||||
|
"filters": [],
|
||||||
|
"idx": 0,
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"modified": "2021-01-16 08:08:01.694583",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Loan Management",
|
||||||
|
"name": "Loan Security Exposure",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"prepared_report": 0,
|
||||||
|
"ref_doctype": "Loan Security",
|
||||||
|
"report_name": "Loan Security Exposure",
|
||||||
|
"report_type": "Script Report",
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "System Manager"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "Loan Manager"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import erpnext
|
||||||
|
from frappe import _
|
||||||
|
from frappe.utils import flt
|
||||||
|
from six import iteritems
|
||||||
|
from erpnext.loan_management.report.applicant_wise_loan_security_exposure.applicant_wise_loan_security_exposure \
|
||||||
|
import get_loan_security_details, get_applicant_wise_total_loan_security_qty
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
columns = get_columns(filters)
|
||||||
|
data = get_data(filters)
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
def get_columns(filters):
|
||||||
|
columns = [
|
||||||
|
{"label": _("Loan Security"), "fieldname": "loan_security", "fieldtype": "Link", "options": "Loan Security", "width": 160},
|
||||||
|
{"label": _("Loan Security Code"), "fieldname": "loan_security_code", "fieldtype": "Data", "width": 100},
|
||||||
|
{"label": _("Loan Security Name"), "fieldname": "loan_security_name", "fieldtype": "Data", "width": 150},
|
||||||
|
{"label": _("Haircut"), "fieldname": "haircut", "fieldtype": "Percent", "width": 100},
|
||||||
|
{"label": _("Loan Security Type"), "fieldname": "loan_security_type", "fieldtype": "Link", "options": "Loan Security Type", "width": 120},
|
||||||
|
{"label": _("Disabled"), "fieldname": "disabled", "fieldtype": "Check", "width": 80},
|
||||||
|
{"label": _("Total Qty"), "fieldname": "total_qty", "fieldtype": "Float", "width": 100},
|
||||||
|
{"label": _("Latest Price"), "fieldname": "latest_price", "fieldtype": "Currency", "options": "currency", "width": 100},
|
||||||
|
{"label": _("Current Value"), "fieldname": "current_value", "fieldtype": "Currency", "options": "currency", "width": 100},
|
||||||
|
{"label": _("% Of Total Portfolio"), "fieldname": "portfolio_percent", "fieldtype": "Percentage", "width": 100},
|
||||||
|
{"label": _("Pledged Applicant Count"), "fieldname": "pledged_applicant_count", "fieldtype": "Percentage", "width": 100},
|
||||||
|
{"label": _("Currency"), "fieldname": "currency", "fieldtype": "Currency", "options": "Currency", "hidden": 1, "width": 100},
|
||||||
|
]
|
||||||
|
|
||||||
|
return columns
|
||||||
|
|
||||||
|
def get_data(filters):
|
||||||
|
data = []
|
||||||
|
loan_security_details = get_loan_security_details(filters)
|
||||||
|
current_pledges, total_portfolio_value = get_company_wise_loan_security_details(filters, loan_security_details)
|
||||||
|
currency = erpnext.get_company_currency(filters.get('company'))
|
||||||
|
|
||||||
|
for security, value in iteritems(current_pledges):
|
||||||
|
row = {}
|
||||||
|
current_value = flt(value['qty'] * loan_security_details.get(security)['latest_price'])
|
||||||
|
row.update(loan_security_details.get(security))
|
||||||
|
row.update({
|
||||||
|
'total_qty': value['qty'],
|
||||||
|
'current_value': current_value,
|
||||||
|
'portfolio_percent': flt(current_value * 100 / total_portfolio_value, 2),
|
||||||
|
'pledged_applicant_count': value['applicant_count'],
|
||||||
|
'currency': currency
|
||||||
|
})
|
||||||
|
|
||||||
|
data.append(row)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def get_company_wise_loan_security_details(filters, loan_security_details):
|
||||||
|
pledge_values, total_value_map, applicant_type_map = get_applicant_wise_total_loan_security_qty(filters,
|
||||||
|
loan_security_details)
|
||||||
|
|
||||||
|
total_portfolio_value = 0
|
||||||
|
security_wise_map = {}
|
||||||
|
for key, qty in iteritems(pledge_values):
|
||||||
|
security_wise_map.setdefault(key[1], {
|
||||||
|
'qty': 0.0,
|
||||||
|
'applicant_count': 0.0
|
||||||
|
})
|
||||||
|
|
||||||
|
security_wise_map[key[1]]['qty'] += qty
|
||||||
|
if qty:
|
||||||
|
security_wise_map[key[1]]['applicant_count'] += 1
|
||||||
|
|
||||||
|
total_portfolio_value += flt(qty * loan_security_details.get(key[1])['latest_price'])
|
||||||
|
|
||||||
|
return security_wise_map, total_portfolio_value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user