Merge pull request #40494 from ruthra-kumar/bank_statement_import_error

fix: AttributeError in Bank Statement Import
diff --git a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
index 8be09db..29732ef 100644
--- a/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
+++ b/erpnext/accounts/doctype/exchange_rate_revaluation/exchange_rate_revaluation.py
@@ -628,21 +628,21 @@
 	if account_balance and (
 		account_balance[0].balance or account_balance[0].balance_in_account_currency
 	):
-		account_with_new_balance = ExchangeRateRevaluation.calculate_new_account_balance(
+		if account_with_new_balance := ExchangeRateRevaluation.calculate_new_account_balance(
 			company, posting_date, account_balance
-		)
-		row = account_with_new_balance[0]
-		account_details.update(
-			{
-				"balance_in_base_currency": row["balance_in_base_currency"],
-				"balance_in_account_currency": row["balance_in_account_currency"],
-				"current_exchange_rate": row["current_exchange_rate"],
-				"new_exchange_rate": row["new_exchange_rate"],
-				"new_balance_in_base_currency": row["new_balance_in_base_currency"],
-				"new_balance_in_account_currency": row["new_balance_in_account_currency"],
-				"zero_balance": row["zero_balance"],
-				"gain_loss": row["gain_loss"],
-			}
-		)
+		):
+			row = account_with_new_balance[0]
+			account_details.update(
+				{
+					"balance_in_base_currency": row["balance_in_base_currency"],
+					"balance_in_account_currency": row["balance_in_account_currency"],
+					"current_exchange_rate": row["current_exchange_rate"],
+					"new_exchange_rate": row["new_exchange_rate"],
+					"new_balance_in_base_currency": row["new_balance_in_base_currency"],
+					"new_balance_in_account_currency": row["new_balance_in_account_currency"],
+					"zero_balance": row["zero_balance"],
+					"gain_loss": row["gain_loss"],
+				}
+			)
 
 	return account_details
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index ab50c38..961ee20 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -395,10 +395,6 @@
 				return {
 					query: "erpnext.controllers.queries.employee_query",
 				};
-			} else if (frm.doc.party_type == "Customer") {
-				return {
-					query: "erpnext.controllers.queries.customer_query",
-				};
 			}
 		});
 
diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json
index 60dd54c..3dae044 100644
--- a/erpnext/buying/doctype/supplier/supplier.json
+++ b/erpnext/buying/doctype/supplier/supplier.json
@@ -485,7 +485,7 @@
    "link_fieldname": "party"
   }
  ],
- "modified": "2023-10-19 16:55:15.148325",
+ "modified": "2024-03-13 11:14:06.516519",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Supplier",
@@ -544,7 +544,7 @@
   }
  ],
  "quick_entry": 1,
- "search_fields": "supplier_name, supplier_group",
+ "search_fields": "supplier_group",
  "show_name_in_global_search": 1,
  "sort_field": "modified",
  "sort_order": "ASC",
diff --git a/erpnext/buying/doctype/supplier/test_supplier.py b/erpnext/buying/doctype/supplier/test_supplier.py
index 350a25f..55974ea 100644
--- a/erpnext/buying/doctype/supplier/test_supplier.py
+++ b/erpnext/buying/doctype/supplier/test_supplier.py
@@ -154,44 +154,6 @@
 		# Rollback
 		address.delete()
 
