mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-20 21:49:18 +00:00
Merge pull request #24252 from deepeshgarg007/partial_security_unpledge
fix: Partial loan security unpledging
This commit is contained in:
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe, math, json
|
import frappe, math, json
|
||||||
import erpnext
|
import erpnext
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from six import string_types
|
||||||
from frappe.utils import flt, rounded, add_months, nowdate, getdate, now_datetime
|
from frappe.utils import flt, rounded, add_months, nowdate, getdate, now_datetime
|
||||||
from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
|
from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
@@ -280,10 +281,13 @@ def make_loan_write_off(loan, company=None, posting_date=None, amount=0, as_dict
|
|||||||
return write_off
|
return write_off
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def unpledge_security(loan=None, loan_security_pledge=None, as_dict=0, save=0, submit=0, approve=0):
|
def unpledge_security(loan=None, loan_security_pledge=None, security_map=None, as_dict=0, save=0, submit=0, approve=0):
|
||||||
# if loan is passed it will be considered as full unpledge
|
# if no security_map is passed it will be considered as full unpledge
|
||||||
|
if security_map and isinstance(security_map, string_types):
|
||||||
|
security_map = json.loads(security_map)
|
||||||
|
|
||||||
if loan:
|
if loan:
|
||||||
pledge_qty_map = get_pledged_security_qty(loan)
|
pledge_qty_map = security_map or get_pledged_security_qty(loan)
|
||||||
loan_doc = frappe.get_doc('Loan', loan)
|
loan_doc = frappe.get_doc('Loan', loan)
|
||||||
unpledge_request = create_loan_security_unpledge(pledge_qty_map, loan_doc.name, loan_doc.company,
|
unpledge_request = create_loan_security_unpledge(pledge_qty_map, loan_doc.name, loan_doc.company,
|
||||||
loan_doc.applicant_type, loan_doc.applicant)
|
loan_doc.applicant_type, loan_doc.applicant)
|
||||||
|
|||||||
@@ -325,6 +325,43 @@ class TestLoan(unittest.TestCase):
|
|||||||
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)
|
||||||
|
|
||||||
|
def test_partial_loan_security_unpledge(self):
|
||||||
|
pledge = [{
|
||||||
|
"loan_security": "Test Security 1",
|
||||||
|
"qty": 2000.00
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"loan_security": "Test Security 2",
|
||||||
|
"qty": 4000.00
|
||||||
|
}]
|
||||||
|
|
||||||
|
loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
|
||||||
|
create_pledge(loan_application)
|
||||||
|
|
||||||
|
loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
|
||||||
|
loan.submit()
|
||||||
|
|
||||||
|
self.assertEquals(loan.loan_amount, 1000000)
|
||||||
|
|
||||||
|
first_date = '2019-10-01'
|
||||||
|
last_date = '2019-10-30'
|
||||||
|
|
||||||
|
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
|
||||||
|
process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
|
||||||
|
|
||||||
|
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5), 600000)
|
||||||
|
repayment_entry.submit()
|
||||||
|
|
||||||
|
unpledge_map = {'Test Security 2': 2000}
|
||||||
|
|
||||||
|
unpledge_request = unpledge_security(loan=loan.name, security_map = unpledge_map, save=1)
|
||||||
|
unpledge_request.submit()
|
||||||
|
unpledge_request.status = 'Approved'
|
||||||
|
unpledge_request.save()
|
||||||
|
unpledge_request.submit()
|
||||||
|
unpledge_request.load_from_db()
|
||||||
|
self.assertEqual(unpledge_request.docstatus, 1)
|
||||||
|
|
||||||
def test_disbursal_check_with_shortfall(self):
|
def test_disbursal_check_with_shortfall(self):
|
||||||
pledges = [{
|
pledges = [{
|
||||||
"loan_security": "Test Security 2",
|
"loan_security": "Test Security 2",
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ def check_for_ltv_shortfall(process_loan_security_shortfall):
|
|||||||
process_loan_security_shortfall)
|
process_loan_security_shortfall)
|
||||||
|
|
||||||
def create_loan_security_shortfall(loan, loan_amount, security_value, shortfall_amount, process_loan_security_shortfall):
|
def create_loan_security_shortfall(loan, loan_amount, security_value, shortfall_amount, process_loan_security_shortfall):
|
||||||
|
|
||||||
existing_shortfall = frappe.db.get_value("Loan Security Shortfall", {"loan": loan, "status": "Pending"}, "name")
|
existing_shortfall = frappe.db.get_value("Loan Security Shortfall", {"loan": loan, "status": "Pending"}, "name")
|
||||||
|
|
||||||
if existing_shortfall:
|
if existing_shortfall:
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ class LoanSecurityUnpledge(Document):
|
|||||||
d.idx, frappe.bold(d.loan_security)))
|
d.idx, frappe.bold(d.loan_security)))
|
||||||
|
|
||||||
def validate_unpledge_qty(self):
|
def validate_unpledge_qty(self):
|
||||||
|
from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import get_ltv_ratio
|
||||||
|
|
||||||
pledge_qty_map = get_pledged_security_qty(self.loan)
|
pledge_qty_map = get_pledged_security_qty(self.loan)
|
||||||
|
|
||||||
ltv_ratio_map = frappe._dict(frappe.get_all("Loan Security Type",
|
ltv_ratio_map = frappe._dict(frappe.get_all("Loan Security Type",
|
||||||
@@ -47,6 +49,8 @@ class LoanSecurityUnpledge(Document):
|
|||||||
|
|
||||||
pending_principal_amount = flt(total_payment) - flt(interest_payable) - flt(principal_paid) - flt(written_off_amount)
|
pending_principal_amount = flt(total_payment) - flt(interest_payable) - flt(principal_paid) - flt(written_off_amount)
|
||||||
security_value = 0
|
security_value = 0
|
||||||
|
unpledge_qty_map = {}
|
||||||
|
ltv_ratio = 0
|
||||||
|
|
||||||
for security in self.securities:
|
for security in self.securities:
|
||||||
pledged_qty = pledge_qty_map.get(security.loan_security, 0)
|
pledged_qty = pledge_qty_map.get(security.loan_security, 0)
|
||||||
@@ -57,13 +61,15 @@ class LoanSecurityUnpledge(Document):
|
|||||||
msg += _("You are trying to unpledge more.")
|
msg += _("You are trying to unpledge more.")
|
||||||
frappe.throw(msg, title=_("Loan Security Unpledge Error"))
|
frappe.throw(msg, title=_("Loan Security Unpledge Error"))
|
||||||
|
|
||||||
qty_after_unpledge = pledged_qty - security.qty
|
unpledge_qty_map.setdefault(security.loan_security, 0)
|
||||||
ltv_ratio = ltv_ratio_map.get(security.loan_security_type)
|
unpledge_qty_map[security.loan_security] += security.qty
|
||||||
|
|
||||||
current_price = loan_security_price_map.get(security.loan_security)
|
for security in pledge_qty_map:
|
||||||
if not current_price:
|
if not ltv_ratio:
|
||||||
frappe.throw(_("No valid Loan Security Price found for {0}").format(frappe.bold(security.loan_security)))
|
ltv_ratio = get_ltv_ratio(security)
|
||||||
|
|
||||||
|
qty_after_unpledge = pledge_qty_map.get(security, 0) - unpledge_qty_map.get(security, 0)
|
||||||
|
current_price = loan_security_price_map.get(security)
|
||||||
security_value += qty_after_unpledge * current_price
|
security_value += qty_after_unpledge * current_price
|
||||||
|
|
||||||
if not security_value and flt(pending_principal_amount, 2) > 0:
|
if not security_value and flt(pending_principal_amount, 2) > 0:
|
||||||
|
|||||||
Reference in New Issue
Block a user