Merge pull request #39687 from s-aga-r/FIX-9316

fix: out of range for valuation_rate column in SE
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 651599d..3f11798 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -118,6 +118,7 @@
 		self.validate_balance_must_be_debit_or_credit()
 		self.validate_account_currency()
 		self.validate_root_company_and_sync_account_to_children()
+		self.validate_receivable_payable_account_type()
 
 	def validate_parent_child_account_type(self):
 		if self.parent_account:
@@ -188,6 +189,24 @@
 				"Balance Sheet" if self.root_type in ("Asset", "Liability", "Equity") else "Profit and Loss"
 			)
 
+	def validate_receivable_payable_account_type(self):
+		doc_before_save = self.get_doc_before_save()
+		receivable_payable_types = ["Receivable", "Payable"]
+		if (
+			doc_before_save
+			and doc_before_save.account_type in receivable_payable_types
+			and doc_before_save.account_type != self.account_type
+		):
+			# check for ledger entries
+			if frappe.db.get_all("GL Entry", filters={"account": self.name, "is_cancelled": 0}, limit=1):
+				msg = _(
+					"There are ledger entries against this account. Changing {0} to non-{1} in live system will cause incorrect output in 'Accounts {2}' report"
+				).format(
+					frappe.bold("Account Type"), doc_before_save.account_type, doc_before_save.account_type
+				)
+				frappe.msgprint(msg)
+				self.add_comment("Comment", msg)
+
 	def validate_root_details(self):
 		doc_before_save = self.get_doc_before_save()
 
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index c03b18a..083c8fc 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -120,18 +120,6 @@
 	statement_dict = {}
 	ageing = ""
 
-	err_journals = None
-	if doc.report == "General Ledger" and doc.ignore_exchange_rate_revaluation_journals:
-		err_journals = frappe.db.get_all(
-			"Journal Entry",
-			filters={
-				"company": doc.company,
-				"docstatus": 1,
-				"voucher_type": ("in", ["Exchange Rate Revaluation", "Exchange Gain Or Loss"]),
-			},
-			as_list=True,
-		)
-
 	for entry in doc.customers:
 		if doc.include_ageing:
 			ageing = set_ageing(doc, entry)
@@ -144,8 +132,8 @@
 		)
 
 		filters = get_common_filters(doc)
-		if err_journals:
-			filters.update({"voucher_no_not_in": [x[0] for x in err_journals]})
+		if doc.ignore_exchange_rate_revaluation_journals:
+			filters.update({"ignore_err": True})
 
 		if doc.report == "General Ledger":
 			filters.update(get_gl_filters(doc, entry, tax_id, presentation_currency))
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 79b5e4d..b7b9d34 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -203,8 +203,14 @@
 			"fieldname": "show_remarks",
 			"label": __("Show Remarks"),
 			"fieldtype": "Check"
+		},
+		{
+			"fieldname": "ignore_err",
+			"label": __("Ignore Exchange Rate Revaluation Journals"),
+			"fieldtype": "Check"
 		}
 
+
 	]
 }
 
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 110ec75..cea3a7b 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -241,6 +241,19 @@
 	if filters.get("against_voucher_no"):
 		conditions.append("against_voucher=%(against_voucher_no)s")
 
+	if filters.get("ignore_err"):
+		err_journals = frappe.db.get_all(
+			"Journal Entry",
+			filters={
+				"company": filters.get("company"),
+				"docstatus": 1,
+				"voucher_type": ("in", ["Exchange Rate Revaluation", "Exchange Gain Or Loss"]),
+			},
+			as_list=True,
+		)
+		if err_journals:
+			filters.update({"voucher_no_not_in": [x[0] for x in err_journals]})
+
 	if filters.get("voucher_no_not_in"):
 		conditions.append("voucher_no not in %(voucher_no_not_in)s")
 
diff --git a/erpnext/accounts/report/general_ledger/test_general_ledger.py b/erpnext/accounts/report/general_ledger/test_general_ledger.py
index a8c362e..75f9430 100644
--- a/erpnext/accounts/report/general_ledger/test_general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/test_general_ledger.py
@@ -3,7 +3,7 @@
 
 import frappe
 from frappe.tests.utils import FrappeTestCase
-from frappe.utils import today
+from frappe.utils import flt, today
 
 from erpnext.accounts.report.general_ledger.general_ledger import execute
 
@@ -148,3 +148,105 @@
 		self.assertEqual(data[2]["credit"], 900)
 		self.assertEqual(data[3]["debit"], 100)
 		self.assertEqual(data[3]["credit"], 100)
