Merge pull request #30292 from frappe/mergify/bp/develop/pr-30284

fix: Cleanup and fixes in Dimension-wise Accounts Balance Report (backport #30284)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 2c31561..7654aa4 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -32,6 +32,7 @@
 from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_enabled
 from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
 from erpnext.buying.utils import check_on_hold_or_closed_status
+from erpnext.controllers.accounts_controller import validate_account_head
 from erpnext.controllers.buying_controller import BuyingController
 from erpnext.stock import get_warehouse_account_map
 from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
@@ -107,6 +108,7 @@
 		self.validate_uom_is_integer("uom", "qty")
 		self.validate_uom_is_integer("stock_uom", "stock_qty")
 		self.set_expense_account(for_validate=True)
+		self.validate_expense_account()
 		self.set_against_expense_account()
 		self.validate_write_off_account()
 		self.validate_multiple_billing("Purchase Receipt", "pr_detail", "amount", "items")
@@ -311,6 +313,10 @@
 			elif not item.expense_account and for_validate:
 				throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name))
 
+	def validate_expense_account(self):
+		for item in self.get('items'):
+			validate_account_head(item.idx, item.expense_account, self.company, 'Expense')
+
 	def set_against_expense_account(self):
 		against_accounts = []
 		for item in self.get("items"):
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 3afd72e..e107912 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -37,6 +37,7 @@
 	get_gl_entries_on_asset_regain,
 	make_depreciation_entry,
 )
+from erpnext.controllers.accounts_controller import validate_account_head
 from erpnext.controllers.selling_controller import SellingController
 from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timesheet_data
 from erpnext.setup.doctype.company.company import update_company_current_month_sales
@@ -111,6 +112,8 @@
 		self.validate_fixed_asset()
 		self.set_income_account_for_fixed_assets()
 		self.validate_item_cost_centers()
+		self.validate_income_account()
+
 		validate_inter_company_party(self.doctype, self.customer, self.company, self.inter_company_invoice_reference)
 
 		if cint(self.is_pos):
@@ -178,6 +181,10 @@
 			if cost_center_company != self.company:
 				frappe.throw(_("Row #{0}: Cost Center {1} does not belong to company {2}").format(frappe.bold(item.idx), frappe.bold(item.cost_center), frappe.bold(self.company)))
 
+	def validate_income_account(self):
+		for item in self.get('items'):
+			validate_account_head(item.idx, item.income_account, self.company, 'Income')
+
 	def set_tax_withholding(self):
 		tax_withholding_details = get_party_tax_withholding_details(self)
 
diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py
index 86eb213..17475a7 100644
--- a/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py
+++ b/erpnext/accounts/report/deferred_revenue_and_expense/test_deferred_revenue_and_expense.py
@@ -88,10 +88,12 @@
 			posting_date="2021-05-01",
 			parent_cost_center="Main - _CD",
 			cost_center="Main - _CD",
-			do_not_submit=True,
+			do_not_save=True,
 			rate=300,
 			price_list_rate=300,
 		)
+
+		si.items[0].income_account = "Sales - _CD"
 		si.items[0].enable_deferred_revenue = 1
 		si.items[0].service_start_date = "2021-05-01"
 		si.items[0].service_end_date = "2021-08-01"
@@ -269,11 +271,13 @@
 			posting_date="2021-05-01",
 			parent_cost_center="Main - _CD",
 			cost_center="Main - _CD",
-			do_not_submit=True,
+			do_not_save=True,
 			rate=300,
 			price_list_rate=300,
 		)
+
 		si.items[0].enable_deferred_revenue = 1
+		si.items[0].income_account = "Sales - _CD"
 		si.items[0].deferred_revenue_account = deferred_revenue_account
 		si.items[0].income_account = "Sales - _CD"
 		si.save()
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index a94af10..34ff457 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1566,12 +1566,12 @@
 		tax.rate = None
 
 
-def validate_account_head(idx, account, company):
+def validate_account_head(idx, account, company, context=''):
 	account_company = frappe.get_cached_value('Account', account, 'company')
 
 	if account_company != company:
-		frappe.throw(_('Row {0}: Account {1} does not belong to Company {2}')
-			.format(idx, frappe.bold(account), frappe.bold(company)), title=_('Invalid Account'))
+		frappe.throw(_('Row {0}: {3} Account {1} does not belong to Company {2}')
+			.format(idx, frappe.bold(account), frappe.bold(company), context), title=_('Invalid Account'))
 
 
 def validate_cost_center(tax, doc):
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index 97a740e..7ca4003 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -12,7 +12,7 @@
 from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
 
 Filters = frappe._dict
-precision = cint(frappe.db.get_single_value("System Settings", "float_precision"))
+
 
 def execute(filters: Filters = None) -> Tuple:
 	to_date = filters["to_date"]
@@ -30,6 +30,8 @@
 	_func = itemgetter(1)
 	data = []
 
+	precision = cint(frappe.db.get_single_value("System Settings", "float_precision", cache=True))
+
 	for item, item_dict in item_details.items():
 		earliest_age, latest_age = 0, 0
 		details = item_dict["details"]
@@ -76,6 +78,9 @@
 	return flt(age_qty / total_qty, 2) if total_qty else 0.0
 
 def get_range_age(filters: Filters, fifo_queue: List, to_date: str, item_dict: Dict) -> Tuple:
+
+	precision = cint(frappe.db.get_single_value("System Settings", "float_precision", cache=True))
+
 	range1 = range2 = range3 = above_range3 = 0.0
 
 	for item in fifo_queue: