chore: Extract Expense Claim, FnF, Gratuity, Employee Advance related code from accounting

- Added hooks `advance_payment_doctypes`, `invoice_doctypes`, `period_closing_doctypes` for other apps to extend accounting functionality

- Removed `set_query` code from `journal_entry.js` and `payment_entry.js`

- removed `update_status_for_full_and_final_statement` trigger on JE submission/cancellation

- refactored `payment_entry.py`: split functions for validating reference doctypes for easy overriding, removed hrms references from `get_reference_details` and `get_payment_entry`

- removed dead code: functions `get_bill_no_and_update_amounts`, `get_total_amount_exchange_rate_base_on_currency`, `get_total_amount_exchange_rate_for_employee_advance`, `get_amounts_based_on_ref_doc`, `get_amounts_based_on_reference_doctype`
diff --git a/erpnext/accounts/doctype/accounting_period/accounting_period.py b/erpnext/accounts/doctype/accounting_period/accounting_period.py
index 0c15d6a..1f2d12f 100644
--- a/erpnext/accounts/doctype/accounting_period/accounting_period.py
+++ b/erpnext/accounts/doctype/accounting_period/accounting_period.py
@@ -49,15 +49,8 @@
 	@frappe.whitelist()
 	def get_doctypes_for_closing(self):
 		docs_for_closing = []
