feat: add adjustment amount to loan
- fix: bugs in loan balance adjustment
diff --git a/erpnext/loan_management/doctype/loan/loan.json b/erpnext/loan_management/doctype/loan/loan.json
index 0797084..f4ab7ed 100644
--- a/erpnext/loan_management/doctype/loan/loan.json
+++ b/erpnext/loan_management/doctype/loan/loan.json
@@ -49,6 +49,7 @@
"total_principal_paid",
"written_off_amount",
"refund_amount",
+ "adjustment_amount",
"column_break_19",
"total_interest_payable",
"total_amount_paid",
@@ -388,12 +389,20 @@
"no_copy": 1,
"options": "Company:company:default_currency",
"read_only": 1
- }
+ },
+ {
+ "fieldname": "adjustment_amount",
+ "fieldtype": "Currency",
+ "label": "Adjustment amount",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "read_only": 1
+ }
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2022-06-24 16:17:57.018272",
+ "modified": "2022-06-29 13:17:57.018272",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Loan",
diff --git a/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.json b/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.json
index 5fb25de..35be555 100644
--- a/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.json
+++ b/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.json
@@ -115,12 +115,13 @@
"read_only": 1
},
{
+ "fetch_from": "loan.payment_account",
"fieldname": "adjustment_account",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Adjustment Account",
"options": "Account",
- "reqd": 1
+ "read_only": 1
},
{
"fieldname": "amount",
@@ -130,6 +131,14 @@
"reqd": 1
},
{
+ "fetch_from": "loan.loan_account",
+ "fieldname": "loan_account",
+ "fieldtype": "Link",
+ "label": "Loan Account",
+ "options": "Account",
+ "read_only": 1
+ },
+ {
"fieldname": "adjustment_type",
"fieldtype": "Select",
"label": "Adjustment Type",
diff --git a/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.py b/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.py
index 8f98ce6..4b57060 100644
--- a/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.py
+++ b/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.py
@@ -1,132 +1,140 @@
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
-# import frappe
-from frappe.model.document import Document
-
-class LoanBalanceAdjustment(Document):
- """
- Add credit/debit adjustments to loan ledger.
- """
- def validate(self):
- self.set_missing_values()
-
- def on_submit(self):
- self.set_status_and_amounts()
- self.make_gl_entries()
-
- def on_cancel(self):
- self.set_status_and_amounts(cancel=1)
- self.make_gl_entries(cancel=1)
- self.ignore_linked_doctypes = ["GL Entry"]
-
- def set_missing_values(self):
- if not self.posting_date:
- self.posting_date = nowdate()
-
- if not self.cost_center:
- self.cost_center = erpnext.get_default_cost_center(self.company)
-
- if not self.posting_date:
- self.posting_date = self.posting_date or nowdate()
-
- def set_status_and_amounts(self, cancel=0):
- loan_details = frappe.get_all(
- "Loan",
- fields=[
- "loan_amount",
- "disbursed_amount",
- "total_payment",
- "total_principal_paid",
- "total_interest_payable",
- "status",
- "is_term_loan",
- "is_secured_loan",
- ],
- filters={"name": self.against_loan},
- )[0]
-
- if cancel:
- disbursed_amount = self.get_values_on_cancel(loan_details)
- else:
- disbursed_amount = self.get_values_on_submit(loan_details)
-
- frappe.db.set_value(
- "Loan",
- self.against_loan,
- {
- "disbursed_amount": disbursed_amount,
- },
- )
-
- def get_values_on_cancel(self, loan_details):
- if self.adjustment_type == "Credit Adjustment":
- disbursed_amount = loan_details.disbursed_amount - self.amount
- elif self.adjustment_type == "Debit Adjustment":
- disbursed_amount = loan_details.disbursed_amount + self.amount
-
- return disbursed_amount
-
- def get_values_on_submit(self, loan_details):
- if self.adjustment_type == "Credit":
- disbursed_amount = loan_details.disbursed_amount + self.amount
- elif self.adjustment_type == "Debit":
- disbursed_amount = loan_details.disbursed_amount - self.amount
-
- total_payment = loan_details.total_payment
-
- if loan_details.status in ("Disbursed", "Partially Disbursed") and not loan_details.is_term_loan:
- process_loan_interest_accrual_for_demand_loans(
- posting_date=add_days(self.posting_date, -1),
- loan=self.against_loan,
- accrual_type=self.adjustment_type,
- )
-
- return disbursed_amount
-
- def make_gl_entries(self, cancel=0, adv_adj=0):
- gle_map = []
-
- loan_entry = {
- "account": self.loan_account,
- "against": self.adjustment_account,
- "against_voucher_type": "Loan",
- "against_voucher": self.against_loan,
- "remarks": _("{} against loan:".format(self.adjustment_type)) \
- + self.against_loan,
- "cost_center": self.cost_center,
- "party_type": self.applicant_type,
- "party": self.applicant,
- "posting_date": self.posting_date,
- }
- company_entry = {
- "account": self.adjustment_account,
- "against": self.loan_account,
- "against_voucher_type": "Loan",
- "against_voucher": self.against_loan,
- "remarks": _("{} against loan:".format(self.adjustment_type)) \
- + self.against_loan,
- "cost_center": self.cost_center,
- "posting_date": self.posting_date,
- }
- if self.adjustment_type == "Credit Adjustment":
- loan_entry["credit"] = self.amount
- loan_entry["credit_in_account_currency"] = self.amount
-
- company_entry["debit"] = self.amount
- company_entry["debit_in_account_currency"] = self.amount
-
- elif self.adjustment_type == "Debit Adjustment":
- loan_entry["debit"] = self.amount
- loan_entry["debit_in_account_currency"] = self.amount
-
- company_entry["credit"] = self.amount
- company_entry["credit_in_account_currency"] = self.amount
+import frappe
+import erpnext
+from frappe import _
+from frappe.utils import nowdate, add_days
+from erpnext.controllers.accounts_controller import AccountsController
+from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (
+ process_loan_interest_accrual_for_demand_loans,
+)
+from erpnext.accounts.general_ledger import make_gl_entries
- gle_map.append(self.get_gl_dict(loan_entry))
+class LoanBalanceAdjustment(AccountsController):
+ """
+ Add credit/debit adjustments to loan ledger.
+ """
- gle_map.append(self.get_gl_dict(company_entry))
+ def validate(self):
+ if self.amount == 0:
+ frappe.throw(_("Amount cannot be zero"))
+ if self.amount < 0:
+ frappe.throw(_("Amount cannot be negative"))
+ self.set_missing_values()
- if gle_map:
- make_gl_entries(gle_map, cancel=cancel, adv_adj=adv_adj)
+ def on_submit(self):
+ self.set_status_and_amounts()
+ self.make_gl_entries()
+
+ def on_cancel(self):
+ self.set_status_and_amounts(cancel=1)
+ self.make_gl_entries(cancel=1)
+ self.ignore_linked_doctypes = ["GL Entry", "Payment Ledger Entry"]
+
+ def set_missing_values(self):
+ if not self.posting_date:
+ self.posting_date = nowdate()
+
+ if not self.cost_center:
+ self.cost_center = erpnext.get_default_cost_center(self.company)
+
+ def set_status_and_amounts(self, cancel=0):
+ loan_details = frappe.get_all(
+ "Loan",
+ fields=[
+ "loan_amount",
+ "adjustment_amount",
+ "total_payment",
+ "total_principal_paid",
+ "total_interest_payable",
+ "status",
+ "is_term_loan",
+ "is_secured_loan",
+ ],
+ filters={"name": self.loan},
+ )[0]
+
+ if cancel:
+ adjustment_amount = self.get_values_on_cancel(loan_details)
+ else:
+ adjustment_amount = self.get_values_on_submit(loan_details)
+
+ frappe.db.set_value(
+ "Loan",
+ self.loan,
+ {
+ "adjustment_amount": adjustment_amount,
+ },
+ )
+
+ def get_values_on_cancel(self, loan_details):
+ if self.adjustment_type == "Credit Adjustment":
+ adjustment_amount = loan_details.adjustment_amount - self.amount
+ elif self.adjustment_type == "Debit Adjustment":
+ adjustment_amount = loan_details.adjustment_amount + self.amount
+
+ return adjustment_amount
+
+ def get_values_on_submit(self, loan_details):
+ if self.adjustment_type == "Credit Adjustment":
+ adjustment_amount = loan_details.adjustment_amount + self.amount
+ elif self.adjustment_type == "Debit Adjustment":
+ adjustment_amount = loan_details.adjustment_amount - self.amount
+
+ if (
+ loan_details.status in ("Disbursed", "Partially Disbursed")
+ and not loan_details.is_term_loan
+ ):
+ process_loan_interest_accrual_for_demand_loans(
+ posting_date=add_days(self.posting_date, -1),
+ loan=self.loan,
+ accrual_type=self.adjustment_type,
+ )
+
+ return adjustment_amount
+
+ def make_gl_entries(self, cancel=0, adv_adj=0):
+ gle_map = []
+
+ loan_entry = {
+ "account": self.loan_account,
+ "against": self.adjustment_account,
+ "against_voucher_type": "Loan",
+ "against_voucher": self.loan,
+ "remarks": _("{} against loan:".format(self.adjustment_type)) + self.loan,
+ "cost_center": self.cost_center,
+ "party_type": self.applicant_type,
+ "party": self.applicant,
+ "posting_date": self.posting_date,
+ }
+ company_entry = {
+ "account": self.adjustment_account,
+ "against": self.loan_account,
+ "against_voucher_type": "Loan",
+ "against_voucher": self.loan,
+ "remarks": _("{} against loan:".format(self.adjustment_type)) + self.loan,
+ "cost_center": self.cost_center,
+ "posting_date": self.posting_date,
+ }
+ if self.adjustment_type == "Credit Adjustment":
+ loan_entry["credit"] = self.amount
+ loan_entry["credit_in_account_currency"] = self.amount
+
+ company_entry["debit"] = self.amount
+ company_entry["debit_in_account_currency"] = self.amount
+
+ elif self.adjustment_type == "Debit Adjustment":
+ loan_entry["debit"] = self.amount
+ loan_entry["debit_in_account_currency"] = self.amount
+
+ company_entry["credit"] = self.amount
+ company_entry["credit_in_account_currency"] = self.amount
+
+ gle_map.append(self.get_gl_dict(loan_entry))
+
+ gle_map.append(self.get_gl_dict(company_entry))
+
+ if gle_map:
+ make_gl_entries(gle_map, cancel=cancel, adv_adj=adv_adj, merge_entries=False)
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index 51f40d9..32b257b 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -623,6 +623,7 @@
if loan.status in ("Disbursed", "Closed") or loan.disbursed_amount >= loan.loan_amount:
pending_principal_amount = (
flt(loan.total_payment)
+ + flt(loan.adjustment_amount)
- flt(loan.total_principal_paid)
- flt(loan.total_interest_payable)
- flt(loan.written_off_amount)
@@ -630,6 +631,7 @@
else:
pending_principal_amount = (
flt(loan.disbursed_amount)
+ + flt(loan.adjustment_amount)
- flt(loan.total_principal_paid)
- flt(loan.total_interest_payable)
- flt(loan.written_off_amount)
diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json
index 828df2e..7fc4736 100644
--- a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json
+++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json
@@ -54,17 +54,18 @@
"fieldtype": "Select",
"hidden": 1,
"label": "Accrual Type",
- "options": "Regular\nRepayment\nDisbursement",
+ "options": "Regular\nRepayment\nDisbursement\nCredit Adjustment\nDebit Adjustment\nRefund",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
- "modified": "2020-11-06 13:28:51.478909",
+ "modified": "2022-06-29 11:19:33.203088",
"modified_by": "Administrator",
"module": "Loan Management",
"name": "Process Loan Interest Accrual",
+ "naming_rule": "Expression (old style)",
"owner": "Administrator",
"permissions": [
{
@@ -98,5 +99,6 @@
],
"sort_field": "modified",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
}
\ No newline at end of file