Merge pull request #22142 from deepeshgarg007/loan_amount_precision
fix: Precision in loan amount calculation
This commit is contained in:
commit
63e8391381
@ -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",
|
||||
@ -34,11 +34,10 @@
|
||||
"docstatus": 0,
|
||||
"doctype": "Desk Page",
|
||||
"extends_another_page": 0,
|
||||
"hide_custom": 0,
|
||||
"idx": 0,
|
||||
"is_standard": 1,
|
||||
"label": "Loan",
|
||||
"modified": "2020-05-28 13:37:42.017709",
|
||||
"modified": "2020-06-07 19:42:14.947902",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Loan Management",
|
||||
"name": "Loan",
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
@ -176,21 +177,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,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:
|
||||
@ -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:
|
||||
|
@ -41,6 +41,7 @@
|
||||
"options": "Company:company:default_currency"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "rate_of_interest",
|
||||
"fieldtype": "Percent",
|
||||
"label": "Rate of Interest (%) Yearly",
|
||||
@ -143,7 +144,7 @@
|
||||
],
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-15 00:24:43.259963",
|
||||
"modified": "2020-06-07 18:55:59.346292",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Loan Management",
|
||||
"name": "Loan Type",
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user