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

diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 777a5bb..def2838 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -13,16 +13,9 @@
 from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
 	get_checks_for_pl_and_bs_accounts,
 )
-from erpnext.accounts.doctype.accounting_dimension_filter.accounting_dimension_filter import (
-	get_dimension_filter_map,
-)
 from erpnext.accounts.party import validate_party_frozen_disabled, validate_party_gle_currency
 from erpnext.accounts.utils import get_account_currency, get_fiscal_year
-from erpnext.exceptions import (
-	InvalidAccountCurrency,
-	InvalidAccountDimensionError,
-	MandatoryAccountDimensionError,
-)
+from erpnext.exceptions import InvalidAccountCurrency
 
 exclude_from_linked_with = True
 
@@ -98,7 +91,6 @@
 		if not self.flags.from_repost and self.voucher_type != "Period Closing Voucher":
 			self.validate_account_details(adv_adj)
 			self.validate_dimensions_for_pl_and_bs()
-			self.validate_allowed_dimensions()
 			validate_balance_type(self.account, adv_adj)
 			validate_frozen_account(self.account, adv_adj)
 
@@ -208,42 +200,6 @@
 						)
 					)
 
-	def validate_allowed_dimensions(self):
-		dimension_filter_map = get_dimension_filter_map()
-		for key, value in dimension_filter_map.items():
-			dimension = key[0]
-			account = key[1]
-
-			if self.account == account:
-				if value["is_mandatory"] and not self.get(dimension):
-					frappe.throw(
-						_("{0} is mandatory for account {1}").format(
-							frappe.bold(frappe.unscrub(dimension)), frappe.bold(self.account)
-						),
-						MandatoryAccountDimensionError,
-					)
-
-				if value["allow_or_restrict"] == "Allow":
-					if self.get(dimension) and self.get(dimension) not in value["allowed_dimensions"]:
-						frappe.throw(
-							_("Invalid value {0} for {1} against account {2}").format(
-								frappe.bold(self.get(dimension)),
-								frappe.bold(frappe.unscrub(dimension)),
-								frappe.bold(self.account),
-							),
-							InvalidAccountDimensionError,
-						)
-				else:
-					if self.get(dimension) and self.get(dimension) in value["allowed_dimensions"]:
-						frappe.throw(
-							_("Invalid value {0} for {1} against account {2}").format(
-								frappe.bold(self.get(dimension)),
-								frappe.bold(frappe.unscrub(dimension)),
-								frappe.bold(self.account),
-							),
-							InvalidAccountDimensionError,
-						)
-
 	def check_pl_account(self):
 		if (
 			self.is_opening == "Yes"
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,
+					)