electric-horses-infra/stacks/eh-search/app/search/exact.py

79 lines
2.6 KiB
Python
Raw Permalink Normal View History

"""Exact lookups: Komm-Nr, DVN, VIN.
Loco-Soft Komm-Nr-Schema:
Type-Buchstabe (N/T/V/D/G/L) + DVN-Zahl (4-6 Stellen)
Beispiele: 'D9094' (Nissan Leaf), 'N8093' (Askoll XKP45), 'L9083' (Opel)
N = Neu, T = Tageszul., V = Vorfuehr,
D = Differenzbest., G = Gebraucht, L = Leihgabe
DVN allein ist eindeutig pro Fahrzeug, deshalb auch als Such-Einstieg möglich.
"""
import re
from app import db
from app.schemas import SearchResultItem
COLUMNS = """
vehicle_id, dvn, commission_number, vin, brand, model, title,
price::float8 as price, primary_image_id::text as primary_image_id,
directus_product_id, dealer_vehicle_type
"""
KOMM_NR_RE = re.compile(r"^([NTVDGLntvdgl])\s*(\d{4,6})$")
def normalize_komm_nr(raw: str) -> str | None:
"""'D 9094' / 'd9094' / ' D9094 ' -> 'D9094'. Returns None if not a valid pattern."""
if not raw:
return None
m = KOMM_NR_RE.match(raw.strip())
if not m:
return None
return m.group(1).upper() + m.group(2)
async def by_komm_nr(raw: str) -> list[SearchResultItem]:
"""Lookup by full Komm-Nr (Type-Letter + DVN). Eindeutig wenn vorhanden."""
normalized = normalize_komm_nr(raw)
if not normalized:
return []
sql = f"SELECT {COLUMNS} FROM search_vehicles WHERE commission_number = $1 LIMIT 5"
rows = await db.fetch(sql, normalized)
return [_row_to_item(r, matched_via="exact_komm") for r in rows]
async def by_dvn(number: str) -> list[SearchResultItem]:
"""Lookup by DVN allein (4-6 stellige Zahl ohne Type-Buchstabe).
DVN ist eindeutig pro Fahrzeug, also liefert das immer 0 oder 1 Treffer."""
try:
dvn_int = int(number)
except (ValueError, TypeError):
return []
sql = f"SELECT {COLUMNS} FROM search_vehicles WHERE dvn = $1 LIMIT 5"
rows = await db.fetch(sql, dvn_int)
return [_row_to_item(r, matched_via="exact_dvn") for r in rows]
async def by_vin(vin: str) -> list[SearchResultItem]:
sql = f"SELECT {COLUMNS} FROM search_vehicles WHERE vin = $1 LIMIT 5"
rows = await db.fetch(sql, vin)
return [_row_to_item(r, matched_via="exact_vin") for r in rows]
def _row_to_item(row, matched_via: str) -> SearchResultItem:
return SearchResultItem(
vehicle_id=row["vehicle_id"],
commission_number=row["commission_number"],
vin=row["vin"],
brand=row["brand"],
model=row["model"],
title=row["title"] or "",
price=row["price"],
primary_image_id=row["primary_image_id"],
directus_product_id=row["directus_product_id"],
score=1.0,
matched_via=matched_via,
)