feat: Refund entry against loans

This commit is contained in:
Deepesh Garg 2022-01-25 19:59:33 +05:30
parent 388293dbea
commit c68c70f8bc
9 changed files with 133 additions and 22 deletions

View File

@ -46,7 +46,7 @@ frappe.ui.form.on('Loan', {
});
});
$.each(["payment_account", "loan_account"], function (i, field) {
$.each(["payment_account", "loan_account", "disbursement_account"], function (i, field) {
frm.set_query(field, function () {
return {
"filters": {
@ -88,6 +88,10 @@ frappe.ui.form.on('Loan', {
frm.add_custom_button(__('Loan Write Off'), function() {
frm.trigger("make_loan_write_off_entry");
},__('Create'));
frm.add_custom_button(__('Loan Refund'), function() {
frm.trigger("make_loan_refund");
},__('Create'));
}
}
frm.trigger("toggle_fields");
@ -155,6 +159,21 @@ frappe.ui.form.on('Loan', {
})
},
make_loan_refund: function(frm) {
frappe.call({
args: {
"loan": frm.doc.name
},
method: "erpnext.loan_management.doctype.loan.loan.make_refund_jv",
callback: function (r) {
if (r.message) {
let doc = frappe.model.sync(r.message)[0];
frappe.set_route("Form", doc.doctype, doc.name);
}
}
})
},
request_loan_closure: function(frm) {
frappe.confirm(__("Do you really want to close this loan"),
function() {

View File

@ -2,7 +2,7 @@
"actions": [],
"allow_import": 1,
"autoname": "ACC-LOAN-.YYYY.-.#####",
"creation": "2019-08-29 17:29:18.176786",
"creation": "2022-01-25 10:30:02.294967",
"doctype": "DocType",
"document_type": "Document",
"editable_grid": 1,
@ -34,6 +34,7 @@
"is_term_loan",
"account_info",
"mode_of_payment",
"disbursement_account",
"payment_account",
"column_break_9",
"loan_account",
@ -356,12 +357,21 @@
"fieldtype": "Date",
"label": "Closure Date",
"read_only": 1
},
{
"fetch_from": "loan_type.disbursement_account",
"fieldname": "disbursement_account",
"fieldtype": "Link",
"label": "Disbursement Account",
"options": "Account",
"read_only": 1,
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2021-10-12 18:10:32.360818",
"modified": "2022-01-25 16:29:16.325501",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan",
@ -391,5 +401,6 @@
"search_fields": "posting_date",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}

View File

@ -10,6 +10,7 @@ from frappe import _
from frappe.utils import add_months, flt, get_last_day, getdate, now_datetime, nowdate
import erpnext
from erpnext.accounts.doctype.journal_entry.journal_entry import get_payment_entry
from erpnext.controllers.accounts_controller import AccountsController
from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts
from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import (
@ -233,17 +234,15 @@ def request_loan_closure(loan, posting_date=None):
loan_type = frappe.get_value('Loan', loan, 'loan_type')
write_off_limit = frappe.get_value('Loan Type', loan_type, 'write_off_amount')
# checking greater than 0 as there may be some minor precision error
if not pending_amount:
frappe.db.set_value('Loan', loan, 'status', 'Loan Closure Requested')
elif pending_amount < write_off_limit:
if pending_amount and abs(pending_amount) < write_off_limit:
# Auto create loan write off and update status as loan closure requested
write_off = make_loan_write_off(loan)
write_off.submit()
frappe.db.set_value('Loan', loan, 'status', 'Loan Closure Requested')
else:
elif pending_amount > 0:
frappe.throw(_("Cannot close loan as there is an outstanding of {0}").format(pending_amount))
frappe.db.set_value('Loan', loan, 'status', 'Loan Closure Requested')
@frappe.whitelist()
def get_loan_application(loan_application):
loan = frappe.get_doc("Loan Application", loan_application)
@ -400,4 +399,39 @@ def add_single_month(date):
if getdate(date) == get_last_day(date):
return get_last_day(add_months(date, 1))
else:
return add_months(date, 1)
return add_months(date, 1)
@frappe.whitelist()
def make_refund_jv(loan, amount=0, reference_number=None, reference_date=None, submit=0):
loan_details = frappe.db.get_value('Loan', loan, ['applicant_type', 'applicant',
'loan_account', 'payment_account', 'posting_date', 'company', 'name',
'total_payment', 'total_principal_paid'], as_dict=1)
loan_details.doctype = 'Loan'
loan_details[loan_details.applicant_type.lower()] = loan_details.applicant
if not amount:
amount = flt(loan_details.total_principal_paid - loan_details.total_payment)
if amount < 0:
frappe.throw(_('No excess amount pending for refund'))
refund_jv = get_payment_entry(loan_details, {
"party_type": loan_details.applicant_type,
"party_account": loan_details.loan_account,
"amount_field_party": 'debit_in_account_currency',
"amount_field_bank": 'credit_in_account_currency',
"amount": amount,
"bank_account": loan_details.payment_account
})
if reference_number:
refund_jv.cheque_no = reference_number
if reference_date:
refund_jv.cheque_date = reference_date
if submit:
refund_jv.submit()
return refund_jv

View File

@ -42,16 +42,17 @@ class TestLoan(unittest.TestCase):
create_loan_type("Personal Loan", 500000, 8.4,
is_term_loan=1,
mode_of_payment='Cash',
disbursement_account='Disbursement Account - _TC',
payment_account='Payment Account - _TC',
loan_account='Loan Account - _TC',
interest_income_account='Interest Income Account - _TC',
penalty_income_account='Penalty Income Account - _TC')
create_loan_type("Stock Loan", 2000000, 13.5, 25, 1, 5, 'Cash', 'Payment Account - _TC', 'Loan Account - _TC',
'Interest Income Account - _TC', 'Penalty Income Account - _TC')
create_loan_type("Stock Loan", 2000000, 13.5, 25, 1, 5, 'Cash', 'Disbursement Account - _TC',
'Payment Account - _TC', 'Loan Account - _TC', 'Interest Income Account - _TC', 'Penalty Income Account - _TC')
create_loan_type("Demand Loan", 2000000, 13.5, 25, 0, 5, 'Cash', 'Payment Account - _TC', 'Loan Account - _TC',
'Interest Income Account - _TC', 'Penalty Income Account - _TC')
create_loan_type("Demand Loan", 2000000, 13.5, 25, 0, 5, 'Cash', 'Disbursement Account - _TC',
'Payment Account - _TC', 'Loan Account - _TC', 'Interest Income Account - _TC', 'Penalty Income Account - _TC')
create_loan_security_type()
create_loan_security()
@ -790,6 +791,18 @@ def create_loan_accounts():
"account_type": "Bank",
}).insert(ignore_permissions=True)
if not frappe.db.exists("Account", "Disbursement Account - _TC"):
frappe.get_doc({
"doctype": "Account",
"company": "_Test Company",
"account_name": "Disbursement Account",
"root_type": "Asset",
"report_type": "Balance Sheet",
"currency": "INR",
"parent_account": "Bank Accounts - _TC",
"account_type": "Bank",
}).insert(ignore_permissions=True)
if not frappe.db.exists("Account", "Interest Income Account - _TC"):
frappe.get_doc({
"doctype": "Account",
@ -815,7 +828,7 @@ def create_loan_accounts():
}).insert(ignore_permissions=True)
def create_loan_type(loan_name, maximum_loan_amount, rate_of_interest, penalty_interest_rate=None, is_term_loan=None, grace_period_in_days=None,
mode_of_payment=None, payment_account=None, loan_account=None, interest_income_account=None, penalty_income_account=None,
mode_of_payment=None, disbursement_account=None, payment_account=None, loan_account=None, interest_income_account=None, penalty_income_account=None,
repayment_method=None, repayment_periods=None):
if not frappe.db.exists("Loan Type", loan_name):
@ -829,6 +842,7 @@ def create_loan_type(loan_name, maximum_loan_amount, rate_of_interest, penalty_i
"penalty_interest_rate": penalty_interest_rate,
"grace_period_in_days": grace_period_in_days,
"mode_of_payment": mode_of_payment,
"disbursement_account": disbursement_account,
"payment_account": payment_account,
"loan_account": loan_account,
"interest_income_account": interest_income_account,

View File

@ -122,7 +122,7 @@ class LoanDisbursement(AccountsController):
gle_map.append(
self.get_gl_dict({
"account": loan_details.loan_account,
"against": loan_details.payment_account,
"against": loan_details.disbursement_account,
"debit": self.disbursed_amount,
"debit_in_account_currency": self.disbursed_amount,
"against_voucher_type": "Loan",
@ -137,7 +137,7 @@ class LoanDisbursement(AccountsController):
gle_map.append(
self.get_gl_dict({
"account": loan_details.payment_account,
"account": loan_details.disbursement_account,
"against": loan_details.loan_account,
"credit": self.disbursed_amount,
"credit_in_account_currency": self.disbursed_amount,

View File

@ -15,7 +15,7 @@ frappe.ui.form.on('Loan Type', {
});
});
$.each(["payment_account", "loan_account"], function (i, field) {
$.each(["payment_account", "loan_account", "disbursement_account"], function (i, field) {
frm.set_query(field, function () {
return {
"filters": {

View File

@ -19,9 +19,10 @@
"description",
"account_details_section",
"mode_of_payment",
"disbursement_account",
"payment_account",
"loan_account",
"column_break_12",
"loan_account",
"interest_income_account",
"penalty_income_account",
"amended_from"
@ -79,7 +80,7 @@
{
"fieldname": "payment_account",
"fieldtype": "Link",
"label": "Payment Account",
"label": "Repayment Account",
"options": "Account",
"reqd": 1
},
@ -149,15 +150,23 @@
"fieldtype": "Currency",
"label": "Auto Write Off Amount ",
"options": "Company:company:default_currency"
},
{
"fieldname": "disbursement_account",
"fieldtype": "Link",
"label": "Disbursement Account",
"options": "Account",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2021-04-19 18:10:57.368490",
"modified": "2022-01-25 16:23:57.009349",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan Type",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
@ -181,5 +190,6 @@
}
],
"sort_field": "modified",
"sort_order": "DESC"
"sort_order": "DESC",
"states": []
}

View File

@ -325,3 +325,4 @@ erpnext.patches.v14_0.set_payroll_cost_centers
erpnext.patches.v13_0.agriculture_deprecation_warning
erpnext.patches.v14_0.delete_agriculture_doctypes
erpnext.patches.v13_0.update_exchange_rate_settings
erpnext.patches.v13_0.update_disbursement_account

View File

@ -0,0 +1,22 @@
import frappe
def execute():
frappe.reload_doc("loan_management", "doctype", "loan_type")
frappe.reload_doc("loan_management", "doctype", "loan")
loan_type = frappe.qb.DocType("Loan Type")
loan = frappe.qb.DocType("Loan")
frappe.qb.update(
loan_type
).set(
loan_type.disbursement_account, loan_type.payment_account
).run()
frappe.qb.update(
loan
).set(
loan.disbursement_account, loan.payment_account
).run()