Merge pull request #29865 from deepeshgarg007/loan_bank_reco

feat: Bank Reconciliation for loan documents
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
index 4211bd0..f3351dd 100644
--- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
@@ -7,6 +7,7 @@
 import frappe
 from frappe import _
 from frappe.model.document import Document
+from frappe.query_builder.custom import ConstantColumn
 from frappe.utils import flt
 
 from erpnext import get_company_currency
@@ -275,6 +276,10 @@
 		}
 
 	matching_vouchers = []
+
+	matching_vouchers.extend(get_loan_vouchers(bank_account, transaction,
+		document_types, filters))
+
 	for query in subquery:
 		matching_vouchers.extend(
 			frappe.db.sql(query, filters,)
@@ -311,6 +316,114 @@
 
 	return queries
 
+def get_loan_vouchers(bank_account, transaction, document_types, filters):
+	vouchers = []
+	amount_condition = True if "exact_match" in document_types else False
+
+	if transaction.withdrawal > 0 and "loan_disbursement" in document_types:
+		vouchers.extend(get_ld_matching_query(bank_account, amount_condition, filters))
+
+	if transaction.deposit > 0 and "loan_repayment" in document_types:
+		vouchers.extend(get_lr_matching_query(bank_account, amount_condition, filters))
+
+	return vouchers
+
+def get_ld_matching_query(bank_account, amount_condition, filters):
+	loan_disbursement = frappe.qb.DocType("Loan Disbursement")
+	matching_reference = loan_disbursement.reference_number == filters.get("reference_number")
+	matching_party = loan_disbursement.applicant_type == filters.get("party_type") and \
+			loan_disbursement.applicant == filters.get("party")
+
+	rank = (
+			frappe.qb.terms.Case()
+			.when(matching_reference, 1)
+			.else_(0)
+		)
+
+	rank1 = (
+			frappe.qb.terms.Case()
+			.when(matching_party, 1)
+			.else_(0)
+		)
+
+	query = frappe.qb.from_(loan_disbursement).select(
+		rank + rank1 + 1,
+		ConstantColumn("Loan Disbursement").as_("doctype"),
+		loan_disbursement.name,
+		loan_disbursement.disbursed_amount,
+		loan_disbursement.reference_number,
+		loan_disbursement.reference_date,
+		loan_disbursement.applicant_type,
+		loan_disbursement.disbursement_date
+	).where(
+		loan_disbursement.docstatus == 1
+	).where(
+		loan_disbursement.clearance_date.isnull()
+	).where(
+		loan_disbursement.disbursement_account == bank_account
+	)
+
+	if amount_condition:
+		query.where(
+			loan_disbursement.disbursed_amount == filters.get('amount')
+		)
+	else:
+		query.where(
+			loan_disbursement.disbursed_amount <= filters.get('amount')
+		)
+
+	vouchers = query.run(as_list=True)
+
+	return vouchers
+
+def get_lr_matching_query(bank_account, amount_condition, filters):
+	loan_repayment = frappe.qb.DocType("Loan Repayment")
+	matching_reference = loan_repayment.reference_number == filters.get("reference_number")
+	matching_party = loan_repayment.applicant_type == filters.get("party_type") and \
+			loan_repayment.applicant == filters.get("party")
+
+	rank = (
+			frappe.qb.terms.Case()
+			.when(matching_reference, 1)
+			.else_(0)
+		)
+
+	rank1 = (
+			frappe.qb.terms.Case()
+			.when(matching_party, 1)
+			.else_(0)
+		)
+
+	query = frappe.qb.from_(loan_repayment).select(
+		rank + rank1 + 1,
+		ConstantColumn("Loan Repayment").as_("doctype"),
+		loan_repayment.name,
+		loan_repayment.amount_paid,
+		loan_repayment.reference_number,
+		loan_repayment.reference_date,
+		loan_repayment.applicant_type,
+		loan_repayment.posting_date
+	).where(
+		loan_repayment.docstatus == 1
+	).where(
+		loan_repayment.clearance_date.isnull()
+	).where(
+		loan_repayment.payment_account == bank_account
+	)
+
+	if amount_condition:
+		query.where(
+			loan_repayment.amount_paid == filters.get('amount')
+		)
+	else:
+		query.where(
+			loan_repayment.amount_paid <= filters.get('amount')
+		)
+
+	vouchers = query.run()
+
+	return vouchers
+
 def get_pe_matching_query(amount_condition, account_from_to, transaction):
 	# get matching payment entries query
 	if transaction.deposit > 0:
@@ -348,7 +461,6 @@
 	# We have mapping at the bank level
 	# So one bank could have both types of bank accounts like asset and liability
 	# So cr_or_dr should be judged only on basis of withdrawal and deposit and not account type
-	company_account = frappe.get_value("Bank Account", transaction.bank_account, "account")
 	cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit"
 
 	return f"""
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
index 51e1d6e..a476cab 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
@@ -49,7 +49,8 @@
 
 	def clear_linked_payment_entries(self, for_cancel=False):
 		for payment_entry in self.payment_entries:
-			if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim"]:
+			if payment_entry.payment_document in ["Payment Entry", "Journal Entry", "Purchase Invoice", "Expense Claim", "Loan Repayment",
+				"Loan Disbursement"]:
 				self.clear_simple_entry(payment_entry, for_cancel=for_cancel)
 
 			elif payment_entry.payment_document == "Sales Invoice":
@@ -116,11 +117,18 @@
 			payment_entry.payment_entry, paid_amount_field)
 
 	elif payment_entry.payment_document == "Journal Entry":
-		return frappe.db.get_value('Journal Entry Account', {'parent': payment_entry.payment_entry, 'account': bank_account}, "sum(credit_in_account_currency)")
+		return frappe.db.get_value('Journal Entry Account', {'parent': payment_entry.payment_entry, 'account': bank_account},
+			"sum(credit_in_account_currency)")
 
 	elif payment_entry.payment_document == "Expense Claim":
 		return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "total_amount_reimbursed")
 
+	elif payment_entry.payment_document == "Loan Disbursement":
+		return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "disbursed_amount")
+
+	elif payment_entry.payment_document == "Loan Repayment":
+		return frappe.db.get_value(payment_entry.payment_document, payment_entry.payment_entry, "amount_paid")
+
 	else:
 		frappe.throw("Please reconcile {0}: {1} manually".format(payment_entry.payment_document, payment_entry.payment_entry))
 
diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py
index 6c401fb..b72d266 100644
--- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py
+++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py
@@ -4,7 +4,12 @@
 
 import frappe
 from frappe import _
-from frappe.utils import flt, getdate, nowdate
+from frappe.query_builder.custom import ConstantColumn
+from frappe.query_builder.functions import Sum
+from frappe.utils import flt, getdate
+from pypika import CustomFunction
+
+from erpnext.accounts.utils import get_balance_on
 
 
 def execute(filters=None):
@@ -18,7 +23,6 @@
 
 	data = get_entries(filters)
 
-	from erpnext.accounts.utils import get_balance_on
 	balance_as_per_system = get_balance_on(filters["account"], filters["report_date"])
 
 	total_debit, total_credit = 0,0
@@ -118,7 +122,21 @@
 	]
 
 def get_entries(filters):
-	journal_entries = frappe.db.sql("""
+	journal_entries = get_journal_entries(filters)
+
+	payment_entries = get_payment_entries(filters)
+
+	loan_entries = get_loan_entries(filters)
+
+	pos_entries = []
+	if filters.include_pos_transactions:
+		pos_entries = get_pos_entries(filters)
+
+	return sorted(list(payment_entries)+list(journal_entries+list(pos_entries) + list(loan_entries)),
+			key=lambda k: getdate(k['posting_date']))
+
+def get_journal_entries(filters):
+	return frappe.db.sql("""
 		select "Journal Entry" as payment_document, jv.posting_date,
 			jv.name as payment_entry, jvd.debit_in_account_currency as debit,
 			jvd.credit_in_account_currency as credit, jvd.against_account,
@@ -130,7 +148,8 @@
 			and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s
 			and ifnull(jv.is_opening, 'No') = 'No'""", filters, as_dict=1)
 
-	payment_entries = frappe.db.sql("""
+def get_payment_entries(filters):
+	return frappe.db.sql("""
 		select
 			"Payment Entry" as payment_document, name as payment_entry,
 			reference_no, reference_date as ref_date,
@@ -145,9 +164,8 @@
 			and ifnull(clearance_date, '4000-01-01') > %(report_date)s
 	""", filters, as_dict=1)
 
-	pos_entries = []
-	if filters.include_pos_transactions:
-		pos_entries = frappe.db.sql("""
+def get_pos_entries(filters):
+	return frappe.db.sql("""
 			select
 				"Sales Invoice Payment" as payment_document, sip.name as payment_entry, sip.amount as debit,
 				si.posting_date, si.debit_to as against_account, sip.clearance_date,
@@ -161,8 +179,42 @@
 				si.posting_date ASC, si.name DESC
 		""", filters, as_dict=1)
 
-	return sorted(list(payment_entries)+list(journal_entries+list(pos_entries)),
-			key=lambda k: k['posting_date'] or getdate(nowdate()))
+def get_loan_entries(filters):
+	loan_docs = []
+	for doctype in ["Loan Disbursement", "Loan Repayment"]:
+		loan_doc = frappe.qb.DocType(doctype)
+		ifnull = CustomFunction('IFNULL', ['value', 'default'])
+
+		if doctype == "Loan Disbursement":
+			amount_field = (loan_doc.disbursed_amount).as_("credit")
+			posting_date = (loan_doc.disbursement_date).as_("posting_date")
+			account = loan_doc.disbursement_account
+		else:
+			amount_field = (loan_doc.amount_paid).as_("debit")
+			posting_date = (loan_doc.posting_date).as_("posting_date")
+			account = loan_doc.payment_account
+
+		entries = frappe.qb.from_(loan_doc).select(
+			ConstantColumn(doctype).as_("payment_document"),
+			(loan_doc.name).as_("payment_entry"),
+			(loan_doc.reference_number).as_("reference_no"),
+			(loan_doc.reference_date).as_("ref_date"),
+			amount_field,
+			posting_date,
+		).where(
+			loan_doc.docstatus == 1
+		).where(
+			account == filters.get('account')
+		).where(
+			posting_date <= getdate(filters.get('report_date'))
+		).where(
+			ifnull(loan_doc.clearance_date, '4000-01-01') > getdate(filters.get('report_date'))
+		).run(as_dict=1)
+
+		loan_docs.extend(entries)
+
+	return loan_docs
+
 
 def get_amounts_not_reflected_in_system(filters):
 	je_amount = frappe.db.sql("""
@@ -182,7 +234,40 @@
 
 	pe_amount = flt(pe_amount[0][0]) if pe_amount else 0.0
 
-	return je_amount + pe_amount
+	loan_amount = get_loan_amount(filters)
+
+	return je_amount + pe_amount + loan_amount
+
+def get_loan_amount(filters):
+	total_amount = 0
+	for doctype in ["Loan Disbursement", "Loan Repayment"]:
+		loan_doc = frappe.qb.DocType(doctype)
+		ifnull = CustomFunction('IFNULL', ['value', 'default'])
+
+		if doctype == "Loan Disbursement":
+			amount_field = Sum(loan_doc.disbursed_amount)
+			posting_date = (loan_doc.disbursement_date).as_("posting_date")
+			account = loan_doc.disbursement_account
+		else:
+			amount_field = Sum(loan_doc.amount_paid)
+			posting_date = (loan_doc.posting_date).as_("posting_date")
+			account = loan_doc.payment_account
+
+		amount = frappe.qb.from_(loan_doc).select(
+			amount_field
+		).where(
+			loan_doc.docstatus == 1
+		).where(
+			account == filters.get('account')
+		).where(
+			posting_date > getdate(filters.get('report_date'))
+		).where(
+			ifnull(loan_doc.clearance_date, '4000-01-01') <= getdate(filters.get('report_date'))
+		).run()[0][0]
+
+		total_amount += flt(amount)
+
+	return amount
 
 def get_balance_row(label, amount, account_currency):
 	if amount > 0:
diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
index 7811d56..50926d7 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
+++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
@@ -14,11 +14,15 @@
   "applicant",
   "section_break_7",
   "disbursement_date",
+  "clearance_date",
   "column_break_8",
   "disbursed_amount",
   "accounting_dimensions_section",
   "cost_center",
-  "customer_details_section",
+  "accounting_details",
+  "disbursement_account",
+  "column_break_16",
+  "loan_account",
   "bank_account",
   "disbursement_references_section",
   "reference_date",
@@ -107,11 +111,6 @@
    "label": "Disbursement Details"
   },
   {
-   "fieldname": "customer_details_section",
-   "fieldtype": "Section Break",
-   "label": "Customer Details"
-  },
-  {
    "fetch_from": "against_loan.applicant_type",
    "fieldname": "applicant_type",
    "fieldtype": "Select",
@@ -149,15 +148,48 @@
    "fieldname": "reference_number",
    "fieldtype": "Data",
    "label": "Reference Number"
+  },
+  {
+   "fieldname": "clearance_date",
+   "fieldtype": "Date",
+   "label": "Clearance Date",
+   "no_copy": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "accounting_details",
+   "fieldtype": "Section Break",
+   "label": "Accounting Details"
+  },
+  {
+   "fetch_from": "against_loan.disbursement_account",
+   "fieldname": "disbursement_account",
+   "fieldtype": "Link",
+   "label": "Disbursement Account",
+   "options": "Account",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_16",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fetch_from": "against_loan.loan_account",
+   "fieldname": "loan_account",
+   "fieldtype": "Link",
+   "label": "Loan Account",
+   "options": "Account",
+   "read_only": 1
   }
  ],
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2021-04-19 18:09:32.175355",
+ "modified": "2022-02-17 18:23:44.157598",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Disbursement",
+ "naming_rule": "Expression (old style)",
  "owner": "Administrator",
  "permissions": [
   {
@@ -194,5 +226,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_disbursement/loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
index df3aadf..54a03b9 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
+++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
@@ -42,9 +42,6 @@
 		if not self.posting_date:
 			self.posting_date = self.disbursement_date or nowdate()
 
-		if not self.bank_account and self.applicant_type == "Customer":
-			self.bank_account = frappe.db.get_value("Customer", self.applicant, "default_bank_account")
-
 	def validate_disbursal_amount(self):
 		possible_disbursal_amount = get_disbursal_amount(self.against_loan)
 
@@ -117,12 +114,11 @@
 
 	def make_gl_entries(self, cancel=0, adv_adj=0):
 		gle_map = []
-		loan_details = frappe.get_doc("Loan", self.against_loan)
 
 		gle_map.append(
 			self.get_gl_dict({
-				"account": loan_details.loan_account,
-				"against": loan_details.disbursement_account,
+				"account": self.loan_account,
+				"against": self.disbursement_account,
 				"debit": self.disbursed_amount,
 				"debit_in_account_currency": self.disbursed_amount,
 				"against_voucher_type": "Loan",
@@ -137,8 +133,8 @@
 
 		gle_map.append(
 			self.get_gl_dict({
-				"account": loan_details.disbursement_account,
-				"against": loan_details.loan_account,
+				"account": self.disbursement_account,
+				"against": self.loan_account,
 				"credit": self.disbursed_amount,
 				"credit_in_account_currency": self.disbursed_amount,
 				"against_voucher_type": "Loan",
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
index 93ef217..480e010 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
@@ -1,7 +1,7 @@
 {
  "actions": [],
  "autoname": "LM-REP-.####",
- "creation": "2019-09-03 14:44:39.977266",
+ "creation": "2022-01-25 10:30:02.767941",
  "doctype": "DocType",
  "editable_grid": 1,
  "engine": "InnoDB",
@@ -13,6 +13,7 @@
   "column_break_3",
   "company",
   "posting_date",
+  "clearance_date",
   "rate_of_interest",
   "payroll_payable_account",
   "is_term_loan",
@@ -37,7 +38,12 @@
   "total_penalty_paid",
   "total_interest_paid",
   "repayment_details",
-  "amended_from"
+  "amended_from",
+  "accounting_details_section",
+  "payment_account",
+  "penalty_income_account",
+  "column_break_36",
+  "loan_account"
  ],
  "fields": [
   {
@@ -260,12 +266,52 @@
    "fieldname": "repay_from_salary",
    "fieldtype": "Check",
    "label": "Repay From Salary"
+  },
+  {
+   "fieldname": "clearance_date",
+   "fieldtype": "Date",
+   "label": "Clearance Date",
+   "no_copy": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "accounting_details_section",
+   "fieldtype": "Section Break",
+   "label": "Accounting Details"
+  },
+  {
+   "fetch_from": "against_loan.payment_account",
+   "fieldname": "payment_account",
+   "fieldtype": "Link",
+   "label": "Repayment Account",
+   "options": "Account",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_36",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fetch_from": "against_loan.loan_account",
+   "fieldname": "loan_account",
+   "fieldtype": "Link",
+   "label": "Loan Account",
+   "options": "Account",
+   "read_only": 1
+  },
+  {
+   "fetch_from": "against_loan.penalty_income_account",
+   "fieldname": "penalty_income_account",
+   "fieldtype": "Link",
+   "hidden": 1,
+   "label": "Penalty Income Account",
+   "options": "Account"
   }
  ],
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-01-06 01:51:06.707782",
+ "modified": "2022-02-18 19:10:07.742298",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Repayment",
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index f3ed611..67c2b1e 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -310,7 +310,6 @@
 
 	def make_gl_entries(self, cancel=0, adv_adj=0):
 		gle_map = []
-		loan_details = frappe.get_doc("Loan", self.against_loan)
 
 		if self.shortfall_amount and self.amount_paid > self.shortfall_amount:
 			remarks = _("Shortfall Repayment of {0}.\nRepayment against Loan: {1}").format(self.shortfall_amount,
@@ -323,13 +322,13 @@
 		if self.repay_from_salary:
 			payment_account = self.payroll_payable_account
 		else:
-			payment_account = loan_details.payment_account
+			payment_account = self.payment_account
 
 		if self.total_penalty_paid:
 			gle_map.append(
 				self.get_gl_dict({
-					"account": loan_details.loan_account,
-					"against": loan_details.payment_account,
+					"account": self.loan_account,
+					"against": payment_account,
 					"debit": self.total_penalty_paid,
 					"debit_in_account_currency": self.total_penalty_paid,
 					"against_voucher_type": "Loan",
@@ -344,8 +343,8 @@
 
 			gle_map.append(
 				self.get_gl_dict({
-					"account": loan_details.penalty_income_account,
-					"against": loan_details.loan_account,
+					"account": self.penalty_income_account,
+					"against": self.loan_account,
 					"credit": self.total_penalty_paid,
 					"credit_in_account_currency": self.total_penalty_paid,
 					"against_voucher_type": "Loan",
@@ -359,8 +358,7 @@
 		gle_map.append(
 			self.get_gl_dict({
 				"account": payment_account,
-				"against": loan_details.loan_account + ", " + loan_details.interest_income_account
-						+ ", " + loan_details.penalty_income_account,
+				"against": self.loan_account + ", " + self.penalty_income_account,
 				"debit": self.amount_paid,
 				"debit_in_account_currency": self.amount_paid,
 				"against_voucher_type": "Loan",
@@ -368,16 +366,16 @@
 				"remarks": remarks,
 				"cost_center": self.cost_center,
 				"posting_date": getdate(self.posting_date),
-				"party_type": loan_details.applicant_type if self.repay_from_salary else '',
-				"party": loan_details.applicant if self.repay_from_salary else ''
+				"party_type": self.applicant_type if self.repay_from_salary else '',
+				"party": self.applicant if self.repay_from_salary else ''
 			})
 		)
 
 		gle_map.append(
 			self.get_gl_dict({
-				"account": loan_details.loan_account,
-				"party_type": loan_details.applicant_type,
-				"party": loan_details.applicant,
+				"account": self.loan_account,
+				"party_type": self.applicant_type,
+				"party": self.applicant,
 				"against": payment_account,
 				"credit": self.amount_paid,
 				"credit_in_account_currency": self.amount_paid,
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 52c29b2..7560f2f 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -353,4 +353,5 @@
 erpnext.patches.v13_0.update_exchange_rate_settings
 erpnext.patches.v14_0.delete_amazon_mws_doctype
 erpnext.patches.v13_0.set_work_order_qty_in_so_from_mr
+erpnext.patches.v13_0.update_accounts_in_loan_docs
 erpnext.patches.v14_0.update_batch_valuation_flag
diff --git a/erpnext/patches/v13_0/update_accounts_in_loan_docs.py b/erpnext/patches/v13_0/update_accounts_in_loan_docs.py
new file mode 100644
index 0000000..440f912
--- /dev/null
+++ b/erpnext/patches/v13_0/update_accounts_in_loan_docs.py
@@ -0,0 +1,37 @@
+import frappe
+
+
+def execute():
+	ld = frappe.qb.DocType("Loan Disbursement").as_("ld")
+	lr = frappe.qb.DocType("Loan Repayment").as_("lr")
+	loan = frappe.qb.DocType("Loan")
+
+	frappe.qb.update(
+		ld
+	).inner_join(
+		loan
+	).on(
+		loan.name == ld.against_loan
+	).set(
+		ld.disbursement_account, loan.disbursement_account
+	).set(
+		ld.loan_account, loan.loan_account
+	).where(
+		ld.docstatus < 2
+	).run()
+
+	frappe.qb.update(
+		lr
+	).inner_join(
+		loan
+	).on(
+		loan.name == lr.against_loan
+	).set(
+		lr.payment_account, loan.payment_account
+	).set(
+		lr.loan_account, loan.loan_account
+	).set(
+		lr.penalty_income_account, loan.penalty_income_account
+	).where(
+		lr.docstatus < 2
+	).run()
diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
index ca73393..214a1be 100644
--- a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
+++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
@@ -182,6 +182,12 @@
 				onchange: () => this.update_options(),
 			},
 			{
+				fieldtype: "Check",
+				label: "Loan Repayment",
+				fieldname: "loan_repayment",
+				onchange: () => this.update_options(),
+			},
+			{
 				fieldname: "column_break_5",
 				fieldtype: "Column Break",
 			},
@@ -191,7 +197,6 @@
 				fieldname: "sales_invoice",
 				onchange: () => this.update_options(),
 			},
-
 			{
 				fieldtype: "Check",
 				label: "Purchase Invoice",
@@ -199,6 +204,12 @@
 				onchange: () => this.update_options(),
 			},
 			{
+				fieldtype: "Check",
+				label: "Show Only Exact Amount",
+				fieldname: "exact_match",
+				onchange: () => this.update_options(),
+			},
+			{
 				fieldname: "column_break_5",
 				fieldtype: "Column Break",
 			},
@@ -210,8 +221,8 @@
 			},
 			{
 				fieldtype: "Check",
-				label: "Show Only Exact Amount",
-				fieldname: "exact_match",
+				label: "Loan Disbursement",
+				fieldname: "loan_disbursement",
 				onchange: () => this.update_options(),
 			},
 			{