fix(stock): make get_item_price NULL ordering match across engines (Postgres) (#56380)

get_item_price orders Item Price rows by valid_from DESC and takes LIMIT 1 to
pick the most-recent applicable price. NULL-valid_from rows are kept (the
transaction-date guard uses IfNull(valid_from, '2000-01-01')), and MariaDB
sorts NULL last for DESC while PostgreSQL defaults to NULLS FIRST — so when an
item/price_list/uom has both a dated price and a NULL-valid_from price,
PostgreSQL returns the NULL one and MariaDB the most-recent dated one, a silent
price divergence.

Wrap the sort key in IfNull(valid_from, '1900-01-01') so the NULL row sorts
last on both engines. MariaDB already placed it last for DESC, so its pick is
unchanged. Same NULL-ordering class fixed in point_of_sale.get_items (#56378).
This commit is contained in:
Mihir Kandoi
2026-06-23 20:25:44 +05:30
committed by GitHub
parent 8591a0b6ad
commit 116ef44ddb

View File

@@ -1234,7 +1234,10 @@ def get_item_price(
& (ip.price_list == pctx.price_list)
& (IfNull(ip.uom, "").isin(["", pctx.uom]))
)
.orderby(ip.valid_from, order=frappe.qb.desc)
# IfNull so a NULL valid_from sorts last under DESC on both engines: MariaDB sorts NULL last
# for DESC, but Postgres defaults to NULLS FIRST, which would otherwise make a NULL-valid_from
# price win the LIMIT 1 over the most-recent dated price.
.orderby(IfNull(ip.valid_from, "1900-01-01"), order=frappe.qb.desc)
.orderby(IfNull(ip.batch_no, ""), order=frappe.qb.desc)
.orderby(ip.uom, order=frappe.qb.desc)
.limit(1)