perf: Move dimension validation out of GL Entry doctype (#39730)

diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 1c8ac2f..2e82886 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -13,9 +13,13 @@
 from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
 	get_accounting_dimensions,
 )
+from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_filter import (
+	get_dimension_filter_map,
+)
 from erpnext.accounts.doctype.accounting_period.accounting_period import ClosedAccountingPeriod
 from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
 from erpnext.accounts.utils import create_payment_ledger_entry
+from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
 
 
 def make_gl_entries(
@@ -355,6 +359,7 @@
 
 	process_debit_credit_difference(gl_map)
 
+	dimension_filter_map = get_dimension_filter_map()
 	if gl_map:
 		check_freezing_date(gl_map[0]["posting_date"], adv_adj)
 		is_opening = any(d.get("is_opening") == "Yes" for d in gl_map)
@@ -362,6 +367,7 @@
 			validate_against_pcv(is_opening, gl_map[0]["posting_date"], gl_map[0]["company"])
 
 	for entry in gl_map:
+		validate_allowed_dimensions(entry, dimension_filter_map)
 		make_entry(entry, adv_adj, update_outstanding, from_repost)
 
 
@@ -700,3 +706,39 @@
 		where voucher_type=%s and voucher_no=%s and is_cancelled = 0""",
 		(now(), frappe.session.user, voucher_type, voucher_no),
 	)
+
+
+def validate_allowed_dimensions(gl_entry, dimension_filter_map):
+	for key, value in dimension_filter_map.items():
+		dimension = key[0]
+		account = key[1]
+
+		if gl_entry.account == account:
+			if value["is_mandatory"] and not gl_entry.get(dimension):
+				frappe.throw(
+					_("{0} is mandatory for account {1}").format(
+						frappe.bold(frappe.unscrub(dimension)), frappe.bold(gl_entry.account)
+					),
+					MandatoryAccountDimensionError,
+				)
+
+			if value["allow_or_restrict"] == "Allow":
+				if gl_entry.get(dimension) and gl_entry.get(dimension) not in value["allowed_dimensions"]:
+					frappe.throw(
+						_("Invalid value {0} for {1} against account {2}").format(
+							frappe.bold(gl_entry.get(dimension)),
+							frappe.bold(frappe.unscrub(dimension)),
+							frappe.bold(gl_entry.account),
+						),
+						InvalidAccountDimensionError,
+					)
+			else:
+				if gl_entry.get(dimension) and gl_entry.get(dimension) in value["allowed_dimensions"]:
+					frappe.throw(
+						_("Invalid value {0} for {1} against account {2}").format(
+							frappe.bold(gl_entry.get(dimension)),
+							frappe.bold(frappe.unscrub(dimension)),
+							frappe.bold(gl_entry.account),
+						),
+						InvalidAccountDimensionError,
+					)