mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-13 14:41:53 +00:00
Merge pull request #56105 from mihir-kandoi/pg-parity-other-class
fix(postgres): MariaDB/Postgres parity in pick-list, serial match, null ordering & link-query ranking
This commit is contained in:
@@ -6,7 +6,7 @@ import frappe
|
||||
from frappe import _, bold
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.mapper import map_child_doc, map_doc
|
||||
from frappe.query_builder.functions import IfNull, Sum
|
||||
from frappe.query_builder.functions import IfNull, Lower, Sum
|
||||
from frappe.utils import cint, flt, get_link_to_form, getdate, nowdate
|
||||
from frappe.utils.nestedset import get_descendants_of
|
||||
|
||||
@@ -505,16 +505,20 @@ class POSInvoice(SalesInvoice):
|
||||
if d.get("serial_no"):
|
||||
serial_nos = get_serial_nos(d.serial_no)
|
||||
for sr in serial_nos:
|
||||
serial_no_exists = frappe.get_all(
|
||||
"POS Invoice Item",
|
||||
filters={"parent": self.return_against},
|
||||
or_filters=[
|
||||
["serial_no", "=", sr],
|
||||
["serial_no", "like", f"{sr}\n%"],
|
||||
["serial_no", "like", f"%\n{sr}"],
|
||||
["serial_no", "like", f"%\n{sr}\n%"],
|
||||
],
|
||||
limit=1,
|
||||
POI = frappe.qb.DocType("POS Invoice Item")
|
||||
s = sr.lower()
|
||||
serial_no_exists = (
|
||||
frappe.qb.from_(POI)
|
||||
.select(POI.name)
|
||||
.where(POI.parent == self.return_against)
|
||||
.where(
|
||||
(Lower(POI.serial_no) == s)
|
||||
| Lower(POI.serial_no).like(f"{s}\n%")
|
||||
| Lower(POI.serial_no).like(f"%\n{s}")
|
||||
| Lower(POI.serial_no).like(f"%\n{s}\n%")
|
||||
)
|
||||
.limit(1)
|
||||
.run()
|
||||
)
|
||||
|
||||
if not serial_no_exists:
|
||||
|
||||
@@ -10,7 +10,7 @@ from frappe import qb, scrub
|
||||
from frappe.desk.reportview import get_filters_cond, get_match_cond
|
||||
from frappe.permissions import has_permission
|
||||
from frappe.query_builder import Case, Criterion, DocType
|
||||
from frappe.query_builder.functions import Concat, CustomFunction, Length, Locate, Substring, Sum
|
||||
from frappe.query_builder.functions import Concat, CustomFunction, Length, Locate, Lower, Substring, Sum
|
||||
from frappe.utils import nowdate, today, unique
|
||||
from pypika import Order
|
||||
|
||||
@@ -313,11 +313,19 @@ def item_query(
|
||||
.where(date_condition)
|
||||
.where(Criterion.any(search_conditions))
|
||||
.orderby(
|
||||
Case().when(Locate(txt_no_percent, item.name) > 0, Locate(txt_no_percent, item.name)).else_(99999)
|
||||
Case()
|
||||
.when(
|
||||
Locate(Lower(txt_no_percent), Lower(item.name)) > 0,
|
||||
Locate(Lower(txt_no_percent), Lower(item.name)),
|
||||
)
|
||||
.else_(99999)
|
||||
)
|
||||
.orderby(
|
||||
Case()
|
||||
.when(Locate(txt_no_percent, item.item_name) > 0, Locate(txt_no_percent, item.item_name))
|
||||
.when(
|
||||
Locate(Lower(txt_no_percent), Lower(item.item_name)) > 0,
|
||||
Locate(Lower(txt_no_percent), Lower(item.item_name)),
|
||||
)
|
||||
.else_(99999)
|
||||
)
|
||||
.orderby(item.idx, order=Order.desc)
|
||||
@@ -406,7 +414,13 @@ def get_project_name(
|
||||
# ordering
|
||||
if txt:
|
||||
# project_name containing search string 'txt' will be given higher precedence
|
||||
q = q.orderby(ifelse(Locate(txt, proj.project_name) > 0, Locate(txt, proj.project_name), 99999))
|
||||
q = q.orderby(
|
||||
ifelse(
|
||||
Locate(Lower(txt), Lower(proj.project_name)) > 0,
|
||||
Locate(Lower(txt), Lower(proj.project_name)),
|
||||
99999,
|
||||
)
|
||||
)
|
||||
q = q.orderby(proj.idx, order=Order.desc).orderby(proj.name)
|
||||
|
||||
if page_len:
|
||||
|
||||
@@ -124,13 +124,16 @@ def get_communication_details(filters):
|
||||
FROM
|
||||
`tabCommunication`
|
||||
WHERE
|
||||
recipients = %s
|
||||
recipients = %s AND communication_date IS NOT NULL
|
||||
ORDER BY
|
||||
communication_date
|
||||
LIMIT 1
|
||||
""",
|
||||
(d.contact_email),
|
||||
)[0][0]
|
||||
)
|
||||
first_contact = first_contact[0][0] if first_contact else None
|
||||
if not first_contact:
|
||||
continue
|
||||
|
||||
duration = flt(date_diff(invoice[0][0], first_contact))
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import frappe
|
||||
from frappe import _, bold
|
||||
from frappe.model.document import Document
|
||||
from frappe.query_builder import Case
|
||||
from frappe.query_builder.functions import Coalesce, GroupConcat, Locate, Max, Replace, Sum
|
||||
from frappe.query_builder.functions import Coalesce, GroupConcat, Locate, Lower, Max, Replace, Sum
|
||||
from frappe.utils import cint, floor, flt, get_link_to_form
|
||||
from frappe.utils.nestedset import get_descendants_of
|
||||
|
||||
@@ -1301,7 +1301,11 @@ def get_pending_work_orders(
|
||||
& (wo.company == filters.get("company"))
|
||||
& (wo.name.like(f"%{txt}%"))
|
||||
)
|
||||
.orderby(Case().when(Locate(txt, wo.name) > 0, Locate(txt, wo.name)).else_(99999))
|
||||
.orderby(
|
||||
Case()
|
||||
.when(Locate(Lower(txt), Lower(wo.name)) > 0, Locate(Lower(txt), Lower(wo.name)))
|
||||
.else_(99999)
|
||||
)
|
||||
.orderby(wo.name)
|
||||
.limit(cint(page_length))
|
||||
.offset(start)
|
||||
@@ -1372,7 +1376,10 @@ def get_pick_list_query(doctype: Any, txt: str, searchfield: Any, start: int, pa
|
||||
.where(PICK_LIST.status.isin(["Open", "Partly Delivered"]))
|
||||
.where(PICK_LIST.company == filters.get("company"))
|
||||
.where(SALES_ORDER.customer == filters.get("customer"))
|
||||
.groupby(PICK_LIST.name)
|
||||
# customer is from the joined Sales Order, not Pick List's PK, so Postgres rejects it as a bare
|
||||
# select under GROUP BY pick_list.name; it is pinned to one value by the filter above, so adding
|
||||
# it to the GROUP BY is valid on Postgres and identical on MariaDB.
|
||||
.groupby(PICK_LIST.name, SALES_ORDER.customer)
|
||||
)
|
||||
|
||||
if filters.get("sales_order"):
|
||||
|
||||
@@ -1964,3 +1964,23 @@ class TestPickList(ERPNextTestSuite):
|
||||
item_codes = [item.item_code for item in doc.items]
|
||||
self.assertIn(item1, item_codes)
|
||||
self.assertIn(item2, item_codes)
|
||||
|
||||
def test_get_pick_list_query_postgres_valid(self):
|
||||
"""get_pick_list_query selects Sales Order.customer (a joined-table column) under
|
||||
GROUP BY Pick List.name. Postgres rejects that bare column (PK functional dependency does
|
||||
not cross tables), so the link query raised GroupingError. customer is pinned to one value
|
||||
by the filter, so adding it to the GROUP BY is identical on MariaDB and valid on Postgres."""
|
||||
from erpnext.stock.doctype.pick_list.pick_list import get_pick_list_query
|
||||
|
||||
warehouse = "_Test Warehouse - _TC"
|
||||
item = make_item().name
|
||||
make_stock_entry(item=item, to_warehouse=warehouse, qty=100, basic_rate=100)
|
||||
so = make_sales_order(item_code=item, qty=5, rate=100)
|
||||
pl = create_pick_list(so.name)
|
||||
pl.submit()
|
||||
|
||||
# must run without raising on either engine (GroupingError on Postgres before the fix)
|
||||
result = get_pick_list_query(
|
||||
"Pick List", "", "name", 0, 20, {"company": so.company, "customer": so.customer}
|
||||
)
|
||||
self.assertIn(pl.name, [row["name"] for row in result])
|
||||
|
||||
Reference in New Issue
Block a user