From 8b4845d27283bc44bf612166e3e511d960603957 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Sun, 21 Jun 2026 04:40:33 +0530 Subject: [PATCH] fix(buying): make Procurement Tracker GROUP BY Postgres-valid get_po_entries() grouped only by (Purchase Order, material_request_item) while selecting other Purchase Order Item columns. MariaDB allows this loose GROUP BY (arbitrary-picking the extra columns); Postgres rejects it with "column ... must appear in the GROUP BY clause". Add the Purchase Order Item PK (child.name) to the GROUP BY so the selected child columns are functionally determined by a grouped key. Behaviour note: this is not a MariaDB no-op. When one PO has multiple items sharing the same/blank material_request_item, MariaDB collapsed them into one arbitrary row; now there is one row per PO line. The downstream report already keys rows by purchase_order, so totals are unaffected and the per-line breakdown is more correct. Adds a test that runs the report and asserts the PO is listed, exercising the GROUP BY on both engines. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../procurement_tracker/procurement_tracker.py | 4 +++- .../test_procurement_tracker.py | 14 +++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/erpnext/buying/report/procurement_tracker/procurement_tracker.py b/erpnext/buying/report/procurement_tracker/procurement_tracker.py index 10169c554fb..fd30ddf6884 100644 --- a/erpnext/buying/report/procurement_tracker/procurement_tracker.py +++ b/erpnext/buying/report/procurement_tracker/procurement_tracker.py @@ -305,7 +305,9 @@ def get_po_entries(filters): & (parent.name == child.parent) & (parent.status.notin(("Closed", "Completed", "Cancelled"))) ) - .groupby(parent.name, child.material_request_item) + # This is one row per PO item; the selected child.* columns are only functionally dependent + # on the child PK, which postgres requires in the GROUP BY (MariaDB allows omitting it). + .groupby(parent.name, child.material_request_item, child.name) ) query = apply_filters_on_query(filters, parent, child, query) diff --git a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py index 1577bf2cbf6..f1781c15e05 100644 --- a/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py +++ b/erpnext/buying/report/procurement_tracker/test_procurement_tracker.py @@ -6,4 +6,16 @@ from erpnext.tests.utils import ERPNextTestSuite class TestProcurementTracker(ERPNextTestSuite): - pass + def test_report_executes_and_lists_po(self): + # get_po_entries groups by (Purchase Order, material_request_item, Purchase Order Item) + # while selecting other child columns; this exercises that GROUP BY so the report stays + # valid on Postgres (which rejects selecting non-grouped columns). + from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order + from erpnext.buying.report.procurement_tracker.procurement_tracker import execute + + po = create_purchase_order(company="_Test Company") + + columns, data = execute({"company": "_Test Company"}) + + self.assertTrue(columns) + self.assertIn(po.name, {row.get("purchase_order") for row in data})