feat(5.12): modal editare + cont obligatoriu la import; design.md + PRD 5.13 revizuit (/autoplan)
5.12 (livrat): editare in modal a randurilor de preview, cont obligatoriu inainte de import, formular editare extras (_form_editare, _editare_preview_modal), plus suita de teste aferenta (preview edit/compact, mapare op, form editare, signup, admin panel). Design + planificare: - docs/design.md: sistem de design (tokeni, breakpoints, scara control, componente, a11y). - docs/prd/prd-5.12-* si prd-5.13-* (5.13 cu raport /autoplan: CEO+Design+Eng, audit trail). Curatare: sterse PNG-urile de test/mockup temporare din radacina. Nota: implementarea CSS 5.13 (responsive compact + sistem butoane) NU e inca facuta — planul revizuit cere refactorul testelor fragile din test_web_responsive.py INAINTE de CSS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -130,6 +130,7 @@ def _resolve_row_for_preview(
|
||||
override: dict[str, Any] | None = None,
|
||||
valid_codes: set[str] | None = None,
|
||||
text_rules: list[dict] | None = None,
|
||||
reviewed: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
"""Rezolva un rand din import pentru preview: aplica mapare coloane + validare.
|
||||
|
||||
@@ -220,8 +221,10 @@ def _resolve_row_for_preview(
|
||||
# Validare continut
|
||||
errors = validate_prezentare(mapped)
|
||||
|
||||
if all_flags:
|
||||
# needs_review: validarea a trecut, dar flagurile (date ambigue, formule) cer confirmare manuala
|
||||
if all_flags and not reviewed:
|
||||
# needs_review: validarea a trecut, dar flagurile (date ambigue, formule) cer confirmare manuala.
|
||||
# Daca reviewed=True (operatorul a confirmat explicit valorile in modal), sarim
|
||||
# acest return si continuam spre ok/needs_data (US-007, PRD 5.12).
|
||||
return {
|
||||
"resolved_status": "needs_review",
|
||||
"resolved": mapped,
|
||||
@@ -337,7 +340,10 @@ def apply_row_override(
|
||||
|
||||
new_override = _merge_override(current, fields)
|
||||
enc = encrypt_creds(new_override) if new_override else None
|
||||
conn.execute("UPDATE import_rows SET override_json=? WHERE id=?", (enc, row["rid"]))
|
||||
# D#9 (PRD 5.12): resetam reviewed=0 la orice schimbare de valoare — operatorul
|
||||
# trebuie sa reconfirme dupa editare. NU conditionam pe reviewed curent: orice override
|
||||
# (chiar si revert la valoarea initiala) anuleaza confirmarea implicita.
|
||||
conn.execute("UPDATE import_rows SET override_json=?, reviewed=0 WHERE id=?", (enc, row["rid"]))
|
||||
return new_override
|
||||
|
||||
|
||||
@@ -932,10 +938,30 @@ def commit_import(
|
||||
if batch["status"] == "committed":
|
||||
raise HTTPException(status_code=409, detail="batch deja comis")
|
||||
|
||||
# Incarca randurile cu stare ok sau needs_review
|
||||
# D#8 (PRD 5.12): gate commit derivat din DB `reviewed` pe AMBELE canale.
|
||||
# API: reviewed_rows pastrat (contract stabil) dar seteaza reviewed=1 in DB inainte
|
||||
# de interogare. Randurile needs_review cu reviewed=1 sunt incluse in comit.
|
||||
if req.reviewed_rows:
|
||||
conn.execute("BEGIN IMMEDIATE")
|
||||
try:
|
||||
for idx in req.reviewed_rows:
|
||||
conn.execute(
|
||||
"UPDATE import_rows SET reviewed=1 "
|
||||
"WHERE batch_id=? AND row_index=? AND resolved_status='needs_review'",
|
||||
(import_id, idx),
|
||||
)
|
||||
conn.execute("COMMIT")
|
||||
except Exception:
|
||||
conn.execute("ROLLBACK")
|
||||
raise
|
||||
|
||||
# Incarca randurile ok + needs_review confirmate (reviewed=1)
|
||||
ok_rows_db = conn.execute(
|
||||
"SELECT row_index, raw_json, override_json, resolved_status FROM import_rows "
|
||||
"WHERE batch_id=? AND resolved_status IN ('ok', 'needs_review') ORDER BY row_index",
|
||||
"SELECT row_index, raw_json, override_json, resolved_status, reviewed "
|
||||
"FROM import_rows "
|
||||
"WHERE batch_id=? AND (resolved_status='ok' OR "
|
||||
"(resolved_status='needs_review' AND reviewed=1)) "
|
||||
"ORDER BY row_index",
|
||||
(import_id,),
|
||||
).fetchall()
|
||||
|
||||
@@ -947,8 +973,6 @@ def commit_import(
|
||||
|
||||
# Decripteaza randurile ok
|
||||
ok_rows: list[dict] = []
|
||||
ok_indices: list[int] = []
|
||||
review_indices: set[int] = set()
|
||||
|
||||
for r in ok_rows_db:
|
||||
try:
|
||||
@@ -957,28 +981,12 @@ def commit_import(
|
||||
continue
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if r["resolved_status"] == "ok":
|
||||
ok_rows.append({"row_index": r["row_index"], "data": row_data,
|
||||
"override": _override_of(r), "status": "ok"})
|
||||
ok_indices.append(r["row_index"])
|
||||
elif r["resolved_status"] == "needs_review":
|
||||
review_indices.add(r["row_index"])
|
||||
|
||||
# needs_review bifate explicit (atestare pe valori)
|
||||
confirmed_review = [idx for idx in req.reviewed_rows if idx in review_indices]
|
||||
for idx in confirmed_review:
|
||||
# Gaseste randul needs_review si il adauga la ok_rows
|
||||
for r in ok_rows_db:
|
||||
if r["row_index"] == idx and r["resolved_status"] == "needs_review":
|
||||
try:
|
||||
row_data = decrypt_creds(r["raw_json"])
|
||||
if row_data:
|
||||
ok_rows.append({"row_index": idx, "data": row_data,
|
||||
"override": _override_of(r), "status": "needs_review"})
|
||||
ok_indices.append(idx)
|
||||
except Exception:
|
||||
pass
|
||||
ok_rows.append({
|
||||
"row_index": r["row_index"],
|
||||
"data": row_data,
|
||||
"override": _override_of(r),
|
||||
"status": r["resolved_status"],
|
||||
})
|
||||
|
||||
# Gate HARD: n_confirmat trebuie sa fie EXACT egal cu numarul de randuri ok
|
||||
n_total_ok = len(ok_rows)
|
||||
|
||||
Reference in New Issue
Block a user