fix(postgres): satisfy strict GROUP BY in Deferred Revenue And Expense report

Wrap the non-aggregated, functionally-dependent column(s) in Max()/Min() (or add
them to GROUP BY) so the report's grouped query is valid under PostgreSQL's strict
GROUP BY. No behaviour change on MariaDB.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mihir Kandoi
2026-06-17 13:18:56 +05:30
parent 3faaa87645
commit 24a66d10e7

View File

@@ -3,7 +3,8 @@
import frappe
from frappe import _, qb
from frappe.query_builder import Column, functions
from frappe.query_builder import functions
from frappe.query_builder.custom import ConstantColumn
from frappe.utils import add_days, date_diff, flt, get_first_day, get_last_day, getdate, rounded
from erpnext.accounts.report.financial_statements import get_period_list
@@ -300,8 +301,10 @@ class Deferred_Revenue_and_Expense_Report:
Get all sales and purchase invoices which has deferred revenue/expense items
"""
gle = qb.DocType("GL Entry")
# column doesn't have an alias option
posted = Column("posted")
# a literal marker: real GL rows are "posted" (dummy/simulated future entries use "not").
# ConstantColumn renders a single-quoted string literal, valid on both backends -- a plain
# Column rendered as "posted", which MySQL reads as the string but postgres as an identifier.
posted = ConstantColumn("posted").as_("posted")
if self.filters.type == "Revenue":
inv = qb.DocType("Sales Invoice")
@@ -327,13 +330,15 @@ class Deferred_Revenue_and_Expense_Report:
)
.select(
inv.name.as_("doc"),
inv.posting_date,
# non-grouped columns are constant per grouped invoice / invoice item -> Max() keeps the
# GROUP BY valid on postgres while returning the same value MySQL picked.
functions.Max(inv.posting_date).as_("posting_date"),
inv_item.name.as_("item"),
inv_item.item_name,
inv_item.service_start_date,
inv_item.service_end_date,
inv_item.base_net_amount,
deferred_account_field,
functions.Max(inv_item.item_name).as_("item_name"),
functions.Max(inv_item.service_start_date).as_("service_start_date"),
functions.Max(inv_item.service_end_date).as_("service_end_date"),
functions.Max(inv_item.base_net_amount).as_("base_net_amount"),
functions.Max(deferred_account_field).as_(deferred_account_field.name),
gle.posting_date.as_("gle_posting_date"),
functions.Sum(gle.debit).as_("debit"),
functions.Sum(gle.credit).as_("credit"),