feat(import): T9 canonicalize_row + build_key partajat (idempotency)
- canonicalize_row: VIN upper, odometru strip ".0" (Excel float coercion), data strip — INAINTE de validare si cheie (§3.4bis) - build_key: aplica account_or_default(None->1) inainte de hash (OV-2): canal API (None) si canal import (1) produc aceeasi cheie - build_key_legacy: helper dual-lookup pentru randuri DB vechi (pre-T9) - router.py: POST /v1/prezentari foloseste build_key(account_id, canonicalize_row(content)) - 14 teste: canonicalizare, cross-canal, dedup float/int odometru, legacy Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,7 +22,7 @@ from pydantic import BaseModel, Field
|
||||
from ...auth import resolve_account_id
|
||||
from ...crypto import encrypt_creds
|
||||
from ...db import get_connection
|
||||
from ...idempotency import idempotency_key
|
||||
from ...idempotency import build_key, canonicalize_row, idempotency_key
|
||||
from ...mapping import (
|
||||
account_or_default,
|
||||
load_mapping,
|
||||
@@ -63,7 +63,17 @@ def create_prezentari(
|
||||
mapping = load_mapping(conn, acct)
|
||||
for prez in req.prezentari:
|
||||
content = prez.model_dump()
|
||||
key = idempotency_key(account_id, content)
|
||||
# T9/OV-2: canonicalize_row inaintea build_key (odometru strip ".0", VIN upper).
|
||||
# build_key aplica account_or_default(account_id) inainte de hash:
|
||||
# None si 1 colapseaza la aceeasi cheie (canal API + canal import).
|
||||
canon = canonicalize_row(content)
|
||||
key = build_key(account_id, canon)
|
||||
# Aplica normalizarea si in content (odometru canonicalizat inainte de validare, §3.4bis)
|
||||
content.update({
|
||||
"vin": canon["vin"],
|
||||
"nr_inmatriculare": canon["nr_inmatriculare"],
|
||||
"odometru_final": canon["odometru_final"],
|
||||
})
|
||||
existing = conn.execute(
|
||||
"SELECT id, status, id_prezentare FROM submissions WHERE idempotency_key=?",
|
||||
(key,),
|
||||
|
||||
Reference in New Issue
Block a user