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,
|
"hidden": 0,
|
||||||
"label": "Reports",
|
"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",
|
"category": "Modules",
|
||||||
@ -34,11 +34,10 @@
|
|||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "Desk Page",
|
"doctype": "Desk Page",
|
||||||
"extends_another_page": 0,
|
"extends_another_page": 0,
|
||||||
"hide_custom": 0,
|
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"is_standard": 1,
|
"is_standard": 1,
|
||||||
"label": "Loan",
|
"label": "Loan",
|
||||||
"modified": "2020-05-28 13:37:42.017709",
|
"modified": "2020-06-07 19:42:14.947902",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Loan",
|
"name": "Loan",
|
||||||
|
|||||||
@ -27,6 +27,7 @@ class LoanDisbursement(AccountsController):
|
|||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
self.make_gl_entries(cancel=1)
|
self.make_gl_entries(cancel=1)
|
||||||
|
self.ignore_linked_doctypes = ['GL Entry']
|
||||||
|
|
||||||
def set_missing_values(self):
|
def set_missing_values(self):
|
||||||
if not self.disbursement_date:
|
if not self.disbursement_date:
|
||||||
|
|||||||
@ -31,6 +31,7 @@ class LoanInterestAccrual(AccountsController):
|
|||||||
self.update_is_accrued()
|
self.update_is_accrued()
|
||||||
|
|
||||||
self.make_gl_entries(cancel=1)
|
self.make_gl_entries(cancel=1)
|
||||||
|
self.ignore_linked_doctypes = ['GL Entry']
|
||||||
|
|
||||||
def update_is_accrued(self):
|
def update_is_accrued(self):
|
||||||
frappe.db.set_value('Repayment Schedule', self.repayment_schedule_name, 'is_accrued', 0)
|
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
|
return term_loans
|
||||||
|
|
||||||
def make_loan_interest_accrual_entry(args):
|
def make_loan_interest_accrual_entry(args):
|
||||||
loan_interest_accrual = frappe.new_doc("Loan Interest Accrual")
|
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||||
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
|
|
||||||
|
|
||||||
loan_interest_accrual.save()
|
loan_interest_accrual = frappe.new_doc("Loan Interest Accrual")
|
||||||
loan_interest_accrual.submit()
|
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):
|
def get_no_of_days_for_interest_accural(loan, posting_date):
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
import json
|
import json
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt, getdate
|
from frappe.utils import flt, getdate, cint
|
||||||
from six import iteritems
|
from six import iteritems
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import date_diff, add_days, getdate, add_months, get_first_day, get_datetime
|
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):
|
def on_cancel(self):
|
||||||
self.mark_as_unpaid()
|
self.mark_as_unpaid()
|
||||||
self.make_gl_entries(cancel=1)
|
self.make_gl_entries(cancel=1)
|
||||||
|
self.ignore_linked_doctypes = ['GL Entry']
|
||||||
|
|
||||||
def set_missing_values(self, amounts):
|
def set_missing_values(self, amounts):
|
||||||
|
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||||
|
|
||||||
if not self.posting_date:
|
if not self.posting_date:
|
||||||
self.posting_date = get_datetime()
|
self.posting_date = get_datetime()
|
||||||
|
|
||||||
@ -38,24 +41,26 @@ class LoanRepayment(AccountsController):
|
|||||||
self.cost_center = erpnext.get_default_cost_center(self.company)
|
self.cost_center = erpnext.get_default_cost_center(self.company)
|
||||||
|
|
||||||
if not self.interest_payable:
|
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:
|
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:
|
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:
|
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:
|
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'):
|
if amounts.get('due_date'):
|
||||||
self.due_date = amounts.get('due_date')
|
self.due_date = amounts.get('due_date')
|
||||||
|
|
||||||
def validate_amount(self):
|
def validate_amount(self):
|
||||||
|
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||||
|
|
||||||
if not self.amount_paid:
|
if not self.amount_paid:
|
||||||
frappe.throw(_("Amount paid cannot be zero"))
|
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)
|
msg = _("Paid amount cannot be less than {0}").format(self.penalty_amount)
|
||||||
frappe.throw(msg)
|
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)
|
msg = _("Amount of {0} is required for Loan closure").format(self.payable_amount)
|
||||||
frappe.throw(msg)
|
frappe.throw(msg)
|
||||||
|
|
||||||
def update_paid_amount(self):
|
def update_paid_amount(self):
|
||||||
|
precision = cint(frappe.db.get_default("currency_precision")) or 2
|
||||||
|
|
||||||
loan = frappe.get_doc("Loan", self.against_loan)
|
loan = frappe.get_doc("Loan", self.against_loan)
|
||||||
|
|
||||||
for payment in self.repayment_details:
|
for payment in self.repayment_details:
|
||||||
@ -75,9 +82,9 @@ class LoanRepayment(AccountsController):
|
|||||||
SET paid_principal_amount = `paid_principal_amount` + %s,
|
SET paid_principal_amount = `paid_principal_amount` + %s,
|
||||||
paid_interest_amount = `paid_interest_amount` + %s
|
paid_interest_amount = `paid_interest_amount` + %s
|
||||||
WHERE name = %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:
|
if loan.is_secured_loan:
|
||||||
frappe.db.set_value("Loan", self.against_loan, "status", "Loan Closure Requested")
|
frappe.db.set_value("Loan", self.against_loan, "status", "Loan Closure Requested")
|
||||||
else:
|
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
|
# 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):
|
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)
|
against_loan_doc = frappe.get_doc("Loan", against_loan)
|
||||||
loan_type_details = frappe.get_doc("Loan Type", against_loan_doc.loan_type)
|
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
|
payable_principal_amount += entry.payable_principal_amount
|
||||||
|
|
||||||
pending_accrual_entries.setdefault(entry.name, {
|
pending_accrual_entries.setdefault(entry.name, {
|
||||||
'interest_amount': flt(entry.interest_amount),
|
'interest_amount': flt(entry.interest_amount, precision),
|
||||||
'payable_principal_amount': flt(entry.payable_principal_amount)
|
'payable_principal_amount': flt(entry.payable_principal_amount, precision)
|
||||||
})
|
})
|
||||||
|
|
||||||
if not final_due_date:
|
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
|
per_day_interest = (payable_principal_amount * (loan_type_details.rate_of_interest / 100))/365
|
||||||
total_pending_interest += (pending_days * per_day_interest)
|
total_pending_interest += (pending_days * per_day_interest)
|
||||||
|
|
||||||
amounts["pending_principal_amount"] = pending_principal_amount
|
amounts["pending_principal_amount"] = flt(pending_principal_amount, precision)
|
||||||
amounts["payable_principal_amount"] = payable_principal_amount
|
amounts["payable_principal_amount"] = flt(payable_principal_amount, precision)
|
||||||
amounts["interest_amount"] = total_pending_interest
|
amounts["interest_amount"] = flt(total_pending_interest, precision)
|
||||||
amounts["penalty_amount"] = penalty_amount
|
amounts["penalty_amount"] = flt(penalty_amount, precision)
|
||||||
amounts["payable_amount"] = payable_principal_amount + total_pending_interest + penalty_amount
|
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
|
||||||
|
|
||||||
if final_due_date:
|
if final_due_date:
|
||||||
|
|||||||
@ -41,6 +41,7 @@
|
|||||||
"options": "Company:company:default_currency"
|
"options": "Company:company:default_currency"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "0",
|
||||||
"fieldname": "rate_of_interest",
|
"fieldname": "rate_of_interest",
|
||||||
"fieldtype": "Percent",
|
"fieldtype": "Percent",
|
||||||
"label": "Rate of Interest (%) Yearly",
|
"label": "Rate of Interest (%) Yearly",
|
||||||
@ -143,7 +144,7 @@
|
|||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-04-15 00:24:43.259963",
|
"modified": "2020-06-07 18:55:59.346292",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Loan Type",
|
"name": "Loan Type",
|
||||||
|
|||||||
@ -76,7 +76,8 @@ def get_columns(filters):
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"fieldname": "currency",
|
"fieldname": "currency",
|
||||||
"options": "Currency",
|
"options": "Currency",
|
||||||
"width": 50
|
"width": 50,
|
||||||
|
"hidden": 1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -84,17 +85,13 @@ def get_columns(filters):
|
|||||||
|
|
||||||
def get_data(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 = []
|
data = []
|
||||||
conditions = get_conditions(filters)
|
conditions = get_conditions(filters)
|
||||||
|
|
||||||
loan_security_pledges = frappe.db.sql("""
|
loan_security_pledges = frappe.db.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
p.name, p.applicant, p.loan, p.status, p.pledge_time,
|
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
|
FROM
|
||||||
`tabLoan Security Pledge` p, `tabPledge` c
|
`tabLoan Security Pledge` p, `tabPledge` c
|
||||||
WHERE
|
WHERE
|
||||||
@ -115,8 +112,8 @@ def get_data(filters):
|
|||||||
row["pledge_time"] = pledge.pledge_time
|
row["pledge_time"] = pledge.pledge_time
|
||||||
row["loan_security"] = pledge.loan_security
|
row["loan_security"] = pledge.loan_security
|
||||||
row["qty"] = pledge.qty
|
row["qty"] = pledge.qty
|
||||||
row["loan_security_price"] = loan_security_price_map.get(pledge.loan_security)
|
row["loan_security_price"] = pledge.loan_security_price
|
||||||
row["loan_security_value"] = row["loan_security_price"] * pledge.qty
|
row["loan_security_value"] = pledge.amount
|
||||||
row["currency"] = default_currency
|
row["currency"] = default_currency
|
||||||
|
|
||||||
data.append(row)
|
data.append(row)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user