Skip to content

anaf-sync 0.6.1 — facturile `unknown` se pot repara acum, pe toate sistemele

Latest

Choose a tag to compare

@github-actions github-actions released this 31 Jul 07:57

Versiunea 0.6.0 a ajuns pe PyPI, dar nu a primit niciodată o pagină de release
și nici programe descărcabile: pasul care le construiește a picat pe Windows,
după publicare — a doua oară după 0.5.0, din alt motiv. Conținutul ei e inclus
mai jos, iar 0.6.1 e versiunea completă. Dacă ai instalat deja 0.6.0 de pe
PyPI, ai tot ce e descris la Îmbunătățiri; îți lipsește doar remedierea de la
Remedieri, care privește aplicația de pe Windows.

Îmbunătățiri

Facturile care apar cu unknown se pot repara. Se poate întâmpla ca
descărcarea să reușească, dar citirea XML-ului să nu: ANAF acceptă un document
pe care versiunea instalată de anafpy nu îl poate încă interpreta. Factura
se arhivează oricum — ZIP-ul semnat e scopul — dar tot ce se deduce din XML se
prăbușește în unknown: numărul, data, partenerul și valoarea din fereastra
Facturi, plus calea pe disc, care devine un folder unknown.

Până acum nu exista cale de întoarcere. Evidența nu revizitează niciodată un
mesaj deja arhivat — regula care garantează că nimic nu se descarcă de două
ori — iar după 60 de zile nici măcar sync --redownload nu mai ajunge la el.
Rândul rămânea greșit definitiv, oricât de mult ar fi învățat anafpy între
timp să citească.

Dovada nu s-a pierdut însă niciodată: XML-ul facturii stă permanent în ZIP-ul
arhivat. Exact pe asta se bazează și repararea PDF-urilor din 0.5.1, doar că
acum se aplică datelor și căii, nu randării:

anaf-sync reprocess --dry-run          # arată ce s-ar corecta
anaf-sync reprocess                    # recitește ZIP-urile și corectează catalogul
anaf-sync reprocess --move --dry-run   # și unde s-ar muta fișierele
anaf-sync reprocess --move             # le mută pe calea dată de șablon

Fără --move se schimbă doar ce se vede în aplicație; fișierele rămân exact
unde sunt. Cu --move se recalculează și calea din șablon, se mută acolo toate
fișierele facturii și se șterge folderul unknown rămas gol. Dacă o factură
tot nu poate fi citită, comanda o numără separat, pe unreadable: atunci
merită raportată, iar o versiune mai nouă de anafpy plus încă o rulare a
aceleiași comenzi rezolvă restul.

Comanda nu cere autentificare și nu atinge rețeaua deloc, deci o arhivă veche
de ani se repară la fel de bine ca una de azi.

Un buton pentru fiecare factură, în fereastra Facturi. Panoul din dreapta
are acum „Recitește din arhivă” — aceeași operație, pentru o singură
factură. Pe rândurile cărora le lipsesc toate datele apare evidențiat, sub o
explicație a motivului: descărcarea a reușit, doar citirea nu, iar originalul
semnat e intact pe disc. Pe celelalte rânduri rămâne discret, ca să poți
re-așeza o factură după ce schimbi șablonul, fără să reorganizezi toată arhiva.

Facturile catalogate cu backfill au butonul dezactivat, cu motivul în tooltip:
sunt foldere pe care anaf-sync nu le administrează, așa că nu le rescrie
fișierele.

reprocess --move e și modul corect de a reorganiza arhiva după ce schimbi
template.
Rearanjează local fișierele deja descărcate, spre deosebire de
sync --redownload, care poate aduce din nou doar ce se mai află în fereastra
de 60 de zile. Rulează întâi cu --dry-run, ca să vezi câte fișiere s-ar muta.

Remedieri

