feat(5.8): reguli mapare pe text (substring/cont) + UX tabel trimiteri (detaliu inline, fara scroll, cod RAR)
Reguli text per cont (operation_text_rules), resolve_prestatii cu param aditiv text_rules + precedenta stricta, threadat pe toate cele 6 callsite-uri + valid_codes + seam classify_prezentare. UI Mapari: sectiune reguli + preview pre-salvare + overlap + telemetrie text_rule_hit. UX tabel: cod_rar sub operatie, pill eticheta scurta, fara scroll orizontal (scopat .tabel-trimiteri + carduri <768px), detaliu inline expandabil (a11y + pauza poll). code-review: reparat regula auto_send=0 care trimitea automat la RAR in loc sa tina randul pentru review. 814 passed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,11 +25,13 @@ from ...db import get_connection
|
||||
from ...errors import eroare as err_eroare
|
||||
from ...idempotency import build_key, canonicalize_row
|
||||
from ...mapping import (
|
||||
_emite_text_rule_hits,
|
||||
account_or_default,
|
||||
account_scope_clause,
|
||||
classify_prezentare,
|
||||
load_mapping_meta,
|
||||
load_nomenclator_codes,
|
||||
load_text_rules,
|
||||
pending_unmapped,
|
||||
reresolve_account,
|
||||
save_mapping,
|
||||
@@ -65,13 +67,13 @@ def _effective_on_unmapped_error(conn, acct: int, req_value: bool | None) -> boo
|
||||
return bool(row["on_unmapped_error_default"]) if row else False
|
||||
|
||||
|
||||
def _classify_modal(content, mapping, mapping_meta, valid_codes, error_mode) -> dict:
|
||||
def _classify_modal(content, mapping, mapping_meta, valid_codes, error_mode, text_rules=None) -> dict:
|
||||
"""classify_prezentare + aplicarea modului on_unmapped_error.
|
||||
|
||||
Cand exista coduri nemapate si error_mode=True, marcheaza outcome-ul ca respingere
|
||||
(blocked_error=True): rutele NU mai fac enqueue, ci intorc o eroare per-element.
|
||||
"""
|
||||
cl = classify_prezentare(content, mapping, mapping_meta, valid_codes)
|
||||
cl = classify_prezentare(content, mapping, mapping_meta, valid_codes, text_rules)
|
||||
cl["blocked_error"] = bool(cl["unmapped"]) and error_mode
|
||||
return cl
|
||||
|
||||
@@ -164,6 +166,8 @@ def create_prezentari(
|
||||
# Validare cod_prestatie fata de nomenclator + modul la cod necunoscut/nemapat.
|
||||
# valid_codes gol (nomenclator nepopulat) -> None (nu validam, ca sa nu blocam tot).
|
||||
valid_codes = load_nomenclator_codes(conn) or None
|
||||
# Reguli text incarcate o data per cerere (seam partajat cu dry-run, invariant 5.2).
|
||||
text_rules = load_text_rules(conn, acct)
|
||||
error_mode = _effective_on_unmapped_error(conn, acct, req.on_unmapped_error)
|
||||
for prez in req.prezentari:
|
||||
content = prez.model_dump()
|
||||
@@ -187,7 +191,7 @@ def create_prezentari(
|
||||
# retrimiterea aceluiasi continut. Il RE-ACTIVAM (re-clasificam + actualizam
|
||||
# creds + reset), printr-un UPDATE compare-and-swap pe status='error'.
|
||||
if existing["status"] == "error":
|
||||
cl = _classify_modal(content, mapping, mapping_meta, valid_codes, error_mode)
|
||||
cl = _classify_modal(content, mapping, mapping_meta, valid_codes, error_mode, text_rules)
|
||||
if cl["blocked_error"]:
|
||||
# on_unmapped_error=True: nu reactivam; randul ramane 'error'.
|
||||
results.append(_rezultat_respins(existing["id"], cl))
|
||||
@@ -208,6 +212,8 @@ def create_prezentari(
|
||||
"UPDATE accounts SET rar_creds_enc=? WHERE id=?",
|
||||
(encrypt_creds(req.rar_credentials.model_dump()), acct),
|
||||
)
|
||||
# US-010: telemetrie pentru itemii rezolvati prin regula text.
|
||||
_emite_text_rule_hits(conn, acct, existing["id"], cl["resolved"])
|
||||
# Raspuns onest si la reactivare (PRD 5.7): daca re-clasificarea
|
||||
# cade pe needs_data/needs_mapping, expune motivul (nu doar status).
|
||||
results.append(_rezultat_enqueue(existing["id"], cl, reactivated=True))
|
||||
@@ -230,7 +236,7 @@ def create_prezentari(
|
||||
|
||||
# Helper pur partajat cu dry-run (PRD 5.2): reproduce EXACT clasificarea
|
||||
# (canonicalize + mapare op->cod + validare + auto_send gate).
|
||||
cl = _classify_modal(content, mapping, mapping_meta, valid_codes, error_mode)
|
||||
cl = _classify_modal(content, mapping, mapping_meta, valid_codes, error_mode, text_rules)
|
||||
if cl["blocked_error"]:
|
||||
# on_unmapped_error=True: respinge fara enqueue (cod necunoscut/nemapat).
|
||||
results.append(_rezultat_respins(None, cl))
|
||||
@@ -240,8 +246,11 @@ def create_prezentari(
|
||||
"VALUES (?, ?, ?, ?, ?, ?)",
|
||||
(key, acct, cl["status"], json.dumps(cl["content"], ensure_ascii=False), cl["rar_error"], creds_enc),
|
||||
)
|
||||
sub_id = int(cur.lastrowid)
|
||||
# US-010: telemetrie pentru itemii rezolvati prin regula text.
|
||||
_emite_text_rule_hits(conn, acct, sub_id, cl["resolved"])
|
||||
# Raspuns onest (PRD 5.7): pe needs_data/needs_mapping expune erori/nemapate/motiv.
|
||||
results.append(_rezultat_enqueue(int(cur.lastrowid), cl))
|
||||
results.append(_rezultat_enqueue(sub_id, cl))
|
||||
|
||||
# US-004: audit cerere API per cont. Doar metadate (count + distributie status),
|
||||
# NICIUN camp de payload PII integral. Reuse conn (T4 — fara contentie WAL).
|
||||
@@ -284,10 +293,12 @@ def valideaza_prezentari(
|
||||
mapping_meta = load_mapping_meta(conn, acct)
|
||||
mapping = {op: meta["cod_prestatie"] for op, meta in mapping_meta.items()}
|
||||
valid_codes = load_nomenclator_codes(conn) or None
|
||||
# Acelasi seam ca trimiterea reala: dry-run trebuie sa vada aceleasi reguli text.
|
||||
text_rules = load_text_rules(conn, acct)
|
||||
error_mode = _effective_on_unmapped_error(conn, acct, req.on_unmapped_error)
|
||||
for i, prez in enumerate(req.prezentari):
|
||||
content = prez.model_dump()
|
||||
res = _classify_modal(content, mapping, mapping_meta, valid_codes, error_mode)
|
||||
res = _classify_modal(content, mapping, mapping_meta, valid_codes, error_mode, text_rules)
|
||||
if res["blocked_error"]:
|
||||
res = {**res, "status": "error"}
|
||||
# US-003: imbogatim fiecare element nemapat cu 3 niveluri COD_NEMAPAT
|
||||
|
||||
Reference in New Issue
Block a user