-		doctypes = [
-			"Sales Invoice",
-			"Purchase Invoice",
-			"Journal Entry",
-			"Payroll Entry",
-			"Bank Clearance",
-			"Asset",
-			"Stock Entry",
-		]
+		doctypes = frappe.get_hooks("period_closing_doctypes")
+
 		closed_doctypes = [{"document_type": doctype, "closed": 1} for doctype in doctypes]
 		for closed_doctype in closed_doctypes:
 			docs_for_closing.append(closed_doctype)
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 3cc28a3..b539bfe 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -240,25 +240,6 @@
 		me.frm.set_query("reference_name", "accounts", function(doc, cdt, cdn) {
 			var jvd = frappe.get_doc(cdt, cdn);
 
-			// expense claim
-			if(jvd.reference_type==="Expense Claim") {
-				return {
-					filters: {
-						'total_sanctioned_amount': ['>', 0],
-						'status': ['!=', 'Paid'],
-						'docstatus': 1
-					}
-				};
-			}
-
-			if(jvd.reference_type==="Employee Advance") {
-				return {
-					filters: {
-						'docstatus': 1
-					}
-				};
-			}
-
 			// journal entry
 			if(jvd.reference_type==="Journal Entry") {
 				frappe.model.validate_missing(jvd, "account");
@@ -271,13 +252,6 @@
 				};
 			}
 
-			// payroll entry
-			if(jvd.reference_type==="Payroll Entry") {
-				return {
-					query: "erpnext.payroll.doctype.payroll_entry.payroll_entry.get_payroll_entries_for_jv",
-				};
-			}
-
 			var out = {
 				filters: [
 					[jvd.reference_type, "docstatus", "=", 1]
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 0260eae..5690911 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -83,7 +83,6 @@
 		self.update_advance_paid()
 		self.update_inter_company_jv()
 		self.update_invoice_discounting()
-		self.update_status_for_full_and_final_statement()
 
 	def on_cancel(self):
 		from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
@@ -97,7 +96,6 @@
 		self.unlink_inter_company_jv()
 		self.unlink_asset_adjustment_entry()
 		self.update_invoice_discounting()
-		self.update_status_for_full_and_final_statement()
 
 	def get_title(self):
 		return self.pay_to_recd_from or self.accounts[0].account
@@ -106,21 +104,13 @@
 		advance_paid = frappe._dict()
 		for d in self.get("accounts"):
 			if d.is_advance:
-				if d.reference_type in ("Sales Order", "Purchase Order", "Employee Advance"):
+				if d.reference_type in frappe.get_hooks("advance_payment_doctypes"):
 					advance_paid.setdefault(d.reference_type, []).append(d.reference_name)
 
 		for voucher_type, order_list in advance_paid.items():
 			for voucher_no in list(set(order_list)):
 				frappe.get_doc(voucher_type, voucher_no).set_total_advance_paid()
 
-	def update_status_for_full_and_final_statement(self):
-		for entry in self.accounts:
-			if entry.reference_type == "Full and Final Statement":
-				if self.docstatus == 1:
-					frappe.db.set_value("Full and Final Statement", entry.reference_name, "status", "Paid")
-				elif self.docstatus == 2:
-					frappe.db.set_value("Full and Final Statement", entry.reference_name, "status", "Unpaid")
-
 	def validate_inter_company_accounts(self):
 		if (
 			self.voucher_type == "Inter Company Journal Entry"
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index d7fae6d..0f53079 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -110,8 +110,6 @@
 				var doctypes = ["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"];
 			} else if (frm.doc.party_type == "Supplier") {
 				var doctypes = ["Purchase Order", "Purchase Invoice", "Journal Entry"];
-			} else if (frm.doc.party_type == "Employee") {
-				var doctypes = ["Expense Claim", "Journal Entry"];
 			} else {
 				var doctypes = ["Journal Entry"];
 			}
@@ -140,17 +138,12 @@
 			const child = locals[cdt][cdn];
 			const filters = {"docstatus": 1, "company": doc.company};
 			const party_type_doctypes = ['Sales Invoice', 'Sales Order', 'Purchase Invoice',
-				'Purchase Order', 'Expense Claim', 'Fees', 'Dunning'];
+				'Purchase Order', 'Dunning'];
 
 			if (in_list(party_type_doctypes, child.reference_doctype)) {
 				filters[doc.party_type.toLowerCase()] = doc.party;
 			}
 
-			if(child.reference_doctype == "Expense Claim") {
-				filters["docstatus"] = 1;
-				filters["is_paid"] = 0;
-			}
-
 			return {
 				filters: filters
 			};
@@ -730,7 +723,7 @@
 						c.payment_term = d.payment_term;
 						c.allocated_amount = d.allocated_amount;
 
-						if(!in_list(["Sales Order", "Purchase Order", "Expense Claim", "Fees"], d.voucher_type)) {
+						if(!in_list(frm.events.get_order_doctypes(frm), d.voucher_type)) {
 							if(flt(d.outstanding_amount) > 0)
 								total_positive_outstanding += flt(d.outstanding_amount);
 							else
@@ -745,7 +738,7 @@
 						} else {
 							c.exchange_rate = 1;
 						}
-						if (in_list(['Sales Invoice', 'Purchase Invoice', "Expense Claim", "Fees"], d.reference_doctype)){
+						if (in_list(frm.events.get_invoice_doctypes(frm), d.reference_doctype)){
 							c.due_date = d.due_date;
 						}
 					});
@@ -776,6 +769,14 @@
 		});
 	},
 
+	get_order_doctypes: function(frm) {
+		return ["Sales Order", "Purchase Order"];
+	},
+
+	get_invoice_doctypes: function(frm) {
+		return ["Sales Invoice", "Purchase Invoice"];
+	},
+
 	allocate_party_amount_against_ref_docs: function(frm, paid_amount, paid_amount_change) {
 		var total_positive_outstanding_including_order = 0;
 		var total_negative_outstanding = 0;
@@ -946,14 +947,6 @@
 				frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Purchase Order, Purchase Invoice or Journal Entry", [row.idx]));
 				return false;
 			}