+
+	def test_ignore_exchange_rate_journals_filter(self):
+		# create a new account with USD currency
+		account_name = "Test Debtors USD"
+		company = "_Test Company"
+		account = frappe.get_doc(
+			{
+				"account_name": account_name,
+				"is_group": 0,
+				"company": company,
+				"root_type": "Asset",
+				"report_type": "Balance Sheet",
+				"account_currency": "USD",
+				"parent_account": "Accounts Receivable - _TC",
+				"account_type": "Receivable",
+				"doctype": "Account",
+			}
+		)
+		account.insert(ignore_if_duplicate=True)
+		# create a JV to debit 1000 USD at 75 exchange rate
+		jv = frappe.new_doc("Journal Entry")
+		jv.posting_date = today()
+		jv.company = company
+		jv.multi_currency = 1
+		jv.cost_center = "_Test Cost Center - _TC"
+		jv.set(
+			"accounts",
+			[
+				{
+					"account": account.name,
+					"party_type": "Customer",
+					"party": "_Test Customer USD",
+					"debit_in_account_currency": 1000,
+					"credit_in_account_currency": 0,
+					"exchange_rate": 75,
+					"cost_center": "_Test Cost Center - _TC",
+				},
+				{
+					"account": "Cash - _TC",
+					"debit_in_account_currency": 0,
+					"credit_in_account_currency": 75000,
+					"cost_center": "_Test Cost Center - _TC",
+				},
+			],
+		)
+		jv.save()
+		jv.submit()
+
+		revaluation = frappe.new_doc("Exchange Rate Revaluation")
+		revaluation.posting_date = today()
+		revaluation.company = company
+		accounts = revaluation.get_accounts_data()
+		revaluation.extend("accounts", accounts)
+		row = revaluation.accounts[0]
+		row.new_exchange_rate = 83
+		row.new_balance_in_base_currency = flt(
+			row.new_exchange_rate * flt(row.balance_in_account_currency)
+		)
+		row.gain_loss = row.new_balance_in_base_currency - flt(row.balance_in_base_currency)
+		revaluation.set_total_gain_loss()
+		revaluation = revaluation.save().submit()
+
+		# post journal entry for Revaluation doc
+		frappe.db.set_value(
+			"Company", company, "unrealized_exchange_gain_loss_account", "_Test Exchange Gain/Loss - _TC"
+		)
+		revaluation_jv = revaluation.make_jv_for_revaluation()
+		revaluation_jv.cost_center = "_Test Cost Center - _TC"
+		for acc in revaluation_jv.get("accounts"):
+			acc.cost_center = "_Test Cost Center - _TC"
+		revaluation_jv.save()
+		revaluation_jv.submit()
+
+		# With ignore_err enabled
+		columns, data = execute(
+			frappe._dict(
+				{
+					"company": company,
+					"from_date": today(),
+					"to_date": today(),
+					"account": [account.name],
+					"group_by": "Group by Voucher (Consolidated)",
+					"ignore_err": True,
+				}
+			)
+		)
+		self.assertNotIn(revaluation_jv.name, set([x.voucher_no for x in data]))
+
+		# Without ignore_err enabled
+		columns, data = execute(
+			frappe._dict(
+				{
+					"company": company,
+					"from_date": today(),
+					"to_date": today(),
+					"account": [account.name],
+					"group_by": "Group by Voucher (Consolidated)",
+					"ignore_err": False,
+				}
+			)
+		)
+		self.assertIn(revaluation_jv.name, set([x.voucher_no for x in data]))
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 8cb1a0e..3d7a947 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -98,6 +98,7 @@
 				item_doc = frappe.get_cached_doc("Item", item.item_code)
 				args = {
 					"net_rate": item.net_rate or item.rate,
+					"base_net_rate": item.base_net_rate or item.base_rate,
 					"tax_category": self.doc.get("tax_category"),
 					"posting_date": self.doc.get("posting_date"),
 					"bill_date": self.doc.get("bill_date"),
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 4ea834b..26795f7 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -502,6 +502,7 @@
 							project: item.project || me.frm.doc.project,
 							qty: item.qty || 1,
 							net_rate: item.rate,
+							base_net_rate: item.base_net_rate,
 							stock_qty: item.stock_qty,
 							conversion_factor: item.conversion_factor,
 							weight_per_unit: item.weight_per_unit,
@@ -1902,7 +1903,7 @@
 			if (item.item_code) {
 				// Use combination of name and item code in case same item is added multiple times
 				item_codes.push([item.item_code, item.name]);
-				item_rates[item.name] = item.net_rate;
+				item_rates[item.name] = item.base_net_rate;
 				item_tax_templates[item.name] = item.item_tax_template;
 			}
 		});
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index ebcdd11..bed5285 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -543,7 +543,7 @@
 		args = {
 			"company": company,
 			"tax_category": tax_category,
-			"net_rate": item_rates.get(item_code[1]),
+			"base_net_rate": item_rates.get(item_code[1]),
 		}
 
 		if item_tax_templates:
@@ -635,7 +635,7 @@
 	if not flt(tax.maximum_net_rate):
 		# No range specified, just ignore
 		return True
-	elif flt(tax.minimum_net_rate) <= flt(args.get("net_rate")) <= flt(tax.maximum_net_rate):
+	elif flt(tax.minimum_net_rate) <= flt(args.get("base_net_rate")) <= flt(tax.maximum_net_rate):
 		return True
 
 	return False