Merge pull request #31543 from lebmatter/loan_balance_adjustments

feat: Loan balance adjustment doctypes
diff --git a/erpnext/loan_management/doctype/loan/loan.json b/erpnext/loan_management/doctype/loan/loan.json
index ef78a64..fb5f133 100644
--- a/erpnext/loan_management/doctype/loan/loan.json
+++ b/erpnext/loan_management/doctype/loan/loan.json
@@ -48,6 +48,10 @@
   "total_payment",
   "total_principal_paid",
   "written_off_amount",
+  "refund_amount",
+  "debit_adjustment_amount",
+  "credit_adjustment_amount",
+  "is_npa",
   "column_break_19",
   "total_interest_payable",
   "total_amount_paid",
@@ -379,12 +383,39 @@
    "fieldtype": "Link",
    "label": "Cost Center",
    "options": "Cost Center"
+  },
+  {
+   "fieldname": "refund_amount",
+   "fieldtype": "Currency",
+   "label": "Refund amount",
+   "no_copy": 1,
+   "options": "Company:company:default_currency",
+   "read_only": 1
+  },
+  {
+   "fieldname": "credit_adjustment_amount",
+   "fieldtype": "Currency",
+   "label": "Credit Adjustment Amount",
+   "options": "Company:company:default_currency"
+  },
+  {
+   "fieldname": "debit_adjustment_amount",
+   "fieldtype": "Currency",
+   "label": "Debit Adjustment Amount",
+   "options": "Company:company:default_currency"
+  },
+  {
+   "default": "0",
+   "description": "Mark Loan as a Nonperforming asset",
+   "fieldname": "is_npa",
+   "fieldtype": "Check",
+   "label": "Is NPA"
   }
  ],
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-03-10 11:50:31.957360",
+ "modified": "2022-06-30 12:04:13.728880",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan",
diff --git a/erpnext/loan_management/doctype/loan_balance_adjustment/__init__.py b/erpnext/loan_management/doctype/loan_balance_adjustment/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_balance_adjustment/__init__.py
diff --git a/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.js b/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.js
new file mode 100644
index 0000000..8aec63a
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Loan Balance Adjustment', {
+	// refresh: function(frm) {
+
+	// }
+});
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
new file mode 100644
index 0000000..80c3389
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.json
@@ -0,0 +1,189 @@
+{
+ "actions": [],
+ "autoname": "LM-ADJ-.#####",
+ "creation": "2022-06-28 14:48:47.736269",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "loan",
+  "applicant_type",
+  "applicant",
+  "column_break_3",
+  "company",
+  "posting_date",
+  "accounting_dimensions_section",
+  "cost_center",
+  "section_break_9",
+  "adjustment_account",
+  "column_break_11",
+  "adjustment_type",
+  "amount",
+  "reference_number",
+  "remarks",
+  "amended_from"
+ ],
+ "fields": [
+  {
+   "fieldname": "loan",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Loan",
+   "options": "Loan",
+   "reqd": 1
+  },
+  {
+   "fetch_from": "loan.applicant_type",
+   "fieldname": "applicant_type",
+   "fieldtype": "Select",
+   "label": "Applicant Type",
+   "options": "Employee\nMember\nCustomer",
+   "read_only": 1
+  },
+  {
+   "fetch_from": "loan.applicant",
+   "fieldname": "applicant",
+   "fieldtype": "Dynamic Link",
+   "label": "Applicant ",
+   "options": "applicant_type",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_3",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fetch_from": "loan.company",
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Company",
+   "options": "Company",
+   "read_only": 1,
+   "reqd": 1
+  },
+  {
+   "default": "Today",
+   "fieldname": "posting_date",
+   "fieldtype": "Date",
+   "in_list_view": 1,
+   "label": "Posting Date",
+   "reqd": 1
+  },
+  {
+   "collapsible": 1,
+   "fieldname": "accounting_dimensions_section",
+   "fieldtype": "Section Break",
+   "label": "Accounting Dimensions"
+  },
+  {
+   "fieldname": "cost_center",
+   "fieldtype": "Link",
+   "label": "Cost Center",
+   "options": "Cost Center"
+  },
+  {
+   "fieldname": "section_break_9",
+   "fieldtype": "Section Break",
+   "label": "Adjustment Details"
+  },
+  {
+   "fieldname": "column_break_11",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "reference_number",
+   "fieldtype": "Data",
+   "label": "Reference Number"
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Loan Balance Adjustment",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Loan Balance Adjustment",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "adjustment_account",
+   "fieldtype": "Link",
+   "label": "Adjustment Account",
+   "options": "Account",
+   "reqd": 1
+  },
+  {
+   "fieldname": "amount",
+   "fieldtype": "Currency",
+   "label": "Amount",
+   "options": "Company:company:default_currency",
+   "reqd": 1
+  },
+  {
+   "fieldname": "adjustment_type",
+   "fieldtype": "Select",
+   "label": "Adjustment Type",
+   "options": "Credit Adjustment\nDebit Adjustment",
+   "reqd": 1
+  },
+  {
+   "fieldname": "remarks",
+   "fieldtype": "Data",
+   "label": "Remarks"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2022-07-08 16:48:54.480066",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Loan Balance Adjustment",
+ "naming_rule": "Expression (old style)",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Loan Manager",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..0a576d6
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_balance_adjustment/loan_balance_adjustment.py
@@ -0,0 +1,143 @@
+# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+from frappe.utils import add_days, nowdate
+
+import erpnext
+from erpnext.accounts.general_ledger import make_gl_entries
+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,
+)
+
+
+class LoanBalanceAdjustment(AccountsController):
+	"""
+	Add credit/debit adjustments to loan ledger.
+	"""
+
+	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()
+
+	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.db.get_value(
+			"Loan",
+			self.loan,
+			[
+				"loan_amount",
+				"credit_adjustment_amount",
+				"debit_adjustment_amount",
+				"total_payment",
+				"total_principal_paid",
+				"total_interest_payable",
+				"status",
+				"is_term_loan",
+				"is_secured_loan",
+			],
+			as_dict=1,
+		)
+
+		if cancel:
+			adjustment_amount = self.get_values_on_cancel(loan_details)
+		else:
+			adjustment_amount = self.get_values_on_submit(loan_details)
+
+		if self.adjustment_type == "Credit Adjustment":
+			adj_field = "credit_adjustment_amount"
+		elif self.adjustment_type == "Debit Adjustment":
+			adj_field = "debit_adjustment_amount"
+
+		frappe.db.set_value("Loan", self.loan, {adj_field: adjustment_amount})
+
+	def get_values_on_cancel(self, loan_details):
+		if self.adjustment_type == "Credit Adjustment":
+			adjustment_amount = loan_details.credit_adjustment_amount - self.amount
+		elif self.adjustment_type == "Debit Adjustment":
+			adjustment_amount = loan_details.debit_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.credit_adjustment_amount + self.amount
+		elif self.adjustment_type == "Debit Adjustment":
+			adjustment_amount = loan_details.debit_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_account = frappe.db.get_value("Loan", self.loan, "loan_account")
+		remarks = "{} against loan {}".format(self.adjustment_type.capitalize(), self.loan)
+		if self.reference_number:
+			remarks += "with reference no. {}".format(self.reference_number)
+
+		loan_entry = {
+			"account": loan_account,
+			"against": self.adjustment_account,
+			"against_voucher_type": "Loan",
+			"against_voucher": self.loan,
+			"remarks": _(remarks),
+			"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": loan_account,
+			"against_voucher_type": "Loan",
+			"against_voucher": self.loan,
+			"remarks": _(remarks),
+			"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_balance_adjustment/test_loan_balance_adjustment.py b/erpnext/loan_management/doctype/loan_balance_adjustment/test_loan_balance_adjustment.py
new file mode 100644
index 0000000..7658d7b
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_balance_adjustment/test_loan_balance_adjustment.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+from frappe.tests.utils import FrappeTestCase
+
+
+class TestLoanBalanceAdjustment(FrappeTestCase):
+	pass
diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json
index 30e2328..08dc98c 100644
--- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json
+++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json
@@ -35,12 +35,15 @@
   {
    "fieldname": "loan",
    "fieldtype": "Link",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
    "label": "Loan",
    "options": "Loan"
   },
   {
    "fieldname": "posting_date",
    "fieldtype": "Date",
+   "in_list_view": 1,
    "label": "Posting Date"
   },
   {
@@ -75,6 +78,8 @@
    "fetch_from": "loan.applicant",
    "fieldname": "applicant",
    "fieldtype": "Dynamic Link",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
    "label": "Applicant",
    "options": "applicant_type"
   },
@@ -158,8 +163,11 @@
   {
    "fieldname": "accrual_type",
    "fieldtype": "Select",
+   "in_filter": 1,
+   "in_list_view": 1,
+   "in_standard_filter": 1,
    "label": "Accrual Type",
-   "options": "Regular\nRepayment\nDisbursement"
+   "options": "Regular\nRepayment\nDisbursement\nCredit Adjustment\nDebit Adjustment\nRefund"
   },
   {
    "fieldname": "penalty_amount",
@@ -185,10 +193,11 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2021-04-19 18:26:38.871889",
+ "modified": "2022-06-30 11:51:31.911794",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Interest Accrual",
+ "naming_rule": "Expression (old style)",
  "owner": "Administrator",
  "permissions": [
   {
@@ -225,5 +234,6 @@
  "quick_entry": 1,
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/loan_management/doctype/loan_refund/__init__.py b/erpnext/loan_management/doctype/loan_refund/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_refund/__init__.py
diff --git a/erpnext/loan_management/doctype/loan_refund/loan_refund.js b/erpnext/loan_management/doctype/loan_refund/loan_refund.js
new file mode 100644
index 0000000..f108bf7
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_refund/loan_refund.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Loan Refund', {
+	// refresh: function(frm) {
+
+	// }
+});
diff --git a/erpnext/loan_management/doctype/loan_refund/loan_refund.json b/erpnext/loan_management/doctype/loan_refund/loan_refund.json
new file mode 100644
index 0000000..f78e55e
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_refund/loan_refund.json
@@ -0,0 +1,176 @@
+{
+ "actions": [],
+ "autoname": "LM-RF-.#####",
+ "creation": "2022-06-24 15:51:03.165498",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "loan",
+  "applicant_type",
+  "applicant",
+  "column_break_3",
+  "company",
+  "posting_date",
+  "accounting_dimensions_section",
+  "cost_center",
+  "section_break_9",
+  "refund_account",
+  "column_break_11",
+  "refund_amount",
+  "reference_number",
+  "amended_from"
+ ],
+ "fields": [
+  {
+   "fieldname": "loan",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Loan",
+   "options": "Loan",
+   "reqd": 1
+  },
+  {
+   "fetch_from": "loan.applicant_type",
+   "fieldname": "applicant_type",
+   "fieldtype": "Select",
+   "label": "Applicant Type",
+   "options": "Employee\nMember\nCustomer",
+   "read_only": 1
+  },
+  {
+   "fetch_from": "loan.applicant",
+   "fieldname": "applicant",
+   "fieldtype": "Dynamic Link",
+   "label": "Applicant ",
+   "options": "applicant_type",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_3",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fetch_from": "loan.company",
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Company",
+   "options": "Company",
+   "read_only": 1,
+   "reqd": 1
+  },
+  {
+   "default": "Today",
+   "fieldname": "posting_date",
+   "fieldtype": "Date",
+   "in_list_view": 1,
+   "label": "Posting Date",
+   "reqd": 1
+  },
+  {
+   "collapsible": 1,
+   "fieldname": "accounting_dimensions_section",
+   "fieldtype": "Section Break",
+   "label": "Accounting Dimensions"
+  },
+  {
+   "fieldname": "cost_center",
+   "fieldtype": "Link",
+   "label": "Cost Center",
+   "options": "Cost Center"
+  },
+  {
+   "fieldname": "section_break_9",
+   "fieldtype": "Section Break",
+   "label": "Refund Details"
+  },
+  {
+   "fieldname": "refund_account",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Refund Account",
+   "options": "Account",
+   "reqd": 1
+  },
+  {
+   "fieldname": "column_break_11",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "refund_amount",
+   "fieldtype": "Currency",
+   "label": "Refund Amount",
+   "options": "Company:company:default_currency",
+   "reqd": 1
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Loan Refund",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Loan Refund",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "reference_number",
+   "fieldtype": "Data",
+   "label": "Reference Number"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2022-06-24 16:13:48.793486",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Loan Refund",
+ "naming_rule": "Expression (old style)",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Loan Manager",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/doctype/loan_refund/loan_refund.py b/erpnext/loan_management/doctype/loan_refund/loan_refund.py
new file mode 100644
index 0000000..d7ab54c
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_refund/loan_refund.py
@@ -0,0 +1,97 @@
+# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+from frappe.utils import getdate
+
+import erpnext
+from erpnext.accounts.general_ledger import make_gl_entries
+from erpnext.controllers.accounts_controller import AccountsController
+from erpnext.loan_management.doctype.loan_repayment.loan_repayment import (
+	get_pending_principal_amount,
+)
+
+
+class LoanRefund(AccountsController):
+	"""
+	Add refund if total repayment is more than that is owed.
+	"""
+
+	def validate(self):
+		self.set_missing_values()
+		self.validate_refund_amount()
+
+	def set_missing_values(self):
+		if not self.cost_center:
+			self.cost_center = erpnext.get_default_cost_center(self.company)
+
+	def validate_refund_amount(self):
+		loan = frappe.get_doc("Loan", self.loan)
+		pending_amount = get_pending_principal_amount(loan)
+		if pending_amount >= 0:
+			frappe.throw(_("No excess amount to refund."))
+		else:
+			excess_amount = pending_amount * -1
+
+		if self.refund_amount > excess_amount:
+			frappe.throw(_("Refund amount cannot be greater than excess amount {0}").format(excess_amount))
+
+	def on_submit(self):
+		self.update_outstanding_amount()
+		self.make_gl_entries()
+
+	def on_cancel(self):
+		self.update_outstanding_amount(cancel=1)
+		self.ignore_linked_doctypes = ["GL Entry", "Payment Ledger Entry"]
+		self.make_gl_entries(cancel=1)
+
+	def update_outstanding_amount(self, cancel=0):
+		refund_amount = frappe.db.get_value("Loan", self.loan, "refund_amount")
+
+		if cancel:
+			refund_amount -= self.refund_amount
+		else:
+			refund_amount += self.refund_amount
+
+		frappe.db.set_value("Loan", self.loan, "refund_amount", refund_amount)
+
+	def make_gl_entries(self, cancel=0):
+		gl_entries = []
+		loan_details = frappe.get_doc("Loan", self.loan)
+
+		gl_entries.append(
+			self.get_gl_dict(
+				{
+					"account": self.refund_account,
+					"against": loan_details.loan_account,
+					"credit": self.refund_amount,
+					"credit_in_account_currency": self.refund_amount,
+					"against_voucher_type": "Loan",
+					"against_voucher": self.loan,
+					"remarks": _("Against Loan:") + self.loan,
+					"cost_center": self.cost_center,
+					"posting_date": getdate(self.posting_date),
+				}
+			)
+		)
+
+		gl_entries.append(
+			self.get_gl_dict(
+				{
+					"account": loan_details.loan_account,
+					"party_type": loan_details.applicant_type,
+					"party": loan_details.applicant,
+					"against": self.refund_account,
+					"debit": self.refund_amount,
+					"debit_in_account_currency": self.refund_amount,
+					"against_voucher_type": "Loan",
+					"against_voucher": self.loan,
+					"remarks": _("Against Loan:") + self.loan,
+					"cost_center": self.cost_center,
+					"posting_date": getdate(self.posting_date),
+				}
+			)
+		)
+
+		make_gl_entries(gl_entries, cancel=cancel, merge_entries=False)
diff --git a/erpnext/loan_management/doctype/loan_refund/test_loan_refund.py b/erpnext/loan_management/doctype/loan_refund/test_loan_refund.py
new file mode 100644
index 0000000..de2f9e1
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_refund/test_loan_refund.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+from frappe.tests.utils import FrappeTestCase
+
+
+class TestLoanRefund(FrappeTestCase):
+	pass
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index 51f40d9..e7d6ca8 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -386,15 +386,19 @@
 
 	def make_gl_entries(self, cancel=0, adv_adj=0):
 		gle_map = []
-
 		if self.shortfall_amount and self.amount_paid > self.shortfall_amount:
-			remarks = _("Shortfall Repayment of {0}.<br>Repayment against Loan: {1}").format(
+			remarks = "Shortfall repayment of {0}.<br>Repayment against loan {1}".format(
 				self.shortfall_amount, self.against_loan
 			)
 		elif self.shortfall_amount:
-			remarks = _("Shortfall Repayment of {0}").format(self.shortfall_amount)
+			remarks = "Shortfall repayment of {0} against loan {1}".format(
+				self.shortfall_amount, self.against_loan
+			)
 		else:
-			remarks = _("Repayment against Loan:") + " " + self.against_loan
+			remarks = "Repayment against loan " + self.against_loan
+
+		if self.reference_number:
+			remarks += "with reference no. {}".format(self.reference_number)
 
 		if self.repay_from_salary:
 			payment_account = self.payroll_payable_account
@@ -445,7 +449,7 @@
 					"debit_in_account_currency": self.amount_paid,
 					"against_voucher_type": "Loan",
 					"against_voucher": self.against_loan,
-					"remarks": remarks,
+					"remarks": _(remarks),
 					"cost_center": self.cost_center,
 					"posting_date": getdate(self.posting_date),
 				}
@@ -463,7 +467,7 @@
 					"credit_in_account_currency": self.amount_paid,
 					"against_voucher_type": "Loan",
 					"against_voucher": self.against_loan,
-					"remarks": remarks,
+					"remarks": _(remarks),
 					"cost_center": self.cost_center,
 					"posting_date": getdate(self.posting_date),
 				}
@@ -623,16 +627,22 @@
 	if loan.status in ("Disbursed", "Closed") or loan.disbursed_amount >= loan.loan_amount:
 		pending_principal_amount = (
 			flt(loan.total_payment)
+			+ flt(loan.debit_adjustment_amount)
+			- flt(loan.credit_adjustment_amount)
 			- flt(loan.total_principal_paid)
 			- flt(loan.total_interest_payable)
 			- flt(loan.written_off_amount)
+			+ flt(loan.refund_amount)
 		)
 	else:
 		pending_principal_amount = (
 			flt(loan.disbursed_amount)
+			+ flt(loan.debit_adjustment_amount)
+			- flt(loan.credit_adjustment_amount)
 			- flt(loan.total_principal_paid)
 			- flt(loan.total_interest_payable)
 			- flt(loan.written_off_amount)
+			+ flt(loan.refund_amount)
 		)
 
 	return pending_principal_amount
diff --git a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.json b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.json
index 99b5c72..d4007cb 100644
--- a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.json
+++ b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.json
@@ -7,6 +7,8 @@
  "engine": "InnoDB",
  "field_order": [
   "loan",
+  "applicant_type",
+  "applicant",
   "status",
   "column_break_3",
   "shortfall_time",
@@ -23,6 +25,8 @@
   {
    "fieldname": "loan",
    "fieldtype": "Link",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
    "label": "Loan ",
    "options": "Loan",
    "read_only": 1
@@ -91,17 +95,35 @@
   {
    "fieldname": "shortfall_percentage",
    "fieldtype": "Percent",
+   "in_list_view": 1,
    "label": "Shortfall Percentage",
    "read_only": 1
+  },
+  {
+   "fetch_from": "loan.applicant_type",
+   "fieldname": "applicant_type",
+   "fieldtype": "Select",
+   "label": "Applicant Type",
+   "options": "Employee\nMember\nCustomer"
+  },
+  {
+   "fetch_from": "loan.applicant",
+   "fieldname": "applicant",
+   "fieldtype": "Dynamic Link",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
+   "label": "Applicant",
+   "options": "applicant_type"
   }
  ],
  "in_create": 1,
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2021-04-01 08:13:43.263772",
+ "modified": "2022-06-30 11:57:09.378089",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Security Shortfall",
+ "naming_rule": "Expression (old style)",
  "owner": "Administrator",
  "permissions": [
   {
@@ -132,5 +154,6 @@
  "quick_entry": 1,
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "track_changes": 1
 }
\ No newline at end of file
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