diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 29ed697ccaf..4856bb28e08 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -10,6 +10,7 @@ from frappe import qb, scrub from frappe.permissions import has_permission from frappe.query_builder import Case, Criterion, DocType from frappe.query_builder.functions import ( + Cast_, Concat, IfNull, Length, @@ -1143,7 +1144,8 @@ def get_filtered_child_rows( if txt: txt += "%" query = query.where( - ((table.idx.like(txt.replace("#", ""))) | (table.item_code.like(txt))) | (table.name.like(txt)) + ((Cast_(table.idx, "varchar").like(txt.replace("#", ""))) | (table.item_code.like(txt))) + | (table.name.like(txt)) ) return query.run(as_dict=False) diff --git a/erpnext/controllers/tests/test_queries.py b/erpnext/controllers/tests/test_queries.py index 43603d2a6e7..ff48ad7ed1d 100644 --- a/erpnext/controllers/tests/test_queries.py +++ b/erpnext/controllers/tests/test_queries.py @@ -93,6 +93,34 @@ class TestQueries(ERPNextTestSuite): query = add_default_params(queries.get_purchase_invoices, "Purchase Invoice") self.assertIsInstance(query(txt="", filters={}), list | tuple) + def test_get_filtered_child_rows_query(self): + # idx is an integer column. Searching child rows by it must run on Postgres + # (a bare LIKE rejects "bigint ILIKE text") AND cast to a full-length string: + # CAST(idx AS CHAR) is character(1) on Postgres, so a two-digit idx like 11 + # would render as "1" and be missed. Build a Sales Order with >10 rows and + # search for row 11 to lock both behaviours. + from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order + + frappe.db.set_single_value("Selling Settings", "allow_multiple_items", 1) + so = make_sales_order( + item_list=[ + {"item_code": "_Test Item", "qty": 1, "rate": 100, "warehouse": "_Test Warehouse - _TC"} + for _ in range(11) + ], + do_not_submit=True, + ) + + rows = queries.get_filtered_child_rows( + "Sales Order Item", + txt="#11", + searchfield="name", + start=0, + page_len=20, + filters={"parent": so.name}, + ) + # row label is "#, "; row 11 must be present + self.assertTrue(any(str(label).startswith("#11,") for _name, label in rows)) + def test_default_uoms(self): self.assertGreaterEqual(frappe.db.count("UOM", {"enabled": 1}), 10) diff --git a/erpnext/edi/doctype/code_list/code_list.py b/erpnext/edi/doctype/code_list/code_list.py index e723157e7a0..b816f7dc3e7 100644 --- a/erpnext/edi/doctype/code_list/code_list.py +++ b/erpnext/edi/doctype/code_list/code_list.py @@ -116,7 +116,7 @@ def get_docnames_for(code_list: str, doctype: str, code: str) -> tuple[str]: & (CommonCode.code_list == code_list) ) .distinct() - .orderby(DynamicLink.idx) + .orderby(DynamicLink.link_name) ).run() return tuple(d[0] for d in docnames) if docnames else () diff --git a/erpnext/regional/united_arab_emirates/utils.py b/erpnext/regional/united_arab_emirates/utils.py index 671f726a740..2fb01117fcf 100644 --- a/erpnext/regional/united_arab_emirates/utils.py +++ b/erpnext/regional/united_arab_emirates/utils.py @@ -77,7 +77,7 @@ def get_account_currency(account): def get_tax_accounts(company): """Get the list of tax accounts for a specific company.""" tax_accounts_dict = frappe._dict() - tax_accounts_list = frappe.get_all("UAE VAT Account", filters={"parent": company}, fields=["Account"]) + tax_accounts_list = frappe.get_all("UAE VAT Account", filters={"parent": company}, fields=["account"]) if not tax_accounts_list and not frappe.in_test: frappe.throw(_('Please set Vat Accounts for Company: "{0}" in UAE VAT Settings').format(company)) diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py index f6abae53f5e..52ea26d4383 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -822,6 +822,8 @@ def get_opening_balance_for_inv_dimension(filters, inv_dimension_wise_value): else: query = query.where(sl_doctype[key] == value) + query = query.groupby(sl_doctype.item_code, sl_doctype.warehouse) + opening_data = query.run(as_dict=True) if opening_data: