feat(web): paritate editor mapare import-preview cu pagina /mapari
Panoul inline "Operatii de mapat la cod RAR" din preview-ul de import folosea doar sugestii fuzzy si nu arata sursa sugestiei. Acum are paritate 1:1 cu pagina /mapari: aceeasi sugestie_principala (GOLD partajat > SILVER > embeddings k-NN) si acelasi badge sursa (confirmat / similar / non-operatie). - _collect_unmapped_ops primeste `conn`: ataseaza sugestie_principala + surse_sugestie via enrich_suggestions, cu ensure_embeddings_corpus o data inainte de bucla (replica pattern-ul din pending_unmapped). Init default pe fiecare entry (inclusiv conn=None) -> contract template identic. SUGGESTION-ONLY: nu atinge resolve_prestatii/load_mapping (#13). - _web_compute_preview paseaza conn=conn la _collect_unmapped_ops. - _preview_import.html: preselect din sugestie_principala > fuzzy>=60 + badge sursa (clase .sugg-sursa--{confirmat,similar,nul} deja existente in base.html). - Test de paritate TARE: seed embeddings + GOLD/SILVER/NUL, batch import cu needs_mapping, verifica _web_compute_preview()["unmapped_ops"] == pending_unmapped(conn, account) pe sugestie_principala + surse_sugestie, cate un caz per sursa (gold/silver/embedding/nul). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2694,12 +2694,21 @@ def post_sterge_format_coloane(
|
||||
# Toate rutele /_import/* returneaza fragmente HTML (target #import-section). #
|
||||
# =========================================================================== #
|
||||
|
||||
def _collect_unmapped_ops(preview_rows: list[dict], nomenclator: list[dict]) -> list[dict]:
|
||||
"""Operatii distincte nemapate dintr-un preview de import (staging), cu sugestii fuzzy.
|
||||
def _collect_unmapped_ops(preview_rows: list[dict], nomenclator: list[dict], conn=None) -> list[dict]:
|
||||
"""Operatii distincte nemapate dintr-un preview de import (staging), cu sugestii fuzzy + enriched.
|
||||
|
||||
Echivalentul lui pending_unmapped() dar pe randuri de PREVIEW (import in staging,
|
||||
Echivalentul lui `pending_unmapped()` dar pe randuri de PREVIEW (import in staging,
|
||||
inca neexistente ca submissions). Aduna doar prestatiile fara cod_prestatie
|
||||
(cele cu auto_send=0 au deja cod -> nu apar aici). Sortare: cele mai blocate intai.
|
||||
|
||||
L14-S6 / paritate editor: cand `conn` e dat, ataseaza `sugestie_principala`
|
||||
(GOLD partajat > SILVER > embeddings k-NN) si `surse_sugestie` din `enrich_suggestions`,
|
||||
exact ca `pending_unmapped` — asa panoul inline al preview-ului are aceeasi sugestie
|
||||
principala + badge sursa ca pagina /mapari. SUGGESTION-ONLY: nu atinge
|
||||
`resolve_prestatii`/`load_mapping` (#13). Degradare gratioasa pe embeddings (#16b).
|
||||
|
||||
`sugestie_principala`/`surse_sugestie` se initializeaza pe FIECARE entry (chiar cand
|
||||
conn=None) ca contractul catre template sa fie identic indiferent de call-site.
|
||||
"""
|
||||
agg: dict[str, dict[str, Any]] = {}
|
||||
for row in preview_rows:
|
||||
@@ -2715,9 +2724,22 @@ def _collect_unmapped_ops(preview_rows: list[dict], nomenclator: list[dict]) ->
|
||||
if not entry["denumire"] and item.get("denumire"):
|
||||
entry["denumire"] = item.get("denumire")
|
||||
entry["blocked"] += 1
|
||||
|
||||
# Indexeaza corpusul embeddings o data inainte de bucla (no-op cand flagul e off).
|
||||
if conn is not None:
|
||||
ensure_embeddings_corpus(conn, nomenclator)
|
||||
|
||||
out: list[dict] = []
|
||||
for entry in agg.values():
|
||||
entry["suggestions"] = suggest_codes(entry["denumire"], nomenclator, limit=5)
|
||||
# Init default pe FIECARE entry -> contract template identic (conn=None inclus).
|
||||
entry["sugestie_principala"] = None
|
||||
entry["surse_sugestie"] = {"gold_partajat": None, "silver": None, "embedding": None, "nul": False}
|
||||
# L14-S6: imbogatire cu GOLD partajat > SILVER > embeddings (SUGGESTION-ONLY, #13)
|
||||
if conn is not None:
|
||||
enriched = enrich_suggestions(conn, entry["denumire"])
|
||||
entry["sugestie_principala"] = enriched["sugestie_principala"]
|
||||
entry["surse_sugestie"] = enriched["surse"]
|
||||
out.append(entry)
|
||||
out.sort(key=lambda e: (-e["blocked"], e["cod_op_service"]))
|
||||
return out
|
||||
@@ -2940,7 +2962,7 @@ def _web_compute_preview(
|
||||
"summary": summary,
|
||||
"total": len(preview_rows),
|
||||
"filename": batch["filename"],
|
||||
"unmapped_ops": _collect_unmapped_ops(preview_rows, nomenclator),
|
||||
"unmapped_ops": _collect_unmapped_ops(preview_rows, nomenclator, conn=conn),
|
||||
"nomenclator": nomenclator,
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,8 @@
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token or '' }}">
|
||||
{% for e in unmapped_ops %}
|
||||
{%- set top = e.suggestions[0] if e.suggestions else None -%}
|
||||
{%- set preselect = top.cod_prestatie if (top and top.score >= 60) else '' -%}
|
||||
{# L14-S6: pre-selectare din sugestie_principala (GOLD/SILVER/embedding) > fuzzy>=60 #}
|
||||
{%- set preselect = e.sugestie_principala.cod_prestatie if e.sugestie_principala else (top.cod_prestatie if (top and top.score >= 60) else '') -%}
|
||||
<div class="maprow" style="align-items:flex-end; margin-bottom:10px;">
|
||||
<input type="hidden" name="cod_op_service" value="{{ e.cod_op_service }}">
|
||||
<div class="mapcol grow">
|
||||
@@ -94,9 +95,20 @@
|
||||
{% if e.denumire and e.denumire != e.cod_op_service %}
|
||||
<div class="muted">{{ e.denumire }}</div>
|
||||
{% endif %}
|
||||
{% if e.suggestions %}
|
||||
{% if e.suggestions or e.sugestie_principala or (e.surse_sugestie and e.surse_sugestie.nul) %}
|
||||
<div class="muted" style="font-size:12px; margin-top:4px;">
|
||||
sugestii:
|
||||
{# 5.18 US-007: badge sursa pe sugestia sistemului — confirmat (GOLD) / similar
|
||||
(SILVER+embedding k-NN) / non-operatie (pre-filtru NUL). Suggestion-only. #}
|
||||
{% if e.sugestie_principala %}
|
||||
{% if e.sugestie_principala.sursa == 'gold_partajat' %}
|
||||
<span class="sugg-sursa sugg-sursa--confirmat" title="cod confirmat de un operator">confirmat</span>
|
||||
{% else %}
|
||||
<span class="sugg-sursa sugg-sursa--similar" title="operatie similara deja vazuta (k-NN/exact)">similar</span>
|
||||
{% endif %}
|
||||
{% elif e.surse_sugestie and e.surse_sugestie.nul %}
|
||||
<span class="sugg-sursa sugg-sursa--nul" title="pare non-operatie (ITP/plata/discount...)">non-operatie</span>
|
||||
{% endif %}
|
||||
{% for s in e.suggestions[:3] %}
|
||||
<span class="sugg">{{ s.cod_prestatie }} ({{ s.score|round|int }}%)</span>{% if not loop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
|
||||
Reference in New Issue
Block a user