From fe13c0709b5fb2aff11f51a29e863c9d65101bf3 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Fri, 19 Jun 2026 16:15:28 +0530 Subject: [PATCH] refactor(postgres): port pending_so_items_for_purchase_request report to the query builder Co-Authored-By: Claude Opus 4.8 (1M context) --- .../pending_so_items_for_purchase_request.py | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py index 82143a11eea..7d7ea42209f 100644 --- a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py +++ b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py @@ -4,6 +4,7 @@ import frappe from frappe import _ +from frappe.query_builder.functions import Max, Sum from frappe.utils import flt @@ -49,27 +50,28 @@ def get_columns(): def get_data(): - sales_order_entry = frappe.db.sql( - """ - SELECT + so = frappe.qb.DocType("Sales Order") + so_item = frappe.qb.DocType("Sales Order Item") + sales_order_entry = ( + frappe.qb.from_(so) + .inner_join(so_item) + .on(so.name == so_item.parent) + .select( so_item.item_code, - so_item.item_name, - so_item.description, + # non-grouped columns are constant per grouped so.name / item_code -> Max() keeps the + # GROUP BY valid on postgres while returning the same value MySQL picked. + Max(so_item.item_name).as_("item_name"), + Max(so_item.description).as_("description"), so.name, - so.transaction_date, - so.customer, - so.territory, - sum(so_item.qty) as total_qty, - so.company - FROM `tabSales Order` so, `tabSales Order Item` so_item - WHERE - so.docstatus = 1 - and so.name = so_item.parent - and so.status not in ('Closed','Completed','Cancelled') - GROUP BY - so.name,so_item.item_code - """, - as_dict=1, + Max(so.transaction_date).as_("transaction_date"), + Max(so.customer).as_("customer"), + Max(so.territory).as_("territory"), + Sum(so_item.qty).as_("total_qty"), + Max(so.company).as_("company"), + ) + .where((so.docstatus == 1) & so.status.notin(["Closed", "Completed", "Cancelled"])) + .groupby(so.name, so_item.item_code) + .run(as_dict=1) ) sales_orders = [row.name for row in sales_order_entry]