- reresolve_account(conn, account_id, batch_id=None): - batch_id specificat -> scope la batch-ul exact (import commit explicit) - fara batch_id (POST /v1/mapari) -> EXCLUSIV canal API (batch_id IS NULL) - salvarea unei mapari NU mai re-queues randuri cross-batch (R1 inchis) - 6 teste: izolare batch A/B, regresie API canal, batch explicit nu atinge API, schema batch_id/row_index, 3 batches izolate Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
198 lines
7.4 KiB
Python
198 lines
7.4 KiB
Python
"""Teste T7: batch_id/row_index scope reresolve_account (R1 INCHIS).
|
|
|
|
Verify:
|
|
(a) salvare mapare in batch A NU trimite randuri din batch B / feed API.
|
|
(b) canal API (batch_id NULL) tot se re-rezolva ca azi (regresie).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import tempfile
|
|
|
|
import pytest
|
|
|
|
|
|
@pytest.fixture()
|
|
def env(monkeypatch):
|
|
tmp = tempfile.mkdtemp()
|
|
monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "t7.db"))
|
|
from app.config import get_settings
|
|
get_settings.cache_clear()
|
|
from app.db import init_db
|
|
init_db()
|
|
yield monkeypatch
|
|
get_settings.cache_clear()
|
|
|
|
|
|
@pytest.fixture()
|
|
def conn(env):
|
|
from app.db import get_connection
|
|
c = get_connection()
|
|
yield c
|
|
c.close()
|
|
|
|
|
|
def _insert_batch(conn, account_id=1):
|
|
"""Creeaza un import_batch si returneaza id-ul."""
|
|
cur = conn.execute(
|
|
"INSERT INTO import_batches (account_id, filename, status) VALUES (?, ?, 'staging')",
|
|
(account_id, "test.xlsx"),
|
|
)
|
|
return int(cur.lastrowid)
|
|
|
|
|
|
def _insert_submission(conn, account_id=1, batch_id=None, cod_op="ITP-1", key_sfx=None):
|
|
"""Insereaza un submission needs_mapping (cu sau fara batch)."""
|
|
content = {
|
|
"vin": "WVWZZZ1KZAW000123", "nr_inmatriculare": "B1",
|
|
"data_prestatie": "2026-06-15", "odometru_final": "123456",
|
|
"prestatii": [{"cod_op_service": cod_op, "denumire": "Test"}],
|
|
}
|
|
sfx = key_sfx or os.urandom(4).hex()
|
|
if batch_id is not None:
|
|
cur = conn.execute(
|
|
"INSERT INTO submissions (idempotency_key, account_id, status, payload_json, batch_id) "
|
|
"VALUES (?, ?, 'needs_mapping', ?, ?)",
|
|
(f"k-{sfx}", account_id, json.dumps(content), batch_id),
|
|
)
|
|
else:
|
|
cur = conn.execute(
|
|
"INSERT INTO submissions (idempotency_key, account_id, status, payload_json) "
|
|
"VALUES (?, ?, 'needs_mapping', ?)",
|
|
(f"k-{sfx}", account_id, json.dumps(content)),
|
|
)
|
|
return int(cur.lastrowid)
|
|
|
|
|
|
def _add_mapping(conn, account_id=1, cod_op="ITP-1", cod_prestatie="OE-1", auto_send=True):
|
|
conn.execute(
|
|
"INSERT OR IGNORE INTO nomenclator_rar (cod_prestatie, nume_prestatie) VALUES (?, ?)",
|
|
(cod_prestatie, "Test operatie"),
|
|
)
|
|
conn.execute(
|
|
"INSERT OR REPLACE INTO operations_mapping (account_id, cod_op_service, cod_prestatie, auto_send) "
|
|
"VALUES (?, ?, ?, ?)",
|
|
(account_id, cod_op, cod_prestatie, 1 if auto_send else 0),
|
|
)
|
|
|
|
|
|
# --- Scoping ---
|
|
|
|
def test_reresolve_batch_specific_nu_atinge_alt_batch(conn):
|
|
"""(a) reresolve_account cu batch_id=A nu atinge randuri din batch_id=B."""
|
|
from app.mapping import reresolve_account
|
|
|
|
batch_a = _insert_batch(conn)
|
|
batch_b = _insert_batch(conn)
|
|
|
|
sid_a = _insert_submission(conn, batch_id=batch_a, cod_op="ITP-1", key_sfx="a1")
|
|
sid_b = _insert_submission(conn, batch_id=batch_b, cod_op="ITP-1", key_sfx="b1")
|
|
|
|
_add_mapping(conn, cod_op="ITP-1", cod_prestatie="OE-1", auto_send=True)
|
|
|
|
# Re-rezolva NUMAI batch_a
|
|
stats = reresolve_account(conn, 1, batch_id=batch_a)
|
|
assert stats["requeued"] == 1
|
|
|
|
# Batch B nemodificat
|
|
row_a = conn.execute("SELECT status FROM submissions WHERE id=?", (sid_a,)).fetchone()
|
|
row_b = conn.execute("SELECT status FROM submissions WHERE id=?", (sid_b,)).fetchone()
|
|
assert row_a["status"] == "queued", "batch A trebuie requeued"
|
|
assert row_b["status"] == "needs_mapping", "batch B trebuie sa ramana needs_mapping"
|
|
|
|
|
|
def test_reresolve_fara_batch_nu_atinge_batches(conn):
|
|
"""(a) reresolve fara batch (POST /v1/mapari) NU atinge batch submissions."""
|
|
from app.mapping import reresolve_account
|
|
|
|
batch_a = _insert_batch(conn)
|
|
sid_batch = _insert_submission(conn, batch_id=batch_a, cod_op="ITP-1", key_sfx="ba")
|
|
sid_api = _insert_submission(conn, batch_id=None, cod_op="ITP-1", key_sfx="ap")
|
|
|
|
_add_mapping(conn, cod_op="ITP-1", cod_prestatie="OE-1", auto_send=True)
|
|
|
|
# Fara batch (cum apeleaza POST /v1/mapari)
|
|
stats = reresolve_account(conn, 1)
|
|
assert stats["requeued"] == 1 # numai API canal
|
|
|
|
row_batch = conn.execute("SELECT status FROM submissions WHERE id=?", (sid_batch,)).fetchone()
|
|
row_api = conn.execute("SELECT status FROM submissions WHERE id=?", (sid_api,)).fetchone()
|
|
assert row_batch["status"] == "needs_mapping", "batch submission NU trebuie atins de reresolve global"
|
|
assert row_api["status"] == "queued", "API canal trebuie requeued"
|
|
|
|
|
|
def test_reresolve_canal_api_regresie(conn):
|
|
"""(b) Canal API (batch_id NULL) tot se re-rezolva ca azi."""
|
|
from app.mapping import reresolve_account
|
|
|
|
# Doua submission-uri API fara batch
|
|
sid1 = _insert_submission(conn, batch_id=None, cod_op="ITP-2", key_sfx="r1")
|
|
sid2 = _insert_submission(conn, batch_id=None, cod_op="ITP-2", key_sfx="r2")
|
|
|
|
_add_mapping(conn, cod_op="ITP-2", cod_prestatie="OE-1", auto_send=True)
|
|
|
|
stats = reresolve_account(conn, 1) # fara batch — re-rezolva tot API
|
|
assert stats["requeued"] == 2
|
|
|
|
for sid in (sid1, sid2):
|
|
row = conn.execute("SELECT status FROM submissions WHERE id=?", (sid,)).fetchone()
|
|
assert row["status"] == "queued"
|
|
|
|
|
|
def test_reresolve_batch_explicit_nu_atinge_api(conn):
|
|
"""Batch explicit: nu atinge feed API (batch_id IS NULL)."""
|
|
from app.mapping import reresolve_account
|
|
|
|
batch_a = _insert_batch(conn)
|
|
sid_batch = _insert_submission(conn, batch_id=batch_a, cod_op="ITP-3", key_sfx="ba3")
|
|
sid_api = _insert_submission(conn, batch_id=None, cod_op="ITP-3", key_sfx="ap3")
|
|
|
|
_add_mapping(conn, cod_op="ITP-3", cod_prestatie="OE-1", auto_send=True)
|
|
|
|
stats = reresolve_account(conn, 1, batch_id=batch_a)
|
|
assert stats["requeued"] == 1
|
|
|
|
row_batch = conn.execute("SELECT status FROM submissions WHERE id=?", (sid_batch,)).fetchone()
|
|
row_api = conn.execute("SELECT status FROM submissions WHERE id=?", (sid_api,)).fetchone()
|
|
assert row_batch["status"] == "queued"
|
|
assert row_api["status"] == "needs_mapping", "API canal nu trebuie atins de reresolve batch-specific"
|
|
|
|
|
|
def test_submissions_au_batch_id_si_row_index(conn):
|
|
"""Schema: submissions.batch_id si .row_index exista si se pot seta."""
|
|
batch_id = _insert_batch(conn)
|
|
conn.execute(
|
|
"INSERT INTO submissions (idempotency_key, account_id, status, payload_json, batch_id, row_index) "
|
|
"VALUES (?, ?, 'queued', '{}', ?, ?)",
|
|
("k-test-bi", 1, batch_id, 5),
|
|
)
|
|
row = conn.execute("SELECT batch_id, row_index FROM submissions WHERE idempotency_key='k-test-bi'").fetchone()
|
|
assert row["batch_id"] == batch_id
|
|
assert row["row_index"] == 5
|
|
|
|
|
|
def test_reresolve_multiple_batches_izolate(conn):
|
|
"""R1 INCHIS: 3 batches, fiecare re-rezolvat independent."""
|
|
from app.mapping import reresolve_account
|
|
|
|
batches = [_insert_batch(conn) for _ in range(3)]
|
|
sids = {
|
|
b: _insert_submission(conn, batch_id=b, cod_op="ITP-4", key_sfx=f"mb{i}")
|
|
for i, b in enumerate(batches)
|
|
}
|
|
|
|
_add_mapping(conn, cod_op="ITP-4", cod_prestatie="OE-1", auto_send=True)
|
|
|
|
# Re-rezolva batch 0, verifica ca 1 si 2 nu sunt atinse
|
|
reresolve_account(conn, 1, batch_id=batches[0])
|
|
|
|
statuses = {
|
|
b: conn.execute("SELECT status FROM submissions WHERE id=?", (sid,)).fetchone()["status"]
|
|
for b, sid in sids.items()
|
|
}
|
|
assert statuses[batches[0]] == "queued"
|
|
assert statuses[batches[1]] == "needs_mapping"
|
|
assert statuses[batches[2]] == "needs_mapping"
|