mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-11 13:41:47 +00:00
fix(stock): case-insensitive serial-no match in get_stock_ledgers_for_serial_nos
The serial-no filter used serial_batch_entry.serial_no.isin(serial_nos), which is case-sensitive on Postgres -- a differently-cased serial no missed Serial and Batch Entry rows that MariaDB (case-insensitive collation) matches (the OR'd regexp branch only covers the legacy Stock Ledger Entry.serial_no text, empty for bundle-tracked serials). Lower() both sides: MariaDB result unchanged, Postgres now matches too. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ import frappe.query_builder
|
||||
from frappe import _, _dict, bold
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.naming import make_autoname
|
||||
from frappe.query_builder.functions import Concat_ws, Max, Sum
|
||||
from frappe.query_builder.functions import Concat_ws, Lower, Max, Sum
|
||||
from frappe.utils import (
|
||||
cint,
|
||||
cstr,
|
||||
@@ -3388,7 +3388,8 @@ def get_stock_ledgers_for_serial_nos(kwargs):
|
||||
query.left_join(serial_batch_entry)
|
||||
.on(stock_ledger_entry.serial_and_batch_bundle == serial_batch_entry.parent)
|
||||
.where(
|
||||
serial_batch_entry.serial_no.isin(serial_nos)
|
||||
# Lower() both sides so serial-no matching is case-insensitive on Postgres as on MariaDB
|
||||
Lower(serial_batch_entry.serial_no).isin([sn.lower() for sn in serial_nos])
|
||||
| Concat_ws("", "\n", stock_ledger_entry.serial_no, "\n").regexp(regex_pattern)
|
||||
)
|
||||
.distinct()
|
||||
|
||||
@@ -80,6 +80,31 @@ class TestSerialandBatchBundle(ERPNextTestSuite):
|
||||
|
||||
self.assertFalse(bundle_doc.name.startswith("SABB-"))
|
||||
|
||||
def test_get_stock_ledgers_for_serial_nos_is_case_insensitive(self):
|
||||
# get_stock_ledgers_for_serial_nos matches Serial and Batch Entry.serial_no with isin(), which is
|
||||
# case-sensitive on Postgres -- a differently-cased serial no would miss entries that MariaDB
|
||||
# (case-insensitive collation) matches. Lower() both sides keeps MariaDB unchanged and makes
|
||||
# Postgres match too.
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||
from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle import (
|
||||
get_stock_ledgers_for_serial_nos,
|
||||
)
|
||||
|
||||
item_code = "Test SBB Case-insensitive Serial Item"
|
||||
make_item(
|
||||
item_code,
|
||||
{"has_serial_no": 1, "serial_no_series": "TESTCISER-.#####", "is_stock_item": 1},
|
||||
)
|
||||
pr = make_purchase_receipt(item_code=item_code, warehouse="_Test Warehouse - _TC", qty=1, rate=100)
|
||||
bundle = pr.items[0].serial_and_batch_bundle
|
||||
serial_no = get_serial_nos_from_bundle(bundle)[0]
|
||||
|
||||
# query with a lowercased serial no; the stored Serial and Batch Entry value is uppercase
|
||||
rows = get_stock_ledgers_for_serial_nos(
|
||||
frappe._dict({"item_code": item_code, "serial_nos": [serial_no.lower()]})
|
||||
)
|
||||
self.assertTrue(any(row.serial_and_batch_bundle == bundle for row in rows))
|
||||
|
||||
def test_inward_outward_serial_valuation(self):
|
||||
from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
|
||||
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||
|
||||
Reference in New Issue
Block a user