-
-			if(frm.doc.party_type=="Employee" &&
-				!in_list(["Expense Claim", "Journal Entry"], row.reference_doctype)
-			) {
-				frappe.model.set_value(row.doctype, row.name, "against_voucher_type", null);
-				frappe.msgprint(__("Row #{0}: Reference Document Type must be one of Expense Claim or Journal Entry", [row.idx]));
-				return false;
-			}
 		}
 
 		if (row) {
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index c9746ab..c8a5746 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -293,14 +293,7 @@
 				frappe.throw(_("{0} is mandatory").format(self.meta.get_label(field)))
 
 	def validate_reference_documents(self):
-		if self.party_type == "Customer":
-			valid_reference_doctypes = ("Sales Order", "Sales Invoice", "Journal Entry", "Dunning")
-		elif self.party_type == "Supplier":
-			valid_reference_doctypes = ("Purchase Order", "Purchase Invoice", "Journal Entry")
-		elif self.party_type == "Employee":
-			valid_reference_doctypes = ("Expense Claim", "Journal Entry", "Employee Advance", "Gratuity")
-		elif self.party_type == "Shareholder":
-			valid_reference_doctypes = "Journal Entry"
+		valid_reference_doctypes = self.get_valid_reference_doctypes()
 
 		for d in self.get("references"):
 			if not d.allocated_amount:
@@ -326,7 +319,7 @@
 					else:
 						self.validate_journal_entry()
 
-					if d.reference_doctype in ("Sales Invoice", "Purchase Invoice", "Expense Claim", "Fees"):
+					if d.reference_doctype in frappe.get_hooks("invoice_doctypes"):
 						if self.party_type == "Customer":
 							ref_party_account = (
 								get_party_account_based_on_invoice_discounting(d.reference_name) or ref_doc.debit_to
@@ -352,6 +345,16 @@
 					if ref_doc.docstatus != 1:
 						frappe.throw(_("{0} {1} must be submitted").format(d.reference_doctype, d.reference_name))
 
+	def get_valid_reference_doctypes(self):
+		if self.party_type == "Customer":
+			return ("Sales Order", "Sales Invoice", "Journal Entry", "Dunning")
+		elif self.party_type == "Supplier":
+			return ("Purchase Order", "Purchase Invoice", "Journal Entry")
+		elif self.party_type == "Shareholder":
+			return ("Journal Entry",)
+		elif self.party_type == "Employee":
+			return ("Journal Entry",)
+
 	def validate_paid_invoices(self):
 		no_oustanding_refs = {}
 
@@ -974,12 +977,7 @@
 	def update_advance_paid(self):
 		if self.payment_type in ("Receive", "Pay") and self.party:
 			for d in self.get("references"):
-				if d.allocated_amount and d.reference_doctype in (
-					"Sales Order",
-					"Purchase Order",
-					"Employee Advance",
-					"Gratuity",
-				):
+				if d.allocated_amount and d.reference_doctype in frappe.get_hooks("advance_payment_doctypes"):
 					frappe.get_doc(d.reference_doctype, d.reference_name).set_total_advance_paid()
 
 	def on_recurring(self, reference_doc, auto_repeat_doc):
@@ -1235,7 +1233,7 @@
 	for d in outstanding_invoices:
 		d["exchange_rate"] = 1
 		if party_account_currency != company_currency:
-			if d.voucher_type in ("Sales Invoice", "Purchase Invoice", "Expense Claim"):
+			if d.voucher_type in frappe.get_hooks("invoice_doctypes"):
 				d["exchange_rate"] = frappe.db.get_value(d.voucher_type, d.voucher_no, "conversion_rate")
 			elif d.voucher_type == "Journal Entry":
 				d["exchange_rate"] = get_exchange_rate(
@@ -1562,20 +1560,17 @@
 
 @frappe.whitelist()
 def get_reference_details(reference_doctype, reference_name, party_account_currency):
-	total_amount = outstanding_amount = exchange_rate = bill_no = None
+	total_amount = outstanding_amount = exchange_rate = None
+
 	ref_doc = frappe.get_doc(reference_doctype, reference_name)
 	company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(
 		ref_doc.company
 	)
 
-	if reference_doctype == "Fees":
-		total_amount = ref_doc.get("grand_total")
+	if reference_doctype == "Dunning":
+		total_amount = outstanding_amount = ref_doc.get("dunning_amount")
 		exchange_rate = 1
-		outstanding_amount = ref_doc.get("outstanding_amount")
-	elif reference_doctype == "Dunning":
-		total_amount = ref_doc.get("dunning_amount")
-		exchange_rate = 1
-		outstanding_amount = ref_doc.get("dunning_amount")
+
 	elif reference_doctype == "Journal Entry" and ref_doc.docstatus == 1:
 		total_amount = ref_doc.get("total_amount")
 		if ref_doc.multi_currency:
@@ -1585,16 +1580,8 @@
 		else:
 			exchange_rate = 1
 			outstanding_amount = get_outstanding_on_journal_entry(reference_name)
+
 	elif reference_doctype != "Journal Entry":
-		if ref_doc.doctype == "Expense Claim":
-			total_amount = flt(ref_doc.total_sanctioned_amount) + flt(ref_doc.total_taxes_and_charges)
-		elif ref_doc.doctype == "Employee Advance":
-			total_amount = ref_doc.advance_amount
-			exchange_rate = ref_doc.get("exchange_rate")
-			if party_account_currency != ref_doc.currency:
-				total_amount = flt(total_amount) * flt(exchange_rate)
-		elif ref_doc.doctype == "Gratuity":
-			total_amount = ref_doc.amount
 		if not total_amount:
 			if party_account_currency == company_currency:
 				total_amount = ref_doc.base_grand_total
@@ -1607,26 +1594,12 @@
 			exchange_rate = ref_doc.get("conversion_rate") or get_exchange_rate(
 				party_account_currency, company_currency, ref_doc.posting_date
 			)
+
 		if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
 			outstanding_amount = ref_doc.get("outstanding_amount")
-			bill_no = ref_doc.get("bill_no")
-		elif reference_doctype == "Expense Claim":
-			outstanding_amount = (
-				flt(ref_doc.get("total_sanctioned_amount"))
-				+ flt(ref_doc.get("total_taxes_and_charges"))
-				- flt(ref_doc.get("total_amount_reimbursed"))
-				- flt(ref_doc.get("total_advance_amount"))
-			)
-		elif reference_doctype == "Employee Advance":
-			outstanding_amount = flt(ref_doc.advance_amount) - flt(ref_doc.paid_amount)
-			if party_account_currency != ref_doc.currency:
-				outstanding_amount = flt(outstanding_amount) * flt(exchange_rate)
-				if party_account_currency == company_currency:
-					exchange_rate = 1
-		elif reference_doctype == "Gratuity":
-			outstanding_amount = ref_doc.amount - flt(ref_doc.paid_amount)
 		else:
 			outstanding_amount = flt(total_amount) - flt(ref_doc.advance_paid)
+
 	else:
 		# Get the exchange rate based on the posting date of the ref doc.
 		exchange_rate = get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
@@ -1637,114 +1610,11 @@
 			"total_amount": flt(total_amount),
 			"outstanding_amount": flt(outstanding_amount),
 			"exchange_rate": flt(exchange_rate),
-			"bill_no": bill_no,
+			"bill_no": ref_doc.get("bill_no"),
 		}
 	)
 
 
-def get_amounts_based_on_reference_doctype(
-	reference_doctype, ref_doc, party_account_currency, company_currency, reference_name
-):
-	total_amount = outstanding_amount = exchange_rate = None
-	if reference_doctype == "Fees":
-		total_amount = ref_doc.get("grand_total")
-		exchange_rate = 1
-		outstanding_amount = ref_doc.get("outstanding_amount")
-	elif reference_doctype == "Dunning":
-		total_amount = ref_doc.get("dunning_amount")
-		exchange_rate = 1
-		outstanding_amount = ref_doc.get("dunning_amount")
-	elif reference_doctype == "Journal Entry" and ref_doc.docstatus == 1:
-		total_amount = ref_doc.get("total_amount")
-		if ref_doc.multi_currency:
-			exchange_rate = get_exchange_rate(
-				party_account_currency, company_currency, ref_doc.posting_date
-			)
-		else:
-			exchange_rate = 1
-			outstanding_amount = get_outstanding_on_journal_entry(reference_name)
-
-	return total_amount, outstanding_amount, exchange_rate
-
-
-def get_amounts_based_on_ref_doc(
-	reference_doctype, ref_doc, party_account_currency, company_currency
-):
-	total_amount = outstanding_amount = exchange_rate = None
-	if ref_doc.doctype == "Expense Claim":
-		total_amount = flt(ref_doc.total_sanctioned_amount) + flt(ref_doc.total_taxes_and_charges)
-	elif ref_doc.doctype == "Employee Advance":
-		total_amount, exchange_rate = get_total_amount_exchange_rate_for_employee_advance(
-			party_account_currency, ref_doc
-		)
-
-	if not total_amount:
-		total_amount, exchange_rate = get_total_amount_exchange_rate_base_on_currency(
-			party_account_currency, company_currency, ref_doc
-		)
-
-	if not exchange_rate:
-		# Get the exchange rate from the original ref doc
-		# or get it based on the posting date of the ref doc
-		exchange_rate = ref_doc.get("conversion_rate") or get_exchange_rate(
-			party_account_currency, company_currency, ref_doc.posting_date
-		)
-
-	outstanding_amount, exchange_rate, bill_no = get_bill_no_and_update_amounts(
-		reference_doctype, ref_doc, total_amount, exchange_rate, party_account_currency, company_currency
-	)
-
-	return total_amount, outstanding_amount, exchange_rate, bill_no
-
-
-def get_total_amount_exchange_rate_for_employee_advance(party_account_currency, ref_doc):
-	total_amount = ref_doc.advance_amount
-	exchange_rate = ref_doc.get("exchange_rate")
-	if party_account_currency != ref_doc.currency:
-		total_amount = flt(total_amount) * flt(exchange_rate)
-
-	return total_amount, exchange_rate
-
-
-def get_total_amount_exchange_rate_base_on_currency(
-	party_account_currency, company_currency, ref_doc
-):
-	exchange_rate = None
-	if party_account_currency == company_currency:
-		total_amount = ref_doc.base_grand_total
-		exchange_rate = 1
-	else:
-		total_amount = ref_doc.grand_total
-
-	return total_amount, exchange_rate
-
-
-def get_bill_no_and_update_amounts(
-	reference_doctype, ref_doc, total_amount, exchange_rate, party_account_currency, company_currency
-):
-	outstanding_amount = bill_no = None
-	if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
-		outstanding_amount = ref_doc.get("outstanding_amount")
-		bill_no = ref_doc.get("bill_no")
-	elif reference_doctype == "Expense Claim":
-		outstanding_amount = (
-			flt(ref_doc.get("total_sanctioned_amount"))
-			+ flt(ref_doc.get("total_taxes_and_charges"))
-			- flt(ref_doc.get("total_amount_reimbursed"))
-			- flt(ref_doc.get("total_advance_amount"))
-		)
-	elif reference_doctype == "Employee Advance":
-		outstanding_amount = flt(ref_doc.advance_amount) - flt(ref_doc.paid_amount)
-		if party_account_currency != ref_doc.currency:
-			outstanding_amount = flt(outstanding_amount) * flt(exchange_rate)
-			if party_account_currency == company_currency:
-				exchange_rate = 1
-	else:
-		outstanding_amount = flt(total_amount) - flt(ref_doc.advance_paid)
-
-	return outstanding_amount, exchange_rate, bill_no
-
-
 @frappe.whitelist()
 def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount=None):
 	reference_doc = None
