Files
erpnext/erpnext/projects/utils.py
Mihir Kandoi ea665d1a9b refactor(postgres): port Projects module queries to the query builder
Convert raw `frappe.db.sql` across the Projects module to `frappe.qb` / the ORM
so the same code runs on MariaDB and Postgres. Behaviour is preserved on
MariaDB; the conversions also make these paths valid under Postgres' stricter
SQL (GROUP BY, case-sensitivity, empty-string handling).

Conversions of note (behaviour kept identical to the MariaDB original):
- project.get_users_for_project: search selects the stored full_name instead of
  concat_ws(first, middle, last) (concat_ws diverges on Postgres, where empty
  Data fields are NULL) and wraps Locate in LOWER() to keep MariaDB's
  case-insensitive result ordering.
- project costing: percent-complete and sales/billed-amount aggregates rebuilt
  as Sum() query-builder selects.
- task.reschedule_dependent_tasks: the correlated subquery is split into a
  `Task Depends On` parent-pluck + a Task lookup (same rows, no nested SQL).
- timesheet.get_events: user-permission match conditions move to the query-builder
  form via get_event_conditions_qb; calendar columns rebuilt with Concat/Round.
- report/project_wise_stock_tracking & report/daily_timesheet_summary: GROUP BY
  cost aggregates and the timesheet date window (timestamp(to_date,'24:00:00') ->
  end-of-day via get_combine_datetime) rebuilt to satisfy Postgres.
- search helpers (query_task, get_project, get_timesheet) use frappe.qb.get_query
  with ignore_permissions=False in place of build_match_conditions/get_match_cond.

Tests (run on both MariaDB and Postgres, --lightmode):
- Existing project/task/timesheet/activity_cost suites kept green (27 tests).
- New project_wise_stock_tracking test drives all three cost aggregates with
  positive data (purchased / issued / delivered GROUP BY) plus get_project_details.
- New daily_timesheet_summary test covers the date-window join.

Not included: project_update.py is deferred. Its daily_reminder()/email_sending()
select `progress`/`progress_details`, columns that do not exist on the Project
Update doctype, so the function errors when invoked regardless of backend - a
pre-existing bug that needs an email-rework, not just a query port.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 15:22:20 +05:30

30 lines
908 B
Python

# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
# For license information, please see license.txt
import frappe
from frappe.query_builder import Case
@frappe.whitelist()
@frappe.validate_and_sanitize_search_inputs
def query_task(doctype: str, txt: str, searchfield: str, start: int, page_len: int, filters: dict):
search_str = f"%{txt}%"
prefix_str = f"{txt}%"
Task = frappe.qb.DocType("Task")
query = frappe.qb.get_query("Task", fields=["name", "subject"], ignore_permissions=False)
return (
query.where(Task[searchfield].like(search_str) | Task.subject.like(search_str))
.orderby(Case().when(Task.subject.like(prefix_str), 0).else_(1))
.orderby(Case().when(Task[searchfield].like(prefix_str), 0).else_(1))
.orderby(Task[searchfield])
.orderby(Task.subject)
.limit(page_len)
.offset(start)
.run()
)