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