@@ -1863,8 +1733,6 @@
 	pe.set_missing_values()
 
 	if party_account and bank:
-		if dt == "Employee Advance":
-			reference_doc = doc
 		pe.set_exchange_rate(ref_doc=reference_doc)
 		pe.set_amounts()
 		if discount_amount:
@@ -1899,8 +1767,6 @@
 		party_type = "Customer"
 	elif dt in ("Purchase Invoice", "Purchase Order"):
 		party_type = "Supplier"
-	elif dt in ("Expense Claim", "Employee Advance", "Gratuity"):
-		party_type = "Employee"
 	return party_type
 
 
@@ -1911,12 +1777,6 @@
 		party_account = doc.credit_to
 	elif dt == "Fees":
 		party_account = doc.receivable_account
-	elif dt == "Employee Advance":
-		party_account = doc.advance_account
-	elif dt == "Expense Claim":
-		party_account = doc.payable_account
-	elif dt == "Gratuity":
-		party_account = doc.payable_account
 	else:
 		party_account = get_party_account(party_type, doc.get(party_type.lower()), doc.company)
 	return party_account
@@ -1951,24 +1811,12 @@
 		else:
 			grand_total = doc.rounded_total or doc.grand_total
 		outstanding_amount = doc.outstanding_amount
-	elif dt in ("Expense Claim"):
-		grand_total = doc.total_sanctioned_amount + doc.total_taxes_and_charges
-		outstanding_amount = doc.grand_total - doc.total_amount_reimbursed
-	elif dt == "Employee Advance":
-		grand_total = flt(doc.advance_amount)
-		outstanding_amount = flt(doc.advance_amount) - flt(doc.paid_amount)
-		if party_account_currency != doc.currency:
-			grand_total = flt(doc.advance_amount) * flt(doc.exchange_rate)
-			outstanding_amount = (flt(doc.advance_amount) - flt(doc.paid_amount)) * flt(doc.exchange_rate)
 	elif dt == "Fees":
 		grand_total = doc.grand_total
 		outstanding_amount = doc.outstanding_amount
 	elif dt == "Dunning":
 		grand_total = doc.grand_total
 		outstanding_amount = doc.grand_total
