From afb7c251411b8362bcc9bfacf06f63ea32e37e72 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Sat, 20 Jun 2026 19:42:00 +0530 Subject: [PATCH] refactor(stock): convert LCV serial-rate update to qb + fix cost_center GROUP BY (PG) Convert the `update tabSerial No set purchase_rate ... where name in (...)` to frappe.qb.update(isin). Also fix the #39 Postgres bug in set_landed_cost_voucher_amount: `.select(Sum(applicable_charges), cost_center)` selected a non-grouped column with no GROUP BY (GroupingError on PG) -> wrap it in `Max(cost_center)` (deterministic representative; per (receipt_document, receipt_item) the matching LCV items share a cost_center -> MariaDB-identical). Covered by the existing landed-cost tests. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../landed_cost_voucher/landed_cost_voucher.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 6576380e862..31b3e057570 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -9,7 +9,7 @@ from frappe import _ from frappe.model.document import Document from frappe.model.meta import get_field_precision from frappe.query_builder.custom import ConstantColumn -from frappe.query_builder.functions import Sum +from frappe.query_builder.functions import Max, Sum from frappe.utils import cint, flt import erpnext @@ -395,12 +395,12 @@ class LandedCostVoucher(Document): if not item.is_fixed_asset and item.serial_no: serial_nos = get_serial_nos(item.serial_no) if serial_nos: - frappe.db.sql( - "update `tabSerial No` set purchase_rate=%s where name in ({})".format( - ", ".join(["%s"] * len(serial_nos)) - ), - tuple([item.valuation_rate, *serial_nos]), - ) + serial_no = frappe.qb.DocType("Serial No") + ( + frappe.qb.update(serial_no) + .set(serial_no.purchase_rate, item.valuation_rate) + .where(serial_no.name.isin(serial_nos)) + ).run() @frappe.whitelist() def get_vendor_invoice_amount(self, vendor_invoice: str): @@ -532,7 +532,7 @@ def set_landed_cost_voucher_amount(doc): lcv_item = frappe.qb.DocType("Landed Cost Item") query = ( frappe.qb.from_(lcv_item) - .select(Sum(lcv_item.applicable_charges), lcv_item.cost_center) + .select(Sum(lcv_item.applicable_charges), Max(lcv_item.cost_center)) .where((lcv_item.docstatus == 1) & (lcv_item.receipt_document == doc.name)) )