-	def test_serach_fields_for_supplier(self):
-		from erpnext.controllers.queries import supplier_query
-
-		frappe.db.set_single_value("Buying Settings", "supp_master_name", "Naming Series")
-
-		supplier_name = create_supplier(supplier_name="Test Supplier 1").name
-
-		make_property_setter(
-			"Supplier", None, "search_fields", "supplier_group", "Data", for_doctype="Doctype"
-		)
-
-		data = supplier_query(
-			"Supplier", supplier_name, "name", 0, 20, filters={"name": supplier_name}, as_dict=True
-		)
-
-		self.assertEqual(data[0].name, supplier_name)
-		self.assertEqual(data[0].supplier_group, "Services")
-		self.assertTrue("supplier_type" not in data[0])
-
-		make_property_setter(
-			"Supplier",
-			None,
-			"search_fields",
-			"supplier_group, supplier_type",
-			"Data",
-			for_doctype="Doctype",
-		)
-		data = supplier_query(
-			"Supplier", supplier_name, "name", 0, 20, filters={"name": supplier_name}, as_dict=True
-		)
-
-		self.assertEqual(data[0].name, supplier_name)
-		self.assertEqual(data[0].supplier_group, "Services")
-		self.assertEqual(data[0].supplier_type, "Company")
-		self.assertTrue("supplier_type" in data[0])
-
-		frappe.db.set_single_value("Buying Settings", "supp_master_name", "Supplier Name")
-
 
 def create_supplier(**args):
 	args = frappe._dict(args)
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index bb1ed35..0de75d4 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -85,79 +85,6 @@
 		{"txt": "%%%s%%" % txt, "_txt": txt.replace("%", ""), "start": start, "page_len": page_len},
 	)
 
-	# searches for customer
-
-
-@frappe.whitelist()
-@frappe.validate_and_sanitize_search_inputs
-def customer_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
-	doctype = "Customer"
-	conditions = []
-	cust_master_name = frappe.defaults.get_user_default("cust_master_name")
-
-	fields = ["name"]
-	if cust_master_name != "Customer Name":
-		fields.append("customer_name")
-
-	fields = get_fields(doctype, fields)
-	searchfields = frappe.get_meta(doctype).get_search_fields()
-	searchfields = " or ".join(field + " like %(txt)s" for field in searchfields)
-
-	return frappe.db.sql(
-		"""select {fields} from `tabCustomer`
-		where docstatus < 2
-			and ({scond}) and disabled=0
-			{fcond} {mcond}
-		order by
-			(case when locate(%(_txt)s, name) > 0 then locate(%(_txt)s, name) else 99999 end),
-			(case when locate(%(_txt)s, customer_name) > 0 then locate(%(_txt)s, customer_name) else 99999 end),
-			idx desc,
-			name, customer_name
-		limit %(page_len)s offset %(start)s""".format(
-			**{
-				"fields": ", ".join(fields),
-				"scond": searchfields,
-				"mcond": get_match_cond(doctype),
-				"fcond": get_filters_cond(doctype, filters, conditions).replace("%", "%%"),
-			}
-		),
-		{"txt": "%%%s%%" % txt, "_txt": txt.replace("%", ""), "start": start, "page_len": page_len},
-		as_dict=as_dict,
-	)
-
-
-# searches for supplier
-@frappe.whitelist()
-@frappe.validate_and_sanitize_search_inputs
-def supplier_query(doctype, txt, searchfield, start, page_len, filters, as_dict=False):
-	doctype = "Supplier"
-	supp_master_name = frappe.defaults.get_user_default("supp_master_name")
-
-	fields = ["name"]
-	if supp_master_name != "Supplier Name":
-		fields.append("supplier_name")
-
-	fields = get_fields(doctype, fields)
-
-	return frappe.db.sql(
-		"""select {field} from `tabSupplier`
-		where docstatus < 2
-			and ({key} like %(txt)s
-			or supplier_name like %(txt)s) and disabled=0
-			and (on_hold = 0 or (on_hold = 1 and CURRENT_DATE > release_date))
-			{mcond}
-		order by
-			(case when locate(%(_txt)s, name) > 0 then locate(%(_txt)s, name) else 99999 end),
-			(case when locate(%(_txt)s, supplier_name) > 0 then locate(%(_txt)s, supplier_name) else 99999 end),
-			idx desc,
-			name, supplier_name
-		limit %(page_len)s offset %(start)s""".format(
-			**{"field": ", ".join(fields), "key": searchfield, "mcond": get_match_cond(doctype)}
-		),
-		{"txt": "%%%s%%" % txt, "_txt": txt.replace("%", ""), "start": start, "page_len": page_len},
-		as_dict=as_dict,
-	)
-
 
 @frappe.whitelist()
 @frappe.validate_and_sanitize_search_inputs
