From 4d29bfbe0702dd6fdc5d32da0eed387f02c8d2f2 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Sat, 20 Jun 2026 21:53:50 +0530 Subject: [PATCH] fix(stock): make Job Card secondary-item query Postgres-valid (GROUP BY) get_secondary_items_from_job_card selected item_name/description/stock_uom/ bom_secondary_item alongside `group by item_code, secondary_item_type` (and an orderby on the non-grouped idx) -> arbitrary pick on MariaDB, GroupingError on Postgres. Wrap the non-grouped columns in Max() (Min(idx) for the orderby); they are item attributes / the secondary-item BOM link, constant per group, so MariaDB output is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../doctype/stock_entry/services/manufacturing.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/services/manufacturing.py b/erpnext/stock/doctype/stock_entry/services/manufacturing.py index f61b667380c..b3455c40b51 100644 --- a/erpnext/stock/doctype/stock_entry/services/manufacturing.py +++ b/erpnext/stock/doctype/stock_entry/services/manufacturing.py @@ -3,7 +3,7 @@ from collections import defaultdict import frappe from frappe import _, bold -from frappe.query_builder.functions import Sum +from frappe.query_builder.functions import Max, Min, Sum from frappe.utils import ceil, cint, flt, get_link_to_form from erpnext.manufacturing.doctype.bom.bom import add_additional_cost @@ -1005,11 +1005,14 @@ def get_secondary_items_from_job_card(work_order, jc_name=None): .select( Sum(job_card_secondary_item.stock_qty).as_("stock_qty"), job_card_secondary_item.item_code, - job_card_secondary_item.item_name, - job_card_secondary_item.description, - job_card_secondary_item.stock_uom, + # non-grouped columns are item attributes / the secondary-item BOM link, constant per + # grouped (item_code, secondary_item_type) -> Max() keeps the GROUP BY valid on postgres + # while returning the value MySQL picked arbitrarily. + Max(job_card_secondary_item.item_name).as_("item_name"), + Max(job_card_secondary_item.description).as_("description"), + Max(job_card_secondary_item.stock_uom).as_("stock_uom"), job_card_secondary_item.secondary_item_type, - job_card_secondary_item.bom_secondary_item, + Max(job_card_secondary_item.bom_secondary_item).as_("bom_secondary_item"), ) .join(job_card_secondary_item) .on(job_card_secondary_item.parent == job_card.name) @@ -1019,7 +1022,7 @@ def get_secondary_items_from_job_card(work_order, jc_name=None): & (job_card.docstatus == 1) ) .groupby(job_card_secondary_item.item_code, job_card_secondary_item.secondary_item_type) - .orderby(job_card_secondary_item.idx) + .orderby(Min(job_card_secondary_item.idx)) ) if jc_name: