From 7f8fa5b5a2ffffa5959fb78e7d4d2227cc42d9cc Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Sun, 21 Jun 2026 09:55:51 +0530 Subject: [PATCH] fix(stock): make Landed Cost Voucher vendor-invoice query Postgres-valid get_vendor_invoice_query filtered unclaimed invoices with .having(unclaimed_amount > 0), but the query has no GROUP BY/aggregate and unclaimed_amount is a SELECT alias. Postgres rejects HAVING on a SELECT alias (and HAVING without GROUP BY on a non-aggregated column); MariaDB allowed it. Move the threshold into WHERE on the underlying expression. Behaviour is identical on MariaDB (same rows); fixes a hard error on Postgres. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../landed_cost_voucher.py | 3 ++- .../test_landed_cost_voucher.py | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index 31b3e057570..5bdcf920458 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -516,8 +516,9 @@ def get_vendor_invoice_query(filters): & (doctype.update_stock == 0) & (doctype.company == filters.get("company")) & (item.is_stock_item == 0) + # WHERE not HAVING: no GROUP BY here, and Postgres rejects HAVING on a SELECT alias + & ((doctype.base_total - doctype.claimed_landed_cost_amount) > 0) ) - .having(frappe.qb.Field("unclaimed_amount") > 0) ) if filters.get("name"): diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py index 6c44cec46b4..cc789bc1eca 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py @@ -27,6 +27,28 @@ class TestLandedCostVoucher(ERPNextTestSuite): def setUp(self): self.load_test_records("Currency Exchange") + def test_get_vendor_invoices_runs(self): + # get_vendor_invoice_query filters unclaimed vendor invoices; the threshold moved from a HAVING + # (which referenced a SELECT alias with no GROUP BY -- invalid on Postgres) to a WHERE. + from erpnext.stock.doctype.landed_cost_voucher.landed_cost_voucher import get_vendor_invoices + + pi = make_purchase_invoice(item_code="_Test Non Stock Item", qty=1, rate=100) + self.addCleanup(self._cancel_and_delete_pi, pi.name) + + rows = get_vendor_invoices( + "Purchase Invoice", "", "name", 0, 20, {"company": "_Test Company", "name": pi.name} + ) + self.assertTrue(any(r[0] == pi.name for r in rows)) + + @staticmethod + def _cancel_and_delete_pi(name): + if not frappe.db.exists("Purchase Invoice", name): + return + doc = frappe.get_doc("Purchase Invoice", name) + if doc.docstatus == 1: + doc.cancel() + frappe.delete_doc("Purchase Invoice", name, force=1) + def test_landed_cost_voucher(self): frappe.db.set_single_value("Buying Settings", "allow_multiple_items", 1)