diff --git a/erpnext/controllers/tests/test_queries.py b/erpnext/controllers/tests/test_queries.py
index 3a3bc1c..c536d1c 100644
--- a/erpnext/controllers/tests/test_queries.py
+++ b/erpnext/controllers/tests/test_queries.py
@@ -31,18 +31,6 @@
 		self.assertGreaterEqual(len(query(txt="_Test Lead")), 4)
 		self.assertEqual(len(query(txt="_Test Lead 4")), 1)
 
-	def test_customer_query(self):
-		query = add_default_params(queries.customer_query, "Customer")
-
-		self.assertGreaterEqual(len(query(txt="_Test Customer")), 7)
-		self.assertGreaterEqual(len(query(txt="_Test Customer USD")), 1)
-
-	def test_supplier_query(self):
-		query = add_default_params(queries.supplier_query, "Supplier")
-
-		self.assertGreaterEqual(len(query(txt="_Test Supplier")), 7)
-		self.assertGreaterEqual(len(query(txt="_Test Supplier USD")), 1)
-
 	def test_item_query(self):
 		query = add_default_params(queries.item_query, "Item")
 
diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js
index 0b6cdf2..609eab7 100644
--- a/erpnext/crm/doctype/lead/lead.js
+++ b/erpnext/crm/doctype/lead/lead.js
@@ -17,10 +17,6 @@
 	}
 
 	onload() {
-		this.frm.set_query("customer", function (doc, cdt, cdn) {
-			return { query: "erpnext.controllers.queries.customer_query" };
-		});
-
 		this.frm.set_query("lead_owner", function (doc, cdt, cdn) {
 			return { query: "frappe.core.doctype.user.user.user_query" };
 		});
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 308e6ca..9b996fe 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -282,9 +282,6 @@
 
 before_tests = "erpnext.setup.utils.before_tests"
 
-standard_queries = {
-	"Customer": "erpnext.controllers.queries.customer_query",
-}
 
 period_closing_doctypes = [
 	"Sales Invoice",
diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py
index 4cd0530..2debf91 100644
--- a/erpnext/manufacturing/doctype/bom/test_bom.py
+++ b/erpnext/manufacturing/doctype/bom/test_bom.py
@@ -28,28 +28,6 @@
 
 class TestBOM(FrappeTestCase):
 	@timeout
-	def test_bom_qty(self):
-		from erpnext.stock.doctype.item.test_item import make_item
-
-		# No error.
-		bom = frappe.new_doc("BOM")
-		item = make_item(properties={"is_stock_item": 1})
-		bom.item = fg_item.item_code
-		bom.quantity = 1
-		bom.append(
-			"items",
-			{
-				"item_code": bom_item.item_code,
-				"qty": 0,
-				"uom": bom_item.stock_uom,
-				"stock_uom": bom_item.stock_uom,
-				"rate": 100.0,
-			},
-		)
-		bom.save()
-		self.assertEqual(bom.items[0].qty, 0)
-
-	@timeout
 	def test_get_items(self):
 		from erpnext.manufacturing.doctype.bom.bom import get_bom_items_as_dict
 
diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js
index 16ac8db..49e8d84 100644
--- a/erpnext/projects/doctype/project/project.js
+++ b/erpnext/projects/doctype/project/project.js
@@ -27,8 +27,6 @@
 			};
 		};
 
