fix: Employee loan fixes
This commit is contained in:
@@ -312,13 +312,13 @@ scheduler_events = {
|
|||||||
"erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation",
|
"erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation",
|
||||||
"erpnext.hr.utils.generate_leave_encashment",
|
"erpnext.hr.utils.generate_leave_encashment",
|
||||||
"erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall.check_for_ltv_shortfall",
|
"erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall.check_for_ltv_shortfall",
|
||||||
"erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.make_accrual_interest_entry_for_term_loans"
|
"erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.process_loan_interest_accrual_for_term_loans"
|
||||||
],
|
],
|
||||||
"monthly_long": [
|
"monthly_long": [
|
||||||
"erpnext.accounts.deferred_revenue.convert_deferred_revenue_to_income",
|
"erpnext.accounts.deferred_revenue.convert_deferred_revenue_to_income",
|
||||||
"erpnext.accounts.deferred_revenue.convert_deferred_expense_to_expense",
|
"erpnext.accounts.deferred_revenue.convert_deferred_expense_to_expense",
|
||||||
"erpnext.hr.utils.allocate_earned_leaves",
|
"erpnext.hr.utils.allocate_earned_leaves",
|
||||||
"erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.process_loan_interest_accrual"
|
"erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.process_loan_interest_accrual_for_demand_loans"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -372,8 +372,7 @@
|
|||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"label": "Employee Loan",
|
"label": "Employee Loan",
|
||||||
"options": "Salary Slip Loan",
|
"options": "Salary Slip Loan",
|
||||||
"print_hide": 1,
|
"print_hide": 1
|
||||||
"read_only": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "section_break_43",
|
"fieldname": "section_break_43",
|
||||||
@@ -464,7 +463,7 @@
|
|||||||
"idx": 9,
|
"idx": 9,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2019-12-31 17:13:45.146271",
|
"modified": "2020-04-09 20:02:53.159827",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Salary Slip",
|
"name": "Salary Slip",
|
||||||
|
|||||||
@@ -97,6 +97,8 @@ frappe.ui.form.on('Loan', {
|
|||||||
"company": frm.doc.company,
|
"company": frm.doc.company,
|
||||||
"applicant_type": frm.doc.applicant_type,
|
"applicant_type": frm.doc.applicant_type,
|
||||||
"applicant": frm.doc.applicant,
|
"applicant": frm.doc.applicant,
|
||||||
|
"pending_amount": frm.doc.loan_amount - frm.doc.disbursed_amount > 0 ?
|
||||||
|
frm.doc.loan_amount - frm.doc.disbursed_amount : 0,
|
||||||
"as_dict": 1
|
"as_dict": 1
|
||||||
},
|
},
|
||||||
method: "erpnext.loan_management.doctype.loan.loan.make_loan_disbursement",
|
method: "erpnext.loan_management.doctype.loan.loan.make_loan_disbursement",
|
||||||
@@ -149,10 +151,10 @@ frappe.ui.form.on('Loan', {
|
|||||||
return frappe.call({
|
return frappe.call({
|
||||||
method: "erpnext.loan_management.doctype.loan.loan.get_loan_application",
|
method: "erpnext.loan_management.doctype.loan.loan.get_loan_application",
|
||||||
args: {
|
args: {
|
||||||
"loan_application": frm.doc.loan_application
|
"loan_application": frm.doc.loan_application
|
||||||
},
|
},
|
||||||
callback: function (r) {
|
callback: function (r) {
|
||||||
if (!r.exc && r.message) {
|
if (!r.exc && r.message) {
|
||||||
|
|
||||||
let loan_fields = ["loan_type", "loan_amount", "repayment_method",
|
let loan_fields = ["loan_type", "loan_amount", "repayment_method",
|
||||||
"monthly_repayment_amount", "repayment_periods", "rate_of_interest", "is_secured_loan"]
|
"monthly_repayment_amount", "repayment_periods", "rate_of_interest", "is_secured_loan"]
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ def close_loan(loan, total_amount_paid):
|
|||||||
frappe.db.set_value("Loan", loan, "status", "Closed")
|
frappe.db.set_value("Loan", loan, "status", "Closed")
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def make_loan_disbursement(loan, company, applicant_type, applicant, disbursed_amount=0, as_dict=0):
|
def make_loan_disbursement(loan, company, applicant_type, applicant, pending_amount=0, as_dict=0):
|
||||||
disbursement_entry = frappe.new_doc("Loan Disbursement")
|
disbursement_entry = frappe.new_doc("Loan Disbursement")
|
||||||
disbursement_entry.against_loan = loan
|
disbursement_entry.against_loan = loan
|
||||||
disbursement_entry.applicant_type = applicant_type
|
disbursement_entry.applicant_type = applicant_type
|
||||||
@@ -206,8 +206,7 @@ def make_loan_disbursement(loan, company, applicant_type, applicant, disbursed_a
|
|||||||
disbursement_entry.company = company
|
disbursement_entry.company = company
|
||||||
disbursement_entry.disbursement_date = nowdate()
|
disbursement_entry.disbursement_date = nowdate()
|
||||||
|
|
||||||
if disbursed_amount:
|
disbursement_entry.disbursed_amount = pending_amount
|
||||||
disbursement_entry.disbursed_amount = disbursed_amount
|
|
||||||
if as_dict:
|
if as_dict:
|
||||||
return disbursement_entry.as_dict()
|
return disbursement_entry.as_dict()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ from frappe.utils import (nowdate, add_days, getdate, now_datetime, add_to_date,
|
|||||||
add_months, get_first_day, get_last_day, flt, date_diff)
|
add_months, get_first_day, get_last_day, flt, date_diff)
|
||||||
from erpnext.selling.doctype.customer.test_customer import get_customer_dict
|
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.hr.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
|
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 (make_accrual_interest_entry_for_term_loans, days_in_year)
|
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (make_accrual_interest_entry_for_term_loans, days_in_year)
|
||||||
|
|
||||||
from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import check_for_ltv_shortfall
|
from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import check_for_ltv_shortfall
|
||||||
@@ -145,7 +146,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
|
|
||||||
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(posting_date = last_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, 10), "Regular Payment", 111118.68)
|
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 10), "Regular Payment", 111118.68)
|
||||||
repayment_entry.save()
|
repayment_entry.save()
|
||||||
@@ -186,7 +187,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
/ (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(posting_date = last_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),
|
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
|
||||||
"Loan Closure", 13315.0681)
|
"Loan Closure", 13315.0681)
|
||||||
@@ -224,7 +225,7 @@ class TestLoan(unittest.TestCase):
|
|||||||
|
|
||||||
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=add_months(nowdate(), -1))
|
make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=add_months(nowdate(), -1))
|
||||||
|
|
||||||
make_accrual_interest_entry_for_term_loans(posting_date=nowdate())
|
process_loan_interest_accrual_for_term_loans(posting_date=nowdate())
|
||||||
|
|
||||||
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(get_last_day(nowdate()), 5),
|
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(get_last_day(nowdate()), 5),
|
||||||
"Regular Payment", 89768.7534247)
|
"Regular Payment", 89768.7534247)
|
||||||
@@ -264,8 +265,8 @@ class TestLoan(unittest.TestCase):
|
|||||||
|
|
||||||
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(posting_date = add_days(first_date, 15))
|
process_loan_interest_accrual_for_demand_loans(posting_date = add_days(first_date, 15))
|
||||||
process_loan_interest_accrual(posting_date = add_days(first_date, 30))
|
process_loan_interest_accrual_for_demand_loans(posting_date = add_days(first_date, 30))
|
||||||
|
|
||||||
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 1), "Regular Payment", 6500)
|
repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 1), "Regular Payment", 6500)
|
||||||
repayment_entry.save()
|
repayment_entry.save()
|
||||||
|
|||||||
@@ -31,13 +31,15 @@ frappe.ui.form.on('Loan Application', {
|
|||||||
add_toolbar_buttons: function(frm) {
|
add_toolbar_buttons: function(frm) {
|
||||||
if (frm.doc.status == "Approved") {
|
if (frm.doc.status == "Approved") {
|
||||||
|
|
||||||
frappe.db.get_value("Loan Security Pledge", {"loan_application": frm.doc.name, "docstatus": 1}, "name", (r) => {
|
if (frm.doc.is_secured) {
|
||||||
if (!r) {
|
frappe.db.get_value("Loan Security Pledge", {"loan_application": frm.doc.name, "docstatus": 1}, "name", (r) => {
|
||||||
frm.add_custom_button(__('Loan Security Pledge'), function() {
|
if (!r) {
|
||||||
frm.trigger('create_loan_security_pledge')
|
frm.add_custom_button(__('Loan Security Pledge'), function() {
|
||||||
},__('Create'))
|
frm.trigger('create_loan_security_pledge')
|
||||||
}
|
},__('Create'))
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
frappe.db.get_value("Loan", {"loan_application": frm.doc.name, "docstatus": 1}, "name", (r) => {
|
frappe.db.get_value("Loan", {"loan_application": frm.doc.name, "docstatus": 1}, "name", (r) => {
|
||||||
if (!r) {
|
if (!r) {
|
||||||
@@ -61,6 +63,11 @@ frappe.ui.form.on('Loan Application', {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
create_loan_security_pledge: function(frm) {
|
create_loan_security_pledge: function(frm) {
|
||||||
|
|
||||||
|
if(!frm.doc.is_secured_loan) {
|
||||||
|
frappe.throw(__("Loan Security Pledge can only be created for secured loans"));
|
||||||
|
}
|
||||||
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.loan_management.doctype.loan_application.loan_application.create_pledge",
|
method: "erpnext.loan_management.doctype.loan_application.loan_application.create_pledge",
|
||||||
args: {
|
args: {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"autoname": "LM-DIS-.#####",
|
"autoname": "LM-DIS-.#####",
|
||||||
"creation": "2019-09-07 12:44:49.125452",
|
"creation": "2019-09-07 12:44:49.125452",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
@@ -13,7 +14,6 @@
|
|||||||
"applicant_type",
|
"applicant_type",
|
||||||
"applicant",
|
"applicant",
|
||||||
"section_break_7",
|
"section_break_7",
|
||||||
"pending_amount_for_disbursal",
|
|
||||||
"disbursed_amount",
|
"disbursed_amount",
|
||||||
"accounting_dimensions_section",
|
"accounting_dimensions_section",
|
||||||
"cost_center",
|
"cost_center",
|
||||||
@@ -83,13 +83,6 @@
|
|||||||
"label": "Posting Date",
|
"label": "Posting Date",
|
||||||
"read_only": 1
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"fieldname": "pending_amount_for_disbursal",
|
|
||||||
"fieldtype": "Currency",
|
|
||||||
"label": "Pending Amount For Disbursal",
|
|
||||||
"options": "Company:company:default_currency",
|
|
||||||
"read_only": 1
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"fieldname": "column_break_4",
|
"fieldname": "column_break_4",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
@@ -99,6 +92,7 @@
|
|||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"collapsible": 1,
|
||||||
"fieldname": "section_break_13",
|
"fieldname": "section_break_13",
|
||||||
"fieldtype": "Section Break"
|
"fieldtype": "Section Break"
|
||||||
},
|
},
|
||||||
@@ -123,7 +117,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-10-24 12:32:32.230881",
|
"links": [],
|
||||||
|
"modified": "2020-04-09 14:44:28.527271",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Loan Disbursement",
|
"name": "Loan Disbursement",
|
||||||
|
|||||||
@@ -4,21 +4,24 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe, erpnext
|
import frappe, erpnext
|
||||||
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import nowdate, getdate, add_days, flt
|
from frappe.utils import nowdate, getdate, add_days, flt
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries
|
from erpnext.accounts.general_ledger import make_gl_entries
|
||||||
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual
|
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans
|
||||||
|
|
||||||
class LoanDisbursement(AccountsController):
|
class LoanDisbursement(AccountsController):
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.set_missing_values()
|
self.set_missing_values()
|
||||||
self.set_pending_amount_for_disbursal()
|
|
||||||
|
|
||||||
def before_submit(self):
|
def before_submit(self):
|
||||||
self.set_status_and_amounts()
|
self.set_status_and_amounts()
|
||||||
|
|
||||||
|
def before_cancel(self):
|
||||||
|
self.set_status_and_amounts(cancel=1)
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.make_gl_entries()
|
self.make_gl_entries()
|
||||||
|
|
||||||
@@ -38,13 +41,7 @@ class LoanDisbursement(AccountsController):
|
|||||||
if not self.bank_account and self.applicant_type == "Customer":
|
if not self.bank_account and self.applicant_type == "Customer":
|
||||||
self.bank_account = frappe.db.get_value("Customer", self.applicant, "default_bank_account")
|
self.bank_account = frappe.db.get_value("Customer", self.applicant, "default_bank_account")
|
||||||
|
|
||||||
def set_pending_amount_for_disbursal(self):
|
def set_status_and_amounts(self, cancel=0):
|
||||||
loan_amount, disbursed_amount = frappe.db.get_value('Loan',
|
|
||||||
{'name': self.against_loan}, ['loan_amount', 'disbursed_amount'])
|
|
||||||
|
|
||||||
self.pending_amount_for_disbursal = loan_amount - disbursed_amount
|
|
||||||
|
|
||||||
def set_status_and_amounts(self):
|
|
||||||
|
|
||||||
loan_details = frappe.get_all("Loan",
|
loan_details = frappe.get_all("Loan",
|
||||||
fields = ["loan_amount", "disbursed_amount", "total_principal_paid", "status", "is_term_loan"],
|
fields = ["loan_amount", "disbursed_amount", "total_principal_paid", "status", "is_term_loan"],
|
||||||
@@ -52,26 +49,32 @@ class LoanDisbursement(AccountsController):
|
|||||||
)[0]
|
)[0]
|
||||||
|
|
||||||
if loan_details.status == "Disbursed" and not loan_details.is_term_loan:
|
if loan_details.status == "Disbursed" and not loan_details.is_term_loan:
|
||||||
process_loan_interest_accrual(posting_date=add_days(self.disbursement_date, -1),
|
process_loan_interest_accrual_for_demand_loans(posting_date=add_days(self.disbursement_date, -1),
|
||||||
loan=self.against_loan)
|
loan=self.against_loan)
|
||||||
|
|
||||||
disbursed_amount = self.disbursed_amount + loan_details.disbursed_amount
|
if cancel:
|
||||||
|
disbursed_amount = loan_details.disbursed_amount - self.disbursed_amount
|
||||||
if flt(disbursed_amount) - flt(loan_details.total_principal_paid) > flt(loan_details.loan_amount):
|
if disbursed_amount == 0:
|
||||||
frappe.throw(_("Disbursed Amount cannot be greater than loan amount"))
|
status = "Sanctioned"
|
||||||
|
elif disbursed_amount >= loan_details.disbursed_amount:
|
||||||
if flt(disbursed_amount) > flt(loan_details.loan_amount):
|
status = "Disbursed"
|
||||||
total_principal_paid = loan_details.total_principal_paid - (disbursed_amount - loan_details.loan_amount)
|
else:
|
||||||
frappe.db.set_value("Loan", self.against_loan, "total_principal_paid", total_principal_paid)
|
status = "Partially Disbursed"
|
||||||
|
|
||||||
if flt(loan_details.loan_amount) == flt(disbursed_amount):
|
|
||||||
frappe.db.set_value("Loan", self.against_loan, "status", "Disbursed")
|
|
||||||
else:
|
else:
|
||||||
frappe.db.set_value("Loan", self.against_loan, "status", "Partially Disbursed")
|
disbursed_amount = self.disbursed_amount + loan_details.disbursed_amount
|
||||||
|
|
||||||
|
if flt(disbursed_amount) - flt(loan_details.total_principal_paid) > flt(loan_details.loan_amount):
|
||||||
|
frappe.throw(_("Disbursed Amount cannot be greater than loan amount"))
|
||||||
|
|
||||||
|
if flt(disbursed_amount) >= loan_details.disbursed_amount:
|
||||||
|
status = "Disbursed"
|
||||||
|
else:
|
||||||
|
status = "Partially Disbursed"
|
||||||
|
|
||||||
frappe.db.set_value("Loan", self.against_loan, {
|
frappe.db.set_value("Loan", self.against_loan, {
|
||||||
"disbursement_date": self.disbursement_date,
|
"disbursement_date": self.disbursement_date,
|
||||||
"disbursed_amount": disbursed_amount
|
"disbursed_amount": disbursed_amount,
|
||||||
|
"status": status
|
||||||
})
|
})
|
||||||
|
|
||||||
def make_gl_entries(self, cancel=0, adv_adj=0):
|
def make_gl_entries(self, cancel=0, adv_adj=0):
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import unittest
|
|||||||
from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_last_day, date_diff, flt, add_to_date)
|
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,
|
||||||
make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan, create_loan_security_price)
|
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
|
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 (make_accrual_interest_entry_for_term_loans, days_in_year)
|
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (make_accrual_interest_entry_for_term_loans, days_in_year)
|
||||||
from erpnext.selling.doctype.customer.test_customer import get_customer_dict
|
from erpnext.selling.doctype.customer.test_customer import get_customer_dict
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ class TestLoanDisbursement(unittest.TestCase):
|
|||||||
|
|
||||||
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(posting_date=add_days(last_date, 1))
|
process_loan_interest_accrual_for_demand_loans(posting_date=add_days(last_date, 1))
|
||||||
|
|
||||||
# Paid 511095.89 amount includes 5,00,000 principal amount and 11095.89 interest amount
|
# Paid 511095.89 amount includes 5,00,000 principal amount and 11095.89 interest amount
|
||||||
repayment_entry = create_repayment_entry(loan.name, self.applicant, add_days(get_last_day(nowdate()), 5),
|
repayment_entry = create_repayment_entry(loan.name, self.applicant, add_days(get_last_day(nowdate()), 5),
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"interest_amount",
|
"interest_amount",
|
||||||
"section_break_15",
|
"section_break_15",
|
||||||
"process_loan_interest_accrual",
|
"process_loan_interest_accrual",
|
||||||
|
"repayment_schedule_name",
|
||||||
"amended_from"
|
"amended_from"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
@@ -135,12 +136,19 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "column_break_14",
|
"fieldname": "column_break_14",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "repayment_schedule_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Repayment Schedule Name",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"in_create": 1,
|
"in_create": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-02-07 01:22:06.924125",
|
"modified": "2020-04-10 18:31:02.369857",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Loan Interest Accrual",
|
"name": "Loan Interest Accrual",
|
||||||
|
|||||||
@@ -27,8 +27,14 @@ class LoanInterestAccrual(AccountsController):
|
|||||||
self.make_gl_entries()
|
self.make_gl_entries()
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
|
if self.repayment_schedule_name:
|
||||||
|
self.update_is_accrued()
|
||||||
|
|
||||||
self.make_gl_entries(cancel=1)
|
self.make_gl_entries(cancel=1)
|
||||||
|
|
||||||
|
def update_is_accrued(self):
|
||||||
|
frappe.db.set_value('Repayment Schedule', self.repayment_schedule_name, 'is_accrued', 0)
|
||||||
|
|
||||||
def make_gl_entries(self, cancel=0, adv_adj=0):
|
def make_gl_entries(self, cancel=0, adv_adj=0):
|
||||||
gle_map = []
|
gle_map = []
|
||||||
|
|
||||||
@@ -83,9 +89,19 @@ def calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_i
|
|||||||
interest_per_day = (pending_principal_amount * loan.rate_of_interest) / (days_in_year(get_datetime(posting_date).year) * 100)
|
interest_per_day = (pending_principal_amount * loan.rate_of_interest) / (days_in_year(get_datetime(posting_date).year) * 100)
|
||||||
payable_interest = interest_per_day * no_of_days
|
payable_interest = interest_per_day * no_of_days
|
||||||
|
|
||||||
make_loan_interest_accrual_entry(loan.name, loan.applicant_type, loan.applicant,loan.interest_income_account,
|
args = frappe._dict({
|
||||||
loan.loan_account, pending_principal_amount, payable_interest, process_loan_interest = process_loan_interest,
|
'loan': loan.name,
|
||||||
posting_date=posting_date)
|
'applicant_type': loan.applicant_type,
|
||||||
|
'applicant': loan.applicant,
|
||||||
|
'interest_income_account': loan.interest_income_account,
|
||||||
|
'loan_account': loan.loan_acccount,
|
||||||
|
'pending_principal_amount': pending_principal_amount,
|
||||||
|
'interest_amount': payable_interest,
|
||||||
|
'process_loan_interest': process_loan_interest,
|
||||||
|
'posting_date': posting_date
|
||||||
|
})
|
||||||
|
|
||||||
|
make_loan_interest_accrual_entry(args)
|
||||||
|
|
||||||
def make_accrual_interest_entry_for_demand_loans(posting_date, process_loan_interest, open_loans=None, loan_type=None):
|
def make_accrual_interest_entry_for_demand_loans(posting_date, process_loan_interest, open_loans=None, loan_type=None):
|
||||||
query_filters = {
|
query_filters = {
|
||||||
@@ -107,49 +123,71 @@ def make_accrual_interest_entry_for_demand_loans(posting_date, process_loan_inte
|
|||||||
for loan in open_loans:
|
for loan in open_loans:
|
||||||
calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest)
|
calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest)
|
||||||
|
|
||||||
def make_accrual_interest_entry_for_term_loans(posting_date=None):
|
def make_accrual_interest_entry_for_term_loans(posting_date, process_loan_interest, term_loan=None, loan_type=None):
|
||||||
curr_date = posting_date or add_days(nowdate(), 1)
|
curr_date = posting_date or add_days(nowdate(), 1)
|
||||||
|
|
||||||
term_loans = frappe.db.sql("""SELECT l.name, l.total_payment, l.total_amount_paid, l.loan_account,
|
term_loans = get_term_loans(curr_date, term_loan, loan_type)
|
||||||
l.interest_income_account, l.is_term_loan, l.disbursement_date, l.applicant_type, l.applicant,
|
|
||||||
l.rate_of_interest, l.total_interest_payable, l.repayment_start_date, rs.name as payment_entry,
|
|
||||||
rs.payment_date, rs.principal_amount, rs.interest_amount, rs.is_accrued , rs.balance_loan_amount
|
|
||||||
FROM `tabLoan` l, `tabRepayment Schedule` rs
|
|
||||||
WHERE rs.parent = l.name
|
|
||||||
AND l.docstatus=1
|
|
||||||
AND l.is_term_loan =1
|
|
||||||
AND rs.payment_date <= %s
|
|
||||||
AND rs.is_accrued=0
|
|
||||||
AND l.status = 'Disbursed'""", (curr_date), as_dict=1)
|
|
||||||
|
|
||||||
accrued_entries = []
|
accrued_entries = []
|
||||||
|
|
||||||
for loan in term_loans:
|
for loan in term_loans:
|
||||||
accrued_entries.append(loan.payment_entry)
|
accrued_entries.append(loan.payment_entry)
|
||||||
make_loan_interest_accrual_entry(loan.name, loan.applicant_type, loan.applicant,loan.interest_income_account,
|
args = frappe._dict({
|
||||||
loan.loan_account, loan.principal_amount + loan.balance_loan_amount, loan.interest_amount,
|
'loan': loan.name,
|
||||||
payable_principal = loan.principal_amount , posting_date=posting_date)
|
'applicant_type': loan.applicant_type,
|
||||||
|
'applicant': loan.applicant,
|
||||||
|
'interest_income_account': loan.interest_income_account,
|
||||||
|
'loan_account': loan.loan_acccount,
|
||||||
|
'interest_amount': loan.interest_amount,
|
||||||
|
'payable_principal': loan.principal_amount,
|
||||||
|
'process_loan_interest': process_loan_interest,
|
||||||
|
'repayment_schedule_name': loan.payment_entry,
|
||||||
|
'posting_date': posting_date
|
||||||
|
})
|
||||||
|
|
||||||
|
make_loan_interest_accrual_entry(args)
|
||||||
|
|
||||||
if accrued_entries:
|
if accrued_entries:
|
||||||
frappe.db.sql("""UPDATE `tabRepayment Schedule`
|
frappe.db.sql("""UPDATE `tabRepayment Schedule`
|
||||||
SET is_accrued = 1 where name in (%s)""" #nosec
|
SET is_accrued = 1 where name in (%s)""" #nosec
|
||||||
% ", ".join(['%s']*len(accrued_entries)), tuple(accrued_entries))
|
% ", ".join(['%s']*len(accrued_entries)), tuple(accrued_entries))
|
||||||
|
|
||||||
def make_loan_interest_accrual_entry(loan, applicant_type, applicant, interest_income_account, loan_account,
|
def get_term_loans(date, term_loan=None, loan_type=None):
|
||||||
pending_principal_amount, interest_amount, payable_principal=None, process_loan_interest=None, posting_date=None):
|
condition = ''
|
||||||
loan_interest_accrual = frappe.new_doc("Loan Interest Accrual")
|
|
||||||
loan_interest_accrual.loan = loan
|
|
||||||
loan_interest_accrual.applicant_type = applicant_type
|
|
||||||
loan_interest_accrual.applicant = applicant
|
|
||||||
loan_interest_accrual.interest_income_account = interest_income_account
|
|
||||||
loan_interest_accrual.loan_account = loan_account
|
|
||||||
loan_interest_accrual.pending_principal_amount = flt(pending_principal_amount, 2)
|
|
||||||
loan_interest_accrual.interest_amount = flt(interest_amount, 2)
|
|
||||||
loan_interest_accrual.posting_date = posting_date or nowdate()
|
|
||||||
loan_interest_accrual.process_loan_interest_accrual = process_loan_interest
|
|
||||||
|
|
||||||
if payable_principal:
|
if term_loan:
|
||||||
loan_interest_accrual.payable_principal_amount = payable_principal
|
condition +=' AND l.name = %s' % frappe.db.escape(term_loan)
|
||||||
|
|
||||||
|
if loan_type:
|
||||||
|
condition += ' AND l.loan_type = %s' % frappe.db.escape(loan_type)
|
||||||
|
|
||||||
|
term_loans = frappe.db.sql("""SELECT l.name, l.total_payment, l.total_amount_paid, l.loan_account,
|
||||||
|
l.interest_income_account, l.is_term_loan, l.disbursement_date, l.applicant_type, l.applicant,
|
||||||
|
l.rate_of_interest, l.total_interest_payable, l.repayment_start_date, rs.name as payment_entry,
|
||||||
|
rs.payment_date, rs.principal_amount, rs.interest_amount, rs.is_accrued , rs.balance_loan_amount
|
||||||
|
FROM `tabLoan` l, `tabRepayment Schedule` rs
|
||||||
|
WHERE rs.parent = l.name
|
||||||
|
AND l.docstatus=1
|
||||||
|
AND l.is_term_loan =1
|
||||||
|
AND rs.payment_date <= %s
|
||||||
|
AND rs.is_accrued=0 {0}
|
||||||
|
AND l.status = 'Disbursed'""".format(condition), (getdate(date)), as_dict=1)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
loan_interest_accrual.save()
|
loan_interest_accrual.save()
|
||||||
loan_interest_accrual.submit()
|
loan_interest_accrual.submit()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import unittest
|
|||||||
from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_last_day, date_diff, flt, add_to_date)
|
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,
|
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)
|
||||||
from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual
|
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 (make_accrual_interest_entry_for_term_loans, days_in_year)
|
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (make_accrual_interest_entry_for_term_loans, days_in_year)
|
||||||
from erpnext.selling.doctype.customer.test_customer import get_customer_dict
|
from erpnext.selling.doctype.customer.test_customer import get_customer_dict
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ class TestLoanInterestAccrual(unittest.TestCase):
|
|||||||
|
|
||||||
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(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})
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"posting_date",
|
"posting_date",
|
||||||
"loan_type",
|
"loan_type",
|
||||||
"loan",
|
"loan",
|
||||||
|
"process_type",
|
||||||
"amended_from"
|
"amended_from"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
@@ -39,11 +40,18 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Loan ",
|
"label": "Loan ",
|
||||||
"options": "Loan"
|
"options": "Loan"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "process_type",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Process Type",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2020-02-01 08:14:33.978636",
|
"modified": "2020-04-09 22:52:53.911416",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Process Loan Interest Accrual",
|
"name": "Process Loan Interest Accrual",
|
||||||
@@ -74,7 +82,6 @@
|
|||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import nowdate
|
from frappe.utils import nowdate
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import make_accrual_interest_entry_for_demand_loans
|
from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (make_accrual_interest_entry_for_demand_loans,
|
||||||
|
make_accrual_interest_entry_for_term_loans)
|
||||||
|
|
||||||
class ProcessLoanInterestAccrual(Document):
|
class ProcessLoanInterestAccrual(Document):
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
@@ -14,16 +15,45 @@ class ProcessLoanInterestAccrual(Document):
|
|||||||
|
|
||||||
if self.loan:
|
if self.loan:
|
||||||
loan_doc = frappe.get_doc('Loan', self.loan)
|
loan_doc = frappe.get_doc('Loan', self.loan)
|
||||||
open_loans.append(loan_doc)
|
if loan_doc:
|
||||||
|
open_loans.append(loan_doc)
|
||||||
|
|
||||||
make_accrual_interest_entry_for_demand_loans(self.posting_date, self.name,
|
if (not self.loan or not loan_doc.is_term_loan) and self.process_type != 'Term Loans':
|
||||||
open_loans = open_loans, loan_type = self.loan_type)
|
make_accrual_interest_entry_for_demand_loans(self.posting_date, self.name,
|
||||||
|
open_loans = open_loans, loan_type = self.loan_type)
|
||||||
|
|
||||||
def process_loan_interest_accrual(posting_date=None, loan_type=None, loan=None):
|
if (not self.loan or loan_doc.is_term_loan) and self.process_type != 'Demand Loans':
|
||||||
|
make_accrual_interest_entry_for_term_loans(self.posting_date, self.name, term_loan=self.loan,
|
||||||
|
loan_type=self.loan_type)
|
||||||
|
|
||||||
|
|
||||||
|
def process_loan_interest_accrual_for_demand_loans(posting_date=None, loan_type=None, loan=None):
|
||||||
loan_process = frappe.new_doc('Process Loan Interest Accrual')
|
loan_process = frappe.new_doc('Process Loan Interest Accrual')
|
||||||
loan_process.posting_date = posting_date or nowdate()
|
loan_process.posting_date = posting_date or nowdate()
|
||||||
loan_process.loan_type = loan_type
|
loan_process.loan_type = loan_type
|
||||||
|
loan_process.process_type = 'Demand Loans'
|
||||||
loan_process.loan = loan
|
loan_process.loan = loan
|
||||||
|
|
||||||
loan_process.submit()
|
loan_process.submit()
|
||||||
|
|
||||||
|
def process_loan_interest_accrual_for_term_loans(posting_date=None, loan_type=None, loan=None):
|
||||||
|
|
||||||
|
if not term_loan_accrual_pending(posting_date or nowdate()):
|
||||||
|
return
|
||||||
|
|
||||||
|
loan_process = frappe.new_doc('Process Loan Interest Accrual')
|
||||||
|
loan_process.posting_date = posting_date or nowdate()
|
||||||
|
loan_process.loan_type = loan_type
|
||||||
|
loan_process.process_type = 'Term Loans'
|
||||||
|
loan_process.loan = loan
|
||||||
|
|
||||||
|
loan_process.submit()
|
||||||
|
|
||||||
|
def term_loan_accrual_pending(date):
|
||||||
|
pending_accrual = frappe.db.get_value('Repayment Schedule', {
|
||||||
|
'payment_date': ('<=', date),
|
||||||
|
'is_accrued': 0
|
||||||
|
})
|
||||||
|
|
||||||
|
return pending_accrual
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"actions": [],
|
||||||
"creation": "2019-08-29 18:11:36.829526",
|
"creation": "2019-08-29 18:11:36.829526",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
@@ -49,16 +50,14 @@
|
|||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Principal Amount",
|
"label": "Principal Amount",
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency"
|
||||||
"read_only": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "interest_amount",
|
"fieldname": "interest_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Interest Amount",
|
"label": "Interest Amount",
|
||||||
"options": "Company:company:default_currency",
|
"options": "Company:company:default_currency"
|
||||||
"read_only": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "total_payment",
|
"fieldname": "total_payment",
|
||||||
@@ -79,11 +78,13 @@
|
|||||||
"fieldname": "loan_type",
|
"fieldname": "loan_type",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Loan Type",
|
"label": "Loan Type",
|
||||||
"options": "Loan Type"
|
"options": "Loan Type",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-10-28 09:15:31.174244",
|
"links": [],
|
||||||
|
"modified": "2020-04-09 20:01:53.546364",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Loan Management",
|
"module": "Loan Management",
|
||||||
"name": "Salary Slip Loan",
|
"name": "Salary Slip Loan",
|
||||||
|
|||||||
Reference in New Issue
Block a user