Pe Windows, aplicația nu mai rămâne blocată pe „Se sincronizează…”. Dacă
pornirea comenzii eșua — de pildă pentru că programul anaf-sync nu se mai
găsea acolo unde fusese instalat — meniul rămânea dezactivat definitiv, iar
butonul de reparare din fereastra Facturi la fel: aplicația aștepta un proces
care nu pornise niciodată, așa că nimic nu mai venea să o deblocheze. Singura
ieșire era repornirea aplicației.

Windows anunță o pornire eșuată pe loc, spre deosebire de macOS și Linux, care
o anunță o clipă mai târziu; aplicația trata cele două anunțuri în ordinea
greșită. Acum ordinea e garantată pe toate sistemele, iar un eșec de pornire
readuce meniul la loc, ca oricare altă rulare încheiată.

Internal

  • What a re-projection may not invent. message_type and created_at
    (data_creare, which the delay flag reads) come only from ANAF's listing,
    which is long gone by the time anything is reprocessed — so the stored row
    keeps them, along with cif, direction, saved_at and the message id.
    Re-deriving them as None would silently turn "unknown delay" into "on
    time". context.project_archived is the third door onto the module's single
    parse, carrying exactly those facts back in.
  • request_id refuses the move. It is the one path variable with no home
    in any artifact, so a template referencing it errors up front rather than
    rendering unknown over paths that already hold the real value. The catalog
    refresh has no such dependency and still runs.
  • Moves are planned before they are applied. An occupied destination
    refuses that message (its catalog is still refreshed); a destination whose
    source is gone is recognised as a move a previous run already made; and the
    file the pass re-read the message from moves last, so an interrupted run
    resumes. Files land before the row does — a crash between them leaves a
    stale pointer with every byte intact, where the reverse would point the row
    at files that never arrived.
  • SyncRunner is now CliRunner, with one in-flight guard across every
    subcommand the tray spawns. Two tray-spawned children would meet at the sync
    lock and the second would die on it, so the UI does not offer the second
    click.
  • ARTIFACT_SUFFIXES moves to config, shared by backfill and
    reprocess instead of copied.
  • CliRunner emits started before it calls QProcess.start(). Windows
    fails a launch inside start(); POSIX defers the same error to the event
    loop. Emitting afterwards delivered finished before started on Windows
    only, and the tray's two handlers then ran in the order that leaves the UI
    disabled forever. This is what broke 0.6.0's release: the tray suite — which
    0.5.1 had just started running on Windows in CI, precisely to stop finding
    these at release time — caught it, but on the release job's leg, after the
    publish step had already put 0.6.0 on PyPI.
  • The tray runner's tests fake at the QProcess seam. They used to aim at
    a missing executable and assert the in-flight guard still held, which is only
    true where the failure is deferred — a test that encoded one platform's
    timing as the contract. A fake process makes the guard's lifetime the
    runner's own, and a variant that fails synchronously pins the signal order on
    every platform.

⚠️ Verificare. Comanda reprocess are teste peste facturi UBL reale
(recitire, mutare, mutare întreruptă și reluată, destinație ocupată, arhive
fără ZIP) și a fost rulată cap-coadă pe o arhivă de probă: factura a ieșit din
unknown, folderul gol a dispărut, catalogul s-a completat și a doua rulare
nu a mai avut ce face. Nu a fost însă rulată pe o arhivă reală de
producție
— dacă --move se poartă altfel pe un volum de sute de facturi,
spune. Rulează întâi --dry-run, și ai oricând ZIP-urile semnate ca sursă de
adevăr. Blocajul de pe Windows are un test care reproduce eșecul sincron, dar
nu a fost verificat pe un Windows real — dacă meniul tot rămâne blocat
după o pornire eșuată, spune.

⚠️ The bundles are unsigned — no macOS notarization, no Windows
Authenticode. First run triggers the usual OS warning; use the
right-click-open workaround documented in the README. The CLI on PyPI
(pip install anaf-sync) is unaffected.

Full changelog: v0.6.0...v0.6.1