-		frm.set_query("customer", "erpnext.controllers.queries.customer_query");
-
 		frm.set_query("user", "users", function () {
 			return {
 				query: "erpnext.projects.doctype.project.project.get_users_for_project",
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index 1d0d47e..934becf 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -74,11 +74,6 @@
 				me.frm.set_query('billing_address', erpnext.queries.company_address_query);
 				erpnext.accounts.dimensions.setup_dimension_filters(me.frm, me.frm.doctype);
 
-				if(this.frm.fields_dict.supplier) {
-					this.frm.set_query("supplier", function() {
-						return{	query: "erpnext.controllers.queries.supplier_query" }});
-				}
-
 				this.frm.set_query("item_code", "items", function() {
 					if (me.frm.doc.is_subcontracted) {
 						var filters = {'supplier': me.frm.doc.supplier};
diff --git a/erpnext/public/js/queries.js b/erpnext/public/js/queries.js
index b7e685c..d7edac3 100644
--- a/erpnext/public/js/queries.js
+++ b/erpnext/public/js/queries.js
@@ -12,14 +12,6 @@
 		return { query: "erpnext.controllers.queries.lead_query" };
 	},
 
-	customer: function () {
-		return { query: "erpnext.controllers.queries.customer_query" };
-	},
-
-	supplier: function () {
-		return { query: "erpnext.controllers.queries.supplier_query" };
-	},
-
 	item: function (filters) {
 		var args = { query: "erpnext.controllers.queries.item_query" };
 		if (filters) args["filters"] = filters;
diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json
index db712d9..41c6311 100644
--- a/erpnext/selling/doctype/customer/customer.json
+++ b/erpnext/selling/doctype/customer/customer.json
@@ -583,7 +583,7 @@
    "link_fieldname": "party"
   }
  ],
- "modified": "2023-12-28 13:15:36.298369",
+ "modified": "2024-03-16 19:41:47.971815",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Customer",
@@ -661,7 +661,7 @@
   }
  ],
  "quick_entry": 1,
- "search_fields": "customer_name,customer_group,territory, mobile_no,primary_address",
+ "search_fields": "customer_group,territory, mobile_no,primary_address",
  "show_name_in_global_search": 1,
  "sort_field": "modified",
  "sort_order": "DESC",
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index a8ebccd..7e6d6de 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -370,37 +370,6 @@
 		due_date = get_due_date("2017-01-22", "Customer", "_Test Customer")
 		self.assertEqual(due_date, "2017-01-22")
 
-	def test_serach_fields_for_customer(self):
-		from erpnext.controllers.queries import customer_query
-
-		frappe.db.set_single_value("Selling Settings", "cust_master_name", "Naming Series")
-
-		make_property_setter(
-			"Customer", None, "search_fields", "customer_group", "Data", for_doctype="Doctype"
-		)
-
-		data = customer_query(
-			"Customer", "_Test Customer", "", 0, 20, filters={"name": "_Test Customer"}, as_dict=True
-		)
-
-		self.assertEqual(data[0].name, "_Test Customer")
-		self.assertEqual(data[0].customer_group, "_Test Customer Group")
-		self.assertTrue("territory" not in data[0])
-
-		make_property_setter(
-			"Customer", None, "search_fields", "customer_group, territory", "Data", for_doctype="Doctype"
-		)
-		data = customer_query(
-			"Customer", "_Test Customer", "", 0, 20, filters={"name": "_Test Customer"}, as_dict=True
-		)
-
-		self.assertEqual(data[0].name, "_Test Customer")
-		self.assertEqual(data[0].customer_group, "_Test Customer Group")
-		self.assertEqual(data[0].territory, "_Test Territory")
-		self.assertTrue("territory" in data[0])
-
-		frappe.db.set_single_value("Selling Settings", "cust_master_name", "Customer Name")
-
 	def test_parse_full_name(self):
 		first, middle, last = parse_full_name("John")
 		self.assertEqual(first, "John")
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 9fcda0d..f7e65e0 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -2206,13 +2206,14 @@
 	return so
 
 
-def create_dn_against_so(so, delivered_qty=0):
+def create_dn_against_so(so, delivered_qty=0, do_not_submit=False):
 	frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 1)
 
 	dn = make_delivery_note(so)
 	dn.get("items")[0].qty = delivered_qty or 5
 	dn.insert()
-	dn.submit()
+	if not do_not_submit:
+		dn.submit()
 	return dn
 
 
diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js
index d95ef58..fbee9c1 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_cart.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js
@@ -295,10 +295,10 @@
 			<div class="customer-field"></div>
 		`);
 		const me = this;
-		const query = { query: "erpnext.controllers.queries.customer_query" };
 		const allowed_customer_group = this.allowed_customer_groups || [];
+		let filters = {};
 		if (allowed_customer_group.length) {
-			query.filters = {
+			filters = {
 				customer_group: ["in", allowed_customer_group],
 			};
 		}
@@ -308,7 +308,11 @@
 				fieldtype: "Link",
 				options: "Customer",
 				placeholder: __("Search by customer name, phone, email."),
-				get_query: () => query,
+				get_query: function () {
+					return {
+						filters: filters,
+					};
+				},
 				onchange: function () {
 					if (this.value) {
 						const frm = me.events.get_frm();
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 0d2d207..2f52f21 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -251,6 +251,7 @@
 	def validate(self):
 		self.validate_posting_time()
 		super(DeliveryNote, self).validate()
+		self.validate_references()
 		self.set_status()
 		self.so_required()
 		self.validate_proj_cust()
@@ -341,6 +342,58 @@
 
 					item.serial_and_batch_bundle = cls_obj.serial_and_batch_bundle
 
+	def validate_references(self):
+		self.validate_sales_order_references()
+		self.validate_sales_invoice_references()
+
+	def validate_sales_order_references(self):
+		err_msg = ""
+		for item in self.items:
+			if (item.against_sales_order and not item.so_detail) or (
+				not item.against_sales_order and item.so_detail
+			):
+				if not item.against_sales_order:
+					err_msg += (
+						_("'Sales Order' reference ({1}) is missing in row {0}").format(
+							frappe.bold(item.idx), frappe.bold("against_sales_order")
+						)
+						+ "<br>"
+					)
+				else:
+					err_msg += (
+						_("'Sales Order Item' reference ({1}) is missing in row {0}").format(
+							frappe.bold(item.idx), frappe.bold("so_detail")
+						)
+						+ "<br>"
+					)
+
+		if err_msg:
+			frappe.throw(err_msg, title=_("References to Sales Orders are Incomplete"))
+
+	def validate_sales_invoice_references(self):
+		err_msg = ""
+		for item in self.items:
+			if (item.against_sales_invoice and not item.si_detail) or (
+				not item.against_sales_invoice and item.si_detail
+			):
+				if not item.against_sales_invoice:
+					err_msg += (
+						_("'Sales Invoice' reference ({1}) is missing in row {0}").format(
+							frappe.bold(item.idx), frappe.bold("against_sales_invoice")
+						)
+						+ "<br>"
+					)
+				else:
+					err_msg += (
+						_("'Sales Invoice Item' reference ({1}) is missing in row {0}").format(
+							frappe.bold(item.idx), frappe.bold("si_detail")
+						)
+						+ "<br>"
+					)
+
+		if err_msg:
+			frappe.throw(err_msg, title=_("References to Sales Invoices are Incomplete"))
+
 	def validate_proj_cust(self):
 		"""check for does customer belong to same project as entered.."""
 		if self.project and self.customer:
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 293ef9f..434e001 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -824,6 +824,15 @@
 		dn.cancel()
 		self.assertEqual(dn.status, "Cancelled")
 
+	def test_sales_order_reference_validation(self):
+		so = make_sales_order(po_no="12345")
+		dn = create_dn_against_so(so.name, delivered_qty=2, do_not_submit=True)
+		dn.items[0].against_sales_order = None
+		self.assertRaises(frappe.ValidationError, dn.save)
+		dn.reload()
+		dn.items[0].so_detail = None
+		self.assertRaises(frappe.ValidationError, dn.save)
+
 	def test_dn_billing_status_case1(self):
 		# SO -> DN -> SI
 		so = make_sales_order(po_no="12345")
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 7a38024..5310a0f 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -406,14 +406,6 @@
 			};
 		};
 
-		frm.fields_dict.customer_items.grid.get_field("customer_name").get_query = function (doc, cdt, cdn) {
-			return { query: "erpnext.controllers.queries.customer_query" };
-		};
-
-		frm.fields_dict.supplier_items.grid.get_field("supplier").get_query = function (doc, cdt, cdn) {
-			return { query: "erpnext.controllers.queries.supplier_query" };
-		};
-
 		frm.fields_dict["item_defaults"].grid.get_field("default_warehouse").get_query = function (
 			doc,
 			cdt,