mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-07 15:12:51 +00:00
Merge branch 'develop' of https://github.com/frappe/erpnext into loan_patch_and_fixes
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
{
|
||||
"hidden": 0,
|
||||
"label": "Reports",
|
||||
"links": "[\n {\n \"dependencies\": [\n \"Loan Repayment\"\n ],\n \"doctype\": \"Loan Repayment\",\n \"incomplete_dependencies\": [\n \"Loan Repayment\"\n ],\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 \"dependencies\": [\n \"Loan Security Pledge\"\n ],\n \"doctype\": \"Loan Security Pledge\",\n \"incomplete_dependencies\": [\n \"Loan Security Pledge\"\n ],\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]"
|
||||
}
|
||||
],
|
||||
"category": "Modules",
|
||||
@@ -36,18 +36,21 @@
|
||||
"extends_another_page": 0,
|
||||
"idx": 0,
|
||||
"is_standard": 1,
|
||||
"label": "Loan Management",
|
||||
"modified": "2020-05-16 08:01:27.784621",
|
||||
"label": "Loan",
|
||||
"modified": "2020-06-07 19:42:14.947902",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Loan Management",
|
||||
"name": "Loan Management",
|
||||
"name": "Loan",
|
||||
"owner": "Administrator",
|
||||
"pin_to_bottom": 0,
|
||||
"pin_to_top": 0,
|
||||
"shortcuts": [
|
||||
{
|
||||
"color": "#ffe8cd",
|
||||
"format": "{} Open",
|
||||
"label": "Loan Application",
|
||||
"link_to": "Loan Application",
|
||||
"stats_filter": "{ \"status\": \"Open\" }",
|
||||
"type": "DocType"
|
||||
},
|
||||
{
|
||||
@@ -45,15 +45,6 @@ frappe.ui.form.on('Loan', {
|
||||
});
|
||||
})
|
||||
|
||||
frm.set_query('loan_security_pledge', function(doc, cdt, cdn) {
|
||||
return {
|
||||
filters: {
|
||||
applicant: frm.doc.applicant,
|
||||
docstatus: 1,
|
||||
loan_application: frm.doc.loan_application || ''
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
refresh: function (frm) {
|
||||
@@ -86,9 +77,6 @@ frappe.ui.form.on('Loan', {
|
||||
frm.toggle_display("repayment_periods", s1 - frm.doc.is_term_loan);
|
||||
},
|
||||
|
||||
is_secured_loan: function(frm) {
|
||||
frm.toggle_reqd("loan_security_pledge", frm.doc.is_secured_loan);
|
||||
},
|
||||
|
||||
make_loan_disbursement: function (frm) {
|
||||
frappe.call({
|
||||
|
||||
@@ -25,15 +25,12 @@
|
||||
"disbursement_date",
|
||||
"disbursed_amount",
|
||||
"column_break_11",
|
||||
"maximum_loan_amount",
|
||||
"is_term_loan",
|
||||
"repayment_method",
|
||||
"repayment_periods",
|
||||
"monthly_repayment_amount",
|
||||
"repayment_start_date",
|
||||
"loan_security_details_section",
|
||||
"loan_security_pledge",
|
||||
"column_break_25",
|
||||
"maximum_loan_value",
|
||||
"account_info",
|
||||
"mode_of_payment",
|
||||
"payment_account",
|
||||
@@ -292,13 +289,8 @@
|
||||
"default": "0",
|
||||
"fieldname": "is_secured_loan",
|
||||
"fieldtype": "Check",
|
||||
"label": "Is Secured Loan"
|
||||
},
|
||||
{
|
||||
"depends_on": "is_secured_loan",
|
||||
"fieldname": "loan_security_details_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Loan Security Details"
|
||||
"label": "Is Secured Loan",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
@@ -324,12 +316,6 @@
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "loan_security_pledge",
|
||||
"fieldtype": "Link",
|
||||
"label": "Loan Security Pledge",
|
||||
"options": "Loan Security Pledge"
|
||||
},
|
||||
{
|
||||
"fieldname": "disbursed_amount",
|
||||
"fieldtype": "Currency",
|
||||
@@ -338,21 +324,17 @@
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fetch_from": "loan_security_pledge.maximum_loan_value",
|
||||
"fieldname": "maximum_loan_value",
|
||||
"fetch_from": "loan_application.maximum_loan_amount",
|
||||
"fieldname": "maximum_loan_amount",
|
||||
"fieldtype": "Currency",
|
||||
"label": "Maximum Loan Value",
|
||||
"label": "Maximum Loan Amount",
|
||||
"options": "Company:company:default_currency",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_25",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-13 13:16:10.192624",
|
||||
"modified": "2020-07-02 20:46:40.128142",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Loan Management",
|
||||
"name": "Loan",
|
||||
|
||||
@@ -13,11 +13,9 @@ from erpnext.controllers.accounts_controller import AccountsController
|
||||
class Loan(AccountsController):
|
||||
def validate(self):
|
||||
self.set_loan_amount()
|
||||
|
||||
self.validate_loan_amount()
|
||||
self.set_missing_fields()
|
||||
self.validate_accounts()
|
||||
self.validate_loan_security_pledge()
|
||||
self.validate_loan_amount()
|
||||
self.check_sanctioned_amount_limit()
|
||||
self.validate_repay_from_salary()
|
||||
|
||||
@@ -56,21 +54,6 @@ class Loan(AccountsController):
|
||||
if self.repayment_method == "Repay Over Number of Periods":
|
||||
self.monthly_repayment_amount = get_monthly_repayment_amount(self.repayment_method, self.loan_amount, self.rate_of_interest, self.repayment_periods)
|
||||
|
||||
def validate_loan_security_pledge(self):
|
||||
|
||||
if self.is_secured_loan and not self.loan_security_pledge:
|
||||
frappe.throw(_("Loan Security Pledge is mandatory for secured loan"))
|
||||
|
||||
if self.loan_security_pledge:
|
||||
loan_security_details = frappe.db.get_value("Loan Security Pledge", self.loan_security_pledge,
|
||||
['loan', 'company'], as_dict=1)
|
||||
|
||||
if loan_security_details.loan:
|
||||
frappe.throw(_("Loan Security Pledge already pledged against loan {0}").format(loan_security_details.loan))
|
||||
|
||||
if loan_security_details.company != self.company:
|
||||
frappe.throw(_("Loan Security Pledge Company and Loan Company must be same"))
|
||||
|
||||
def check_sanctioned_amount_limit(self):
|
||||
total_loan_amount = get_total_loan_amount(self.applicant_type, self.applicant, self.company)
|
||||
sanctioned_amount_limit = get_sanctioned_amount_limit(self.applicant_type, self.applicant, self.company)
|
||||
@@ -129,22 +112,29 @@ class Loan(AccountsController):
|
||||
self.total_payment = self.loan_amount
|
||||
|
||||
def set_loan_amount(self):
|
||||
if self.loan_application and not self.loan_amount:
|
||||
self.loan_amount = frappe.db.get_value('Loan Application', self.loan_application, 'loan_amount')
|
||||
|
||||
if not self.loan_amount and self.is_secured_loan and self.loan_security_pledge:
|
||||
self.loan_amount = self.maximum_loan_value
|
||||
|
||||
def validate_loan_amount(self):
|
||||
if self.is_secured_loan and self.loan_amount > self.maximum_loan_value:
|
||||
msg = _("Loan amount cannot be greater than {0}").format(self.maximum_loan_value)
|
||||
if self.maximum_loan_amount and self.loan_amount > self.maximum_loan_amount:
|
||||
msg = _("Loan amount cannot be greater than {0}").format(self.maximum_loan_amount)
|
||||
frappe.throw(msg)
|
||||
|
||||
if not self.loan_amount:
|
||||
frappe.throw(_("Loan amount is mandatory"))
|
||||
|
||||
def link_loan_security_pledge(self):
|
||||
frappe.db.sql("""UPDATE `tabLoan Security Pledge` SET
|
||||
loan = %s, status = 'Pledged', pledge_time = %s
|
||||
where name = %s """, (self.name, now_datetime(), self.loan_security_pledge))
|
||||
if self.is_secured_loan:
|
||||
loan_security_pledge = frappe.db.get_value('Loan Security Pledge', {'loan_application': self.loan_application},
|
||||
'name')
|
||||
|
||||
if loan_security_pledge:
|
||||
frappe.db.set_value('Loan Security Pledge', loan_security_pledge, {
|
||||
'loan': self.name,
|
||||
'status': 'Pledged',
|
||||
'pledge_time': now_datetime()
|
||||
})
|
||||
|
||||
def unlink_loan_security_pledge(self):
|
||||
frappe.db.sql("""UPDATE `tabLoan Security Pledge` SET
|
||||
@@ -235,8 +225,10 @@ def make_repayment_entry(loan, applicant_type, applicant, loan_type, company, as
|
||||
@frappe.whitelist()
|
||||
def create_loan_security_unpledge(loan, applicant_type, applicant, company, as_dict=1):
|
||||
loan_security_pledge_details = frappe.db.sql("""
|
||||
SELECT p.parent, p.loan_security, p.qty as qty FROM `tabLoan Security Pledge` lsp , `tabPledge` p
|
||||
SELECT p.loan_security, sum(p.qty) as qty
|
||||
FROM `tabLoan Security Pledge` lsp , `tabPledge` p
|
||||
WHERE p.parent = lsp.name AND lsp.loan = %s AND lsp.docstatus = 1
|
||||
GROUP BY p.loan_security
|
||||
""",(loan), as_dict=1)
|
||||
|
||||
unpledge_request = frappe.new_doc("Loan Security Unpledge")
|
||||
|
||||
@@ -9,13 +9,14 @@ import unittest
|
||||
from frappe.utils import (nowdate, add_days, getdate, now_datetime, add_to_date, get_datetime,
|
||||
add_months, get_first_day, get_last_day, flt, date_diff)
|
||||
from erpnext.selling.doctype.customer.test_customer import get_customer_dict
|
||||
from erpnext.hr.doctype.salary_structure.test_salary_structure import make_employee
|
||||
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_employee
|
||||
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (process_loan_interest_accrual_for_demand_loans,
|
||||
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 create_loan_security_unpledge
|
||||
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
|
||||
|
||||
class TestLoan(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@@ -72,31 +73,31 @@ class TestLoan(unittest.TestCase):
|
||||
self.assertEquals(loan.total_payment, 302712)
|
||||
|
||||
def test_loan_with_security(self):
|
||||
pledges = []
|
||||
pledges.append({
|
||||
|
||||
pledge = [{
|
||||
"loan_security": "Test Security 1",
|
||||
"qty": 4000.00,
|
||||
"haircut": 50,
|
||||
"loan_security_price": 500.00
|
||||
})
|
||||
}]
|
||||
|
||||
loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges)
|
||||
|
||||
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_security_pledge.name)
|
||||
loan_application = create_loan_application('_Test Company', self.applicant2,
|
||||
'Stock Loan', pledge, "Repay Over Number of Periods", 12)
|
||||
create_pledge(loan_application)
|
||||
|
||||
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods",
|
||||
12, loan_application)
|
||||
self.assertEquals(loan.loan_amount, 1000000)
|
||||
|
||||
def test_loan_disbursement(self):
|
||||
pledges = []
|
||||
pledges.append({
|
||||
pledge = [{
|
||||
"loan_security": "Test Security 1",
|
||||
"qty": 4000.00,
|
||||
"haircut": 50
|
||||
})
|
||||
"qty": 4000.00
|
||||
}]
|
||||
|
||||
loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges)
|
||||
loan_application = create_loan_application('_Test Company', self.applicant2, 'Stock Loan', pledge, "Repay Over Number of Periods", 12)
|
||||
|
||||
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_security_pledge.name)
|
||||
create_pledge(loan_application)
|
||||
|
||||
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application)
|
||||
self.assertEquals(loan.loan_amount, 1000000)
|
||||
|
||||
loan.submit()
|
||||
@@ -121,18 +122,15 @@ class TestLoan(unittest.TestCase):
|
||||
self.assertTrue(gl_entries2)
|
||||
|
||||
def test_regular_loan_repayment(self):
|
||||
pledges = []
|
||||
pledges.append({
|
||||
pledge = [{
|
||||
"loan_security": "Test Security 1",
|
||||
"qty": 4000.00,
|
||||
"haircut": 50
|
||||
})
|
||||
"qty": 4000.00
|
||||
}]
|
||||
|
||||
loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges)
|
||||
|
||||
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_security_pledge.name,
|
||||
posting_date=get_first_day(nowdate()))
|
||||
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)
|
||||
@@ -166,16 +164,15 @@ class TestLoan(unittest.TestCase):
|
||||
penalty_amount - amounts[0], 2))
|
||||
|
||||
def test_loan_closure_repayment(self):
|
||||
pledges = []
|
||||
pledges.append({
|
||||
pledge = [{
|
||||
"loan_security": "Test Security 1",
|
||||
"qty": 4000.00,
|
||||
"haircut": 50
|
||||
})
|
||||
"qty": 4000.00
|
||||
}]
|
||||
|
||||
loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges)
|
||||
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_security_pledge.name,
|
||||
posting_date=get_first_day(nowdate()))
|
||||
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)
|
||||
@@ -214,23 +211,21 @@ class TestLoan(unittest.TestCase):
|
||||
self.assertEquals(loan.status, "Loan Closure Requested")
|
||||
|
||||
def test_loan_repayment_for_term_loan(self):
|
||||
pledges = []
|
||||
pledges.append({
|
||||
pledges = [{
|
||||
"loan_security": "Test Security 2",
|
||||
"qty": 4000.00,
|
||||
"haircut": 50
|
||||
})
|
||||
|
||||
pledges.append({
|
||||
"qty": 4000.00
|
||||
},
|
||||
{
|
||||
"loan_security": "Test Security 1",
|
||||
"qty": 2000.00,
|
||||
"haircut": 50
|
||||
})
|
||||
"qty": 2000.00
|
||||
}]
|
||||
|
||||
loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges)
|
||||
loan_application = create_loan_application('_Test Company', self.applicant2, 'Stock Loan', pledges,
|
||||
"Repay Over Number of Periods", 12)
|
||||
create_pledge(loan_application)
|
||||
|
||||
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12,
|
||||
loan_security_pledge.name, posting_date=add_months(nowdate(), -1))
|
||||
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application,
|
||||
posting_date=add_months(nowdate(), -1))
|
||||
|
||||
loan.submit()
|
||||
|
||||
@@ -250,16 +245,18 @@ class TestLoan(unittest.TestCase):
|
||||
self.assertEquals(amounts[1], 78303.00)
|
||||
|
||||
def test_security_shortfall(self):
|
||||
pledges = []
|
||||
pledges.append({
|
||||
pledges = [{
|
||||
"loan_security": "Test Security 2",
|
||||
"qty": 8000.00,
|
||||
"haircut": 50,
|
||||
})
|
||||
}]
|
||||
|
||||
loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges)
|
||||
loan_application = create_loan_application('_Test Company', self.applicant2,
|
||||
'Stock Loan', pledges, "Repay Over Number of Periods", 12)
|
||||
|
||||
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_security_pledge.name)
|
||||
create_pledge(loan_application)
|
||||
|
||||
loan = create_loan_with_security(self.applicant2, "Stock Loan", "Repay Over Number of Periods", 12, loan_application)
|
||||
loan.submit()
|
||||
|
||||
make_loan_disbursement_entry(loan.name, loan.loan_amount)
|
||||
@@ -279,16 +276,15 @@ class TestLoan(unittest.TestCase):
|
||||
where loan_security='Test Security 2'""")
|
||||
|
||||
def test_loan_security_unpledge(self):
|
||||
pledges = []
|
||||
pledges.append({
|
||||
pledge = [{
|
||||
"loan_security": "Test Security 1",
|
||||
"qty": 4000.00,
|
||||
"haircut": 50
|
||||
})
|
||||
"qty": 4000.00
|
||||
}]
|
||||
|
||||
loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges)
|
||||
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_security_pledge.name,
|
||||
posting_date=get_first_day(nowdate()))
|
||||
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)
|
||||
@@ -446,12 +442,13 @@ def create_loan_security():
|
||||
"haircut": 50.00,
|
||||
}).insert(ignore_permissions=True)
|
||||
|
||||
def create_loan_security_pledge(applicant, pledges):
|
||||
def create_loan_security_pledge(applicant, pledges, loan_application):
|
||||
|
||||
lsp = frappe.new_doc("Loan Security Pledge")
|
||||
lsp.applicant_type = 'Customer'
|
||||
lsp.applicant = applicant
|
||||
lsp.company = "_Test Company"
|
||||
lsp.loan_application = loan_application
|
||||
|
||||
for pledge in pledges:
|
||||
lsp.append('securities', {
|
||||
@@ -510,6 +507,31 @@ def create_repayment_entry(loan, applicant, posting_date, payment_type, paid_amo
|
||||
|
||||
return lr
|
||||
|
||||
def create_loan_application(company, applicant, loan_type, proposed_pledges, repayment_method=None,
|
||||
repayment_periods=None, posting_date=None):
|
||||
loan_application = frappe.new_doc('Loan Application')
|
||||
loan_application.applicant_type = 'Customer'
|
||||
loan_application.company = company
|
||||
loan_application.applicant = applicant
|
||||
loan_application.loan_type = loan_type
|
||||
loan_application.posting_date = posting_date or nowdate()
|
||||
loan_application.is_secured_loan = 1
|
||||
|
||||
if repayment_method:
|
||||
loan_application.repayment_method = repayment_method
|
||||
loan_application.repayment_periods = repayment_periods
|
||||
|
||||
for pledge in proposed_pledges:
|
||||
loan_application.append('proposed_pledges', pledge)
|
||||
|
||||
loan_application.save()
|
||||
loan_application.submit()
|
||||
|
||||
loan_application.status = 'Approved'
|
||||
loan_application.save()
|
||||
|
||||
return loan_application.name
|
||||
|
||||
|
||||
def create_loan(applicant, loan_type, loan_amount, repayment_method, repayment_periods,
|
||||
repayment_start_date=None, posting_date=None):
|
||||
@@ -531,14 +553,13 @@ def create_loan(applicant, loan_type, loan_amount, repayment_method, repayment_p
|
||||
loan.save()
|
||||
return loan
|
||||
|
||||
def create_loan_with_security(applicant, loan_type, repayment_method, repayment_periods, loan_security_pledge,
|
||||
posting_date=None, repayment_start_date=None):
|
||||
|
||||
def create_loan_with_security(applicant, loan_type, repayment_method, repayment_periods, loan_application, posting_date=None, repayment_start_date=None):
|
||||
loan = frappe.get_doc({
|
||||
"doctype": "Loan",
|
||||
"company": "_Test Company",
|
||||
"applicant_type": "Customer",
|
||||
"posting_date": posting_date or nowdate(),
|
||||
"loan_application": loan_application,
|
||||
"applicant": applicant,
|
||||
"loan_type": loan_type,
|
||||
"is_term_loan": 1,
|
||||
@@ -547,7 +568,6 @@ def create_loan_with_security(applicant, loan_type, repayment_method, repayment_
|
||||
"repayment_periods": repayment_periods,
|
||||
"repayment_start_date": repayment_start_date or nowdate(),
|
||||
"mode_of_payment": frappe.db.get_value('Mode of Payment', {'type': 'Cash'}, 'name'),
|
||||
"loan_security_pledge": loan_security_pledge,
|
||||
"payment_account": 'Payment Account - _TC',
|
||||
"loan_account": 'Loan Account - _TC',
|
||||
"interest_income_account": 'Interest Income Account - _TC',
|
||||
@@ -558,19 +578,19 @@ def create_loan_with_security(applicant, loan_type, repayment_method, repayment_
|
||||
|
||||
return loan
|
||||
|
||||
def create_demand_loan(applicant, loan_type, loan_security_pledge, posting_date=None):
|
||||
def create_demand_loan(applicant, loan_type, loan_application, posting_date=None):
|
||||
|
||||
loan = frappe.get_doc({
|
||||
"doctype": "Loan",
|
||||
"company": "_Test Company",
|
||||
"applicant_type": "Customer",
|
||||
"posting_date": posting_date or nowdate(),
|
||||
'loan_application': loan_application,
|
||||
"applicant": applicant,
|
||||
"loan_type": loan_type,
|
||||
"is_term_loan": 0,
|
||||
"is_secured_loan": 1,
|
||||
"mode_of_payment": frappe.db.get_value('Mode of Payment', {'type': 'Cash'}, 'name'),
|
||||
"loan_security_pledge": loan_security_pledge,
|
||||
"payment_account": 'Payment Account - _TC',
|
||||
"loan_account": 'Loan Account - _TC',
|
||||
"interest_income_account": 'Interest Income Account - _TC',
|
||||
|
||||
@@ -103,10 +103,13 @@ class LoanApplication(Document):
|
||||
if self.is_secured_loan and not self.proposed_pledges:
|
||||
frappe.throw(_("Proposed Pledges are mandatory for secured Loans"))
|
||||
|
||||
if not self.loan_amount and self.is_secured_loan and self.proposed_pledges:
|
||||
self.loan_amount = 0
|
||||
if self.is_secured_loan and self.proposed_pledges:
|
||||
self.maximum_loan_amount = 0
|
||||
for security in self.proposed_pledges:
|
||||
self.loan_amount += security.post_haircut_amount
|
||||
self.maximum_loan_amount += security.post_haircut_amount
|
||||
|
||||
if not self.loan_amount and self.is_secured_loan and self.proposed_pledges:
|
||||
self.loan_amount = self.maximum_loan_amount
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_loan(source_name, target_doc=None, submit=0):
|
||||
@@ -116,7 +119,6 @@ def create_loan(source_name, target_doc=None, submit=0):
|
||||
filters = {'name': source_doc.loan_type}
|
||||
)[0]
|
||||
|
||||
loan_security_pledge = frappe.db.get_value("Loan Security Pledge", {"loan_application": source_name}, 'name')
|
||||
|
||||
target_doc.mode_of_payment = account_details.mode_of_payment
|
||||
target_doc.payment_account = account_details.payment_account
|
||||
@@ -124,9 +126,6 @@ def create_loan(source_name, target_doc=None, submit=0):
|
||||
target_doc.interest_income_account = account_details.interest_income_account
|
||||
target_doc.penalty_income_account = account_details.penalty_income_account
|
||||
|
||||
if loan_security_pledge:
|
||||
target_doc.is_secured_loan = 1
|
||||
target_doc.loan_security_pledge = loan_security_pledge
|
||||
|
||||
doclist = get_mapped_doc("Loan Application", source_name, {
|
||||
"Loan Application": {
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
||||
|
||||
import frappe
|
||||
import unittest
|
||||
from erpnext.hr.doctype.salary_structure.test_salary_structure import make_employee
|
||||
from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_employee
|
||||
from erpnext.loan_management.doctype.loan.test_loan import create_loan_type, create_loan_accounts
|
||||
|
||||
class TestLoanApplication(unittest.TestCase):
|
||||
|
||||
@@ -27,6 +27,7 @@ class LoanDisbursement(AccountsController):
|
||||
|
||||
def on_cancel(self):
|
||||
self.make_gl_entries(cancel=1)
|
||||
self.ignore_linked_doctypes = ['GL Entry']
|
||||
|
||||
def set_missing_values(self):
|
||||
if not self.disbursement_date:
|
||||
|
||||
@@ -5,11 +5,12 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
import unittest
|
||||
from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_last_day, date_diff, flt, add_to_date)
|
||||
from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_repayment_entry,
|
||||
from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_repayment_entry, create_loan_application,
|
||||
make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan, create_loan_security_price)
|
||||
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 days_in_year
|
||||
from erpnext.selling.doctype.customer.test_customer import get_customer_dict
|
||||
from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge
|
||||
|
||||
class TestLoanDisbursement(unittest.TestCase):
|
||||
|
||||
@@ -31,18 +32,15 @@ class TestLoanDisbursement(unittest.TestCase):
|
||||
self.applicant = frappe.db.get_value("Customer", {'name': '_Test Loan Customer'}, 'name')
|
||||
|
||||
def test_loan_topup(self):
|
||||
pledges = []
|
||||
pledges.append({
|
||||
pledge = [{
|
||||
"loan_security": "Test Security 1",
|
||||
"qty": 4000.00,
|
||||
"haircut": 50,
|
||||
"loan_security_price": 500.00
|
||||
})
|
||||
"qty": 4000.00
|
||||
}]
|
||||
|
||||
loan_security_pledge = create_loan_security_pledge(self.applicant, pledges)
|
||||
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_security_pledge.name,
|
||||
posting_date=get_first_day(nowdate()))
|
||||
loan = create_demand_loan(self.applicant, "Demand Loan", loan_application, posting_date=get_first_day(nowdate()))
|
||||
|
||||
loan.submit()
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ class LoanInterestAccrual(AccountsController):
|
||||
self.update_is_accrued()
|
||||
|
||||
self.make_gl_entries(cancel=1)
|
||||
self.ignore_linked_doctypes = ['GL Entry']
|
||||
|
||||
def update_is_accrued(self):
|
||||
frappe.db.set_value('Repayment Schedule', self.repayment_schedule_name, 'is_accrued', 0)
|
||||
@@ -177,21 +178,23 @@ def get_term_loans(date, term_loan=None, loan_type=None):
|
||||
return term_loans
|
||||
|
||||
def make_loan_interest_accrual_entry(args):
|
||||
loan_interest_accrual = frappe.new_doc("Loan Interest Accrual")
|
||||
loan_interest_accrual.loan = args.loan
|
||||
loan_interest_accrual.applicant_type = args.applicant_type
|
||||
loan_interest_accrual.applicant = args.applicant
|
||||
loan_interest_accrual.interest_income_account = args.interest_income_account
|
||||
loan_interest_accrual.loan_account = args.loan_account
|
||||
loan_interest_accrual.pending_principal_amount = flt(args.pending_principal_amount, 2)
|
||||
loan_interest_accrual.interest_amount = flt(args.interest_amount, 2)
|
||||
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
|
||||
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||
|
||||
loan_interest_accrual.save()
|
||||
loan_interest_accrual.submit()
|
||||
loan_interest_accrual = frappe.new_doc("Loan Interest Accrual")
|
||||
loan_interest_accrual.loan = args.loan
|
||||
loan_interest_accrual.applicant_type = args.applicant_type
|
||||
loan_interest_accrual.applicant = args.applicant
|
||||
loan_interest_accrual.interest_income_account = args.interest_income_account
|
||||
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.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.save()
|
||||
loan_interest_accrual.submit()
|
||||
|
||||
|
||||
def get_no_of_days_for_interest_accural(loan, posting_date):
|
||||
|
||||
@@ -6,10 +6,11 @@ import frappe
|
||||
import unittest
|
||||
from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_last_day, date_diff, flt, add_to_date)
|
||||
from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_loan_security_price,
|
||||
make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan)
|
||||
make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan, create_loan_application)
|
||||
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 days_in_year
|
||||
from erpnext.selling.doctype.customer.test_customer import get_customer_dict
|
||||
from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge
|
||||
|
||||
class TestLoanInterestAccrual(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@@ -29,17 +30,15 @@ class TestLoanInterestAccrual(unittest.TestCase):
|
||||
self.applicant = frappe.db.get_value("Customer", {'name': '_Test Loan Customer'}, 'name')
|
||||
|
||||
def test_loan_interest_accural(self):
|
||||
pledges = []
|
||||
pledges.append({
|
||||
pledge = [{
|
||||
"loan_security": "Test Security 1",
|
||||
"qty": 4000.00,
|
||||
"haircut": 50,
|
||||
"loan_security_price": 500.00
|
||||
})
|
||||
"qty": 4000.00
|
||||
}]
|
||||
|
||||
loan_security_pledge = create_loan_security_pledge(self.applicant, pledges)
|
||||
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_security_pledge.name,
|
||||
loan = create_demand_loan(self.applicant, "Demand Loan", loan_application,
|
||||
posting_date=get_first_day(nowdate()))
|
||||
|
||||
loan.submit()
|
||||
|
||||
@@ -6,7 +6,7 @@ from __future__ import unicode_literals
|
||||
import frappe, erpnext
|
||||
import json
|
||||
from frappe import _
|
||||
from frappe.utils import flt, getdate
|
||||
from frappe.utils import flt, getdate, cint
|
||||
from six import iteritems
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import date_diff, add_days, getdate, add_months, get_first_day, get_datetime
|
||||
@@ -29,8 +29,11 @@ class LoanRepayment(AccountsController):
|
||||
def on_cancel(self):
|
||||
self.mark_as_unpaid()
|
||||
self.make_gl_entries(cancel=1)
|
||||
self.ignore_linked_doctypes = ['GL Entry']
|
||||
|
||||
def set_missing_values(self, amounts):
|
||||
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||
|
||||
if not self.posting_date:
|
||||
self.posting_date = get_datetime()
|
||||
|
||||
@@ -38,24 +41,26 @@ class LoanRepayment(AccountsController):
|
||||
self.cost_center = erpnext.get_default_cost_center(self.company)
|
||||
|
||||
if not self.interest_payable:
|
||||
self.interest_payable = flt(amounts['interest_amount'], 2)
|
||||
self.interest_payable = flt(amounts['interest_amount'], precision)
|
||||
|
||||
if not self.penalty_amount:
|
||||
self.penalty_amount = flt(amounts['penalty_amount'], 2)
|
||||
self.penalty_amount = flt(amounts['penalty_amount'], precision)
|
||||
|
||||
if not self.pending_principal_amount:
|
||||
self.pending_principal_amount = flt(amounts['pending_principal_amount'], 2)
|
||||
self.pending_principal_amount = flt(amounts['pending_principal_amount'], precision)
|
||||
|
||||
if not self.payable_principal_amount and self.is_term_loan:
|
||||
self.payable_principal_amount = flt(amounts['payable_principal_amount'], 2)
|
||||
self.payable_principal_amount = flt(amounts['payable_principal_amount'], precision)
|
||||
|
||||
if not self.payable_amount:
|
||||
self.payable_amount = flt(amounts['payable_amount'], 2)
|
||||
self.payable_amount = flt(amounts['payable_amount'], precision)
|
||||
|
||||
if amounts.get('due_date'):
|
||||
self.due_date = amounts.get('due_date')
|
||||
|
||||
def validate_amount(self):
|
||||
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||
|
||||
if not self.amount_paid:
|
||||
frappe.throw(_("Amount paid cannot be zero"))
|
||||
|
||||
@@ -63,11 +68,13 @@ 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, 2) < flt(self.payable_amount, 2):
|
||||
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 update_paid_amount(self):
|
||||
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||
|
||||
loan = frappe.get_doc("Loan", self.against_loan)
|
||||
|
||||
for payment in self.repayment_details:
|
||||
@@ -75,9 +82,9 @@ class LoanRepayment(AccountsController):
|
||||
SET paid_principal_amount = `paid_principal_amount` + %s,
|
||||
paid_interest_amount = `paid_interest_amount` + %s
|
||||
WHERE name = %s""",
|
||||
(flt(payment.paid_principal_amount), flt(payment.paid_interest_amount), payment.loan_interest_accrual))
|
||||
(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, 2) >= flt(loan.total_payment, 2):
|
||||
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:
|
||||
@@ -109,7 +116,7 @@ class LoanRepayment(AccountsController):
|
||||
def allocate_amounts(self, paid_entries):
|
||||
self.set('repayment_details', [])
|
||||
self.principal_amount_paid = 0
|
||||
interest_paid = 0
|
||||
interest_paid = self.amount_paid - self.penalty_amount
|
||||
|
||||
if self.amount_paid - self.penalty_amount > 0 and paid_entries:
|
||||
interest_paid = self.amount_paid - self.penalty_amount
|
||||
@@ -253,6 +260,7 @@ def get_accrued_interest_entries(against_loan):
|
||||
# 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):
|
||||
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||
|
||||
against_loan_doc = frappe.get_doc("Loan", against_loan)
|
||||
loan_type_details = frappe.get_doc("Loan Type", against_loan_doc.loan_type)
|
||||
@@ -282,8 +290,8 @@ def get_amounts(amounts, against_loan, posting_date, payment_type):
|
||||
payable_principal_amount += entry.payable_principal_amount
|
||||
|
||||
pending_accrual_entries.setdefault(entry.name, {
|
||||
'interest_amount': flt(entry.interest_amount),
|
||||
'payable_principal_amount': flt(entry.payable_principal_amount)
|
||||
'interest_amount': flt(entry.interest_amount, precision),
|
||||
'payable_principal_amount': flt(entry.payable_principal_amount, precision)
|
||||
})
|
||||
|
||||
if not final_due_date:
|
||||
@@ -301,11 +309,11 @@ def get_amounts(amounts, against_loan, posting_date, payment_type):
|
||||
per_day_interest = (payable_principal_amount * (loan_type_details.rate_of_interest / 100))/365
|
||||
total_pending_interest += (pending_days * per_day_interest)
|
||||
|
||||
amounts["pending_principal_amount"] = pending_principal_amount
|
||||
amounts["payable_principal_amount"] = payable_principal_amount
|
||||
amounts["interest_amount"] = total_pending_interest
|
||||
amounts["penalty_amount"] = penalty_amount
|
||||
amounts["payable_amount"] = payable_principal_amount + total_pending_interest + penalty_amount
|
||||
amounts["pending_principal_amount"] = flt(pending_principal_amount, precision)
|
||||
amounts["payable_principal_amount"] = flt(payable_principal_amount, precision)
|
||||
amounts["interest_amount"] = flt(total_pending_interest, precision)
|
||||
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
|
||||
|
||||
if final_due_date:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "LS-.{applicant}.-.#####",
|
||||
"creation": "2019-08-29 18:48:51.371674",
|
||||
"doctype": "DocType",
|
||||
@@ -6,10 +7,10 @@
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"loan_details_section",
|
||||
"loan_application",
|
||||
"loan",
|
||||
"applicant_type",
|
||||
"applicant",
|
||||
"loan",
|
||||
"loan_application",
|
||||
"column_break_3",
|
||||
"company",
|
||||
"pledge_time",
|
||||
@@ -55,15 +56,13 @@
|
||||
"fieldname": "loan",
|
||||
"fieldtype": "Link",
|
||||
"label": "Loan",
|
||||
"options": "Loan",
|
||||
"read_only": 1
|
||||
"options": "Loan"
|
||||
},
|
||||
{
|
||||
"fieldname": "loan_application",
|
||||
"fieldtype": "Link",
|
||||
"label": "Loan Application",
|
||||
"options": "Loan Application",
|
||||
"read_only": 1
|
||||
"options": "Loan Application"
|
||||
},
|
||||
{
|
||||
"fieldname": "total_security_value",
|
||||
@@ -133,7 +132,8 @@
|
||||
}
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"modified": "2019-10-10 13:22:53.297519",
|
||||
"links": [],
|
||||
"modified": "2020-07-02 23:38:24.002382",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Loan Management",
|
||||
"name": "Loan Security Pledge",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"actions": [],
|
||||
"autoname": "LM-LSP-.####",
|
||||
"creation": "2019-09-03 18:20:31.382887",
|
||||
"doctype": "DocType",
|
||||
@@ -46,6 +47,7 @@
|
||||
"fieldtype": "Currency",
|
||||
"in_list_view": 1,
|
||||
"label": "Loan Security Price",
|
||||
"options": "Company:company:default_currency",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
@@ -79,7 +81,8 @@
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"modified": "2019-10-26 09:46:46.069667",
|
||||
"links": [],
|
||||
"modified": "2020-06-11 03:41:33.900340",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Loan Management",
|
||||
"name": "Loan Security Price",
|
||||
|
||||
@@ -19,7 +19,9 @@ def update_shortfall_status(loan, security_value):
|
||||
return
|
||||
|
||||
if security_value >= loan_security_shortfall.shortfall_amount:
|
||||
frappe.db.set_value("Loan Security Shortfall", loan_security_shortfall.name, "status", "Completed")
|
||||
frappe.db.set_value("Loan Security Shortfall", loan_security_shortfall.name, {
|
||||
"status": "Completed",
|
||||
"shortfall_value": loan_security_shortfall.shortfall_amount})
|
||||
else:
|
||||
frappe.db.set_value("Loan Security Shortfall", loan_security_shortfall.name,
|
||||
"shortfall_amount", loan_security_shortfall.shortfall_amount - security_value)
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"options": "Company:company:default_currency"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "rate_of_interest",
|
||||
"fieldtype": "Percent",
|
||||
"label": "Rate of Interest (%) Yearly",
|
||||
@@ -148,7 +149,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-05-16 09:08:09.029921",
|
||||
"modified": "2020-06-07 18:55:59.346292",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Loan Management",
|
||||
"name": "Loan Type",
|
||||
|
||||
@@ -9,12 +9,15 @@ frappe.ui.form.on(cur_frm.doctype, {
|
||||
}
|
||||
|
||||
if (['Loan Disbursement', 'Loan Repayment', 'Loan Interest Accrual'].includes(frm.doc.doctype)
|
||||
&& frm.doc.docstatus == 1) {
|
||||
&& frm.doc.docstatus > 0) {
|
||||
|
||||
frm.add_custom_button(__("Accounting Ledger"), function() {
|
||||
frappe.route_options = {
|
||||
voucher_no: frm.doc.name,
|
||||
company: frm.doc.company
|
||||
company: frm.doc.company,
|
||||
from_date: frm.doc.posting_date,
|
||||
to_date: moment(frm.doc.modified).format('YYYY-MM-DD'),
|
||||
show_cancelled_entries: frm.doc.docstatus === 2
|
||||
};
|
||||
|
||||
frappe.set_route("query-report", "General Ledger");
|
||||
|
||||
@@ -76,7 +76,8 @@ def get_columns(filters):
|
||||
"fieldtype": "Link",
|
||||
"fieldname": "currency",
|
||||
"options": "Currency",
|
||||
"width": 50
|
||||
"width": 50,
|
||||
"hidden": 1
|
||||
}
|
||||
]
|
||||
|
||||
@@ -84,17 +85,13 @@ def get_columns(filters):
|
||||
|
||||
def get_data(filters):
|
||||
|
||||
loan_security_price_map = frappe._dict(frappe.get_all("Loan Security",
|
||||
fields=["name", "loan_security_price"], as_list=1
|
||||
))
|
||||
|
||||
data = []
|
||||
conditions = get_conditions(filters)
|
||||
|
||||
loan_security_pledges = frappe.db.sql("""
|
||||
SELECT
|
||||
p.name, p.applicant, p.loan, p.status, p.pledge_time,
|
||||
c.loan_security, c.qty
|
||||
c.loan_security, c.qty, c.loan_security_price, c.amount
|
||||
FROM
|
||||
`tabLoan Security Pledge` p, `tabPledge` c
|
||||
WHERE
|
||||
@@ -115,8 +112,8 @@ def get_data(filters):
|
||||
row["pledge_time"] = pledge.pledge_time
|
||||
row["loan_security"] = pledge.loan_security
|
||||
row["qty"] = pledge.qty
|
||||
row["loan_security_price"] = loan_security_price_map.get(pledge.loan_security)
|
||||
row["loan_security_value"] = row["loan_security_price"] * pledge.qty
|
||||
row["loan_security_price"] = pledge.loan_security_price
|
||||
row["loan_security_value"] = pledge.amount
|
||||
row["currency"] = default_currency
|
||||
|
||||
data.append(row)
|
||||
|
||||
Reference in New Issue
Block a user