-	elif dt == "Gratuity":
-		grand_total = doc.amount
-		outstanding_amount = flt(doc.amount) - flt(doc.paid_amount)
 	else:
 		if party_account_currency == doc.company_currency:
 			grand_total = flt(doc.get("base_rounded_total") or doc.base_grand_total)
@@ -1990,8 +1838,6 @@
 			received_amount = bank_amount
 		else:
 			received_amount = paid_amount * doc.get("conversion_rate", 1)
-			if dt == "Employee Advance":
-				received_amount = paid_amount * doc.get("exchange_rate", 1)
 	else:
 		received_amount = abs(outstanding_amount)
 		if bank_amount:
@@ -1999,8 +1845,6 @@
 		else:
 			# if party account currency and bank currency is different then populate paid amount as well
 			paid_amount = received_amount * doc.get("conversion_rate", 1)
-			if dt == "Employee Advance":
-				paid_amount = received_amount * doc.get("exchange_rate", 1)
 
 	return paid_amount, received_amount
 
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index d629b70..a2dc205 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -472,6 +472,19 @@
 
 communication_doctypes = ["Customer", "Supplier"]
 
+advance_payment_doctypes = ["Sales Order", "Purchase Order"]
+
+invoice_doctypes = ["Sales Invoice", "Purchase Invoice"]
+
+period_closing_doctypes = [
+	"Sales Invoice",
+	"Purchase Invoice",
+	"Journal Entry",
+	"Bank Clearance",
+	"Asset",
+	"Stock Entry",
+]
+
 accounting_dimension_doctypes = [
 	"GL Entry",
 	"Payment Ledger Entry",
@@ -479,12 +492,8 @@
 	"Purchase Invoice",
 	"Payment Entry",
 	"Asset",
-	"Expense Claim",
-	"Expense Claim Detail",
-	"Expense Taxes and Charges",
 	"Stock Entry",
 	"Budget",
-	"Payroll Entry",
 	"Delivery Note",
 	"Sales Invoice Item",
 	"Purchase Invoice Item",