Merge pull request #56260 from mihir-kandoi/pg-wo-stock-report-rowcount

fix(manufacturing): keep Work Order Stock report one row per item (MariaDB parity)
This commit is contained in:
Mihir Kandoi
2026-06-21 22:21:21 +05:30
committed by GitHub
2 changed files with 15 additions and 9 deletions

View File

@@ -8,9 +8,9 @@ from erpnext.tests.utils import ERPNextTestSuite
class TestWorkOrderStockReport(ERPNextTestSuite):
def test_report_executes_and_lists_work_order(self):
# get_item_list computes build_qty by multiplying bin/bom/bom_item columns that are not
# functionally dependent on the grouped item_code; they must be in the GROUP BY for the
# report to run on Postgres. This exercises that query on both engines.
# get_item_list aggregates build_qty with Max() and groups by item_code, so it returns one
# row per item_code and runs on Postgres (which rejects non-grouped selected columns).
# This exercises that query on both engines.
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
from erpnext.manufacturing.report.work_order_stock_report.work_order_stock_report import execute

View File

@@ -4,7 +4,7 @@
import frappe
from frappe import _
from frappe.query_builder.functions import IfNull
from frappe.query_builder.functions import IfNull, Max, Sum
from frappe.utils import cint
@@ -40,17 +40,23 @@ def get_item_list(wo_list, filters):
)
.select(
bom_item.item_code.as_("item_code"),
IfNull(bin.actual_qty * bom.quantity / bom_item.stock_qty, 0).as_("build_qty"),
# Aggregate so the query stays one row per item_code and is Postgres
# GROUP-BY-valid. A BOM may list the same item on several lines; adding the
# qty columns to GROUP BY would split the row and change the row count on
# MariaDB. actual_qty (single warehouse) and bom.quantity (single BOM) are
# pinned to one value, so Max() returns that value; the per-unit requirement
# is the TOTAL of this item across its lines, so stock_qty is summed. For the
# common single-line item this equals the prior expression exactly.
IfNull(Max(bin.actual_qty) * Max(bom.quantity) / Sum(bom_item.stock_qty), 0).as_(
"build_qty"
),
)
.where(
(bom.name == bom_item.parent)
& (bom_item.item_code == wo_item_details.item_code)
& (bom.name == wo_details.bom_no)
)
# build_qty multiplies columns from bin/bom/bom_item that aren't functionally
# dependent on the grouped item_code, so postgres requires them in the GROUP BY.
# The WHERE pins bom, item and warehouse to single rows, so this stays one row.
.groupby(bom_item.item_code, bom.quantity, bom_item.stock_qty, bin.actual_qty)
.groupby(bom_item.item_code)
).run(as_dict=1)
stock_qty = 0