feat: Refund entry against loans
This commit is contained in:
parent
388293dbea
commit
c68c70f8bc
@ -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() {
|
||||
|
@ -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
|
||||
}
|
@ -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
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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": {
|
||||
|
@ -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": []
|
||||
}
|
@ -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
|
||||
|
22
erpnext/patches/v13_0/update_disbursement_account.py
Normal file
22
erpnext/patches/v13_0/update_disbursement_account.py
Normal 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()
|
Loading…
x
Reference in New Issue
Block a user