Files
roafacturare/docs/cercetare/rec_s7_rotunjire.md
Marius Mutu b5a7108f34 docs: cercetarile comune trec in COMUN, reziduul #6 dispare, progres.md la zi
Curatenie ceruta dupa inchiderea lui #6. Folderul cercetare\ NU se putea sterge
in bloc: plan_13 se sprijina pe el cu 85 de trimiteri, deci e baza de dovezi a
planului aflat in lucru. Impartirea:

- 14 cercetari trans-proiect trec in COMUN\docs\cercetare\ - valuta si curs,
  TVA/VANZARI, consumatorii VANZARI din toata suita, integrarile #10/#11/#12,
  watchdog VFP, proiectarea Oracle a lui S5, view-ul VVANZARI_ARTICOLE. Nu sunt
  ale ROAFACTURARE, iar #10/#11/#12 se reiau chiar din ele.
- 20 de rapoarte de executie ale lui #6, nereferite de nimic viu, sterse.
- 91 raman, neatinse.

Trimiterile catre handoff-urile si diff-urile intermediare deja desfiintate au
fost curatate peste tot (39 de fisiere): 50 catre handoff-uri, 37 catre diff-uri
aplicate, plus caile celor mutate in COMUN. Zero trimiteri rupte ramase.

progres.md preia rolul de predare: ce ramane din #6 (cele sase documente
parazite, cele doua esecuri reale din S8 pe factura din aviz), cifrele de test
citite din log, si cele doua capcane de mediu platite - .FXP vechi executat in
locul .prg-ului, si GETFONT() care atarna un formular instantiat fara goApp.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
2026-08-11 22:31:42 +03:00

11 KiB

S7 — rotunjirea la reeditare. Rezultat

Cerinta din plan (docs\plan_06_editare_factura.md:275-280): verifica_total_document insereaza o linie de corectie in ACT_TEMP cand totalul documentului difera de suma din note; gata cand trei editari consecutive nu lasa trei linii de corectie.

Verdict

Nu se acumuleaza. Mecanismul e marginit prin constructie: nota activa a documentului nu poate contine niciodata mai mult decat o singura generatie de linii de corectie (cel mult 2, cate una pentru fiecare din cele doua verificari ftva/tva), indiferent de cate ori a fost editat documentul inainte. Nu e nevoie de reparatie — nu exista defect.

Dovada pe cod

Sursa: D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql (fisierul real aplicat in baza, nu un export all_source — capcana deja platita in S5, vezi handoff intermediar (sters)).

1. ACT_TEMP e tabela de lucru (scratch), golita automat la fiecare COMMIT/ROLLBACK. Verificat direct din dictionar, nu presupus:

select table_name, temporary, duration from all_tables where table_name in ('ACT_TEMP','ACT');
--> ACT       N  (tabela persistenta)
--> ACT_TEMP  Y  SYS$TRANSACTION   (global temporary table, DURATION = SYS$TRANSACTION)

Un GTT cu DURATION = SYS$TRANSACTION se goleste singur la finalul TRANZACTIEI curente. Decizia 38 (handoff intermediar (sters), deja testata cu scriere reala in S5) stabileste ca fiecare editare ruleaza intr-o singura tranzactie manuala, incheiata cu COMMIT — deci ACT_TEMP porneste mereu goala la inceputul fiecarei editari; nu poate purta randuri dintr-o editare anterioara.

2. verifica_total_document se apeleaza o singura data pe generatie, imediat dupa reconstructia notei. cumuleaza_note_act (:14070-14107):

14078   UPDATE ACT_TEMP SET STERS = 1, TVA_INCASARE = ...
...
14092   pack_facturare.cumuleaza_note_act_temp();
14094   if pack_facturare.ntip <> pack_facturare.nTipNotaPlata then
14095     pack_facturare.verifica_total_document();
14096   end if;

cumuleaza_note_act_temp (:14109-14319) marcheaza tot ce e in ACT_TEMP (deci doar randurile scrise in TRANZACTIA curenta, ACT_TEMP fiind goala la start) STERS=1, reconstruieste randurile prin GROUP BY peste ele (:14215-14312) si sterge randurile pre-agregare (:14318 DELETE FROM ACT_TEMP WHERE STERS = 1). Rezultatul, inainte de verifica_total_document, e un set de randuri agregate, cate unul pe combinatie (scd,scc,...), construit exclusiv din datele editarii curente.

3. Corectia insereaza cel mult un rand per verificare, pe baza totalurilor abia calculate. verifica_total_document (:16276-16690): calculeaza V_TOTFTVA_VER/V_TOTTVA_VER prin SUM peste ACT_TEMP (fara filtrare pe cod, dar ACT_TEMP contine oricum o singura generatie — vezi punctul 1), le compara cu pack_facturare.ntotftva/ntottva (setate mai devreme in acelasi flux) si, la neconcordanta, insereaza UN rand nou, copiat dupa randul-ancora (scd,ascd,scc,ascc, explicatia, etc.) cu suma = diferenta si id_act = max(id_act)+1:

16349  IF NVL(pack_facturare.ntotftva, 0) <> 0 and NVL(pack_facturare.ntotftva, 0) <> V_TOTFTVA_VER THEN
16352    pack_facturare.ndifftva := pack_facturare.ntotftva - V_TOTFTVA_VER;
16353    insert into act_temp (...) select b.id_act, ..., pack_facturare.ndifftva as suma, ...
16456      from act_temp a
16457      left join (select max(id_act) + 1 as id_act, 0 as sters from act_temp) b on a.sters = b.sters
16460     where a.id_act = V_ID_TOTFTVA;
16461  END IF;
16462  IF NVL(pack_facturare.ntottva, 0) <> 0 and NVL(pack_facturare.ntottva, 0) <> V_TOTTVA_VER THEN
         -- acelasi tipar, insereaza a doua linie (verificarea de TVA)
16575  END IF;
16577  IF pack_facturare.ntip in (48, 49) AND (...) THEN
         -- a treia linie, DOAR pentru tip 48/49 (nota de credit/debit) - nu e cazul facturii (tip=1)
16688  END IF;

Fiecare din cele doua/trei IF-uri e evaluat o singura data pe apel, deci maximum 2 linii de corectie pe generatie (3 doar pentru ntip in (48,49)) — niciodata proportional cu numarul de editari anterioare.

4. Blocul vechi e retras integral la fiecare editare, nu doar linia de corectie. OSCRIE_IN_FISIERE(2) (sterge nota veche) + actualizeaza_vanzari marcheaza tot cod-ul vechi STERS=1 — confirmat empiric mai jos, pe 8 generatii reale. Deci nota activa contine mereu rezultatul unei singure generatii, cu cel mult 2 linii de corectie proprii — niciodata suma corectiilor din generatii anterioare.

Dovada pe date, in tranzactie — trei editari consecutive

Suita noua: COMUN\utile\Teste\editare_factura\test_s7_rotunjire.prg (log: COMUN\utile\Teste\editare_factura\test_s7_rotunjire_log.txt).

Acelasi lant real ca in S5 (OSCRIE_IN_FISIERE(2) → OSCRIE_IN_FISIERE(0) → finalizeaza_modificare_nota → ScrieArticoleFacturaEditate), pe id_vanzare = 1049, trei treceri consecutive, fiecare in tranzactia ei proprie, cu COMMIT — fara nicio modificare de continut (reeditare pura, ca sa izoleze exact mecanismul verifica_total_document, nu efectele altor modificari). Dupa fiecare COMMIT s-a citit VANZARI.cod (nou) si s-a numarat in ACT:

  • randurile active (STERS=0) pe cod-ul curent;
  • liniile de corectie, cu semnatura exacta a INSERT-ului de mai sus: aceeasi cheie (scd,scc,nract,dataact,explicatia), cel putin 2 randuri, sume diferite si cu diferenta mica (< 5) — nu orice pereche (scd,scc) duplicata, care poate fi legitim generata de doua linii de detaliu diferite ale documentului (vezi capcana de mai jos).

Rezultat: 6 PASS / 0 FAIL.

Trecere cod inainte -> dupa randuri active ACT linii de corectie
1 1140903 -> 1140904 10 0
2 1140904 -> 1140905 10 0
3 1140905 -> 1140906 10 0

Totalurile documentului au ramas neschimbate (747.96 / 157.06 / 905.02), confirmand ca cele trei treceri au fost reeditari pure, fara alta variabila.

Limitare, consemnata explicit: pe compozitia acestui document, verifica_total_document nu declanseaza NICIODATA neconcordanta (ntotftva = V_TOTFTVA_VER exact, la toate cele 8 generatii verificate — vezi mai jos). Cifra 0/0/0 arata ca randurile nu cresc, dar „zero cazuri in date nu e dovada" — nu demonstreaza prin ea insasi ca, DACA s-ar declansa, corectiile nu s-ar acumula. Pentru asta raspunsul vine din cod (sectiunea de mai sus) si din exemplul real de mai jos.

Capcana prinsa in propria masuratoare — semnatura gresita la prima incercare

Prima versiune a interogarii de numarare (fara filtrul de diferenta mica) a gasit „3 linii de corectie" la fiecare trecere — fals pozitiv. Documentul are legitim doua linii de detaliu active (det=1581, det=1583) care genereaza fiecare propriile perechi (371,378)/(378,371)/(4111,4428) in notă — duplicat structural normal, cu diferente mari intre sume (ex. 126.04, 57.48), nu diferente de rotunjire. Corectat cu filtrul abs(max(suma)-min(suma)) < 5 AND max(suma) <> min(suma) (interogare separata, sqlplus, verificat pe cod 1140900-1140903 dupa corectie: 0 randuri la toate patru) inainte de rularea finala (mai sus). NumaraCorectii din test_s7_rotunjire.prg are acum filtrul corect.

Confirmare independenta: mecanismul chiar functioneaza in productie

Cautare in ACT (an=2026), dupa semnatura exacta a corectiei — cauta orice caz real, nu doar pe documentul de test:

select cod, scd, scc, nract, dataact, count(*) nr, min(suma) smin, max(suma) smax
  from act where an=2026 and sters=0 and id_fact is not null
 group by cod, scd, scc, nract, dataact, explicatia
having count(*) = 2 and min(suma) <> max(suma) and abs(max(suma)-min(suma)) < 5;

Gasit: cod=1140709 (id_fact=8008816, an=2026 luna=3) — id_act=122905 (scd=4428, scc=401, suma=150) si id_act=122906 (acelasi scd/scc/nract/dataact, suma=150.02, diferenta 0.02). Corespunde exact tiparului INSERT-ului: id_act cel mai mare = max(id_act)+1, restul coloanelor copiate de pe randul-ancora, suma = diferenta de rotunjire. Acest document nu a fost editat niciodata dupa (o singura valoare cod), deci nu arata direct comportamentul la editari repetate — dar confirma pe date reale ca mecanismul chiar insereaza, si insereaza exact un rand cand se declanseaza, in acord cu structura codului (un INSERT per IF).

Istoricul complet al documentului de test — randurile nu cresc

id_vanzare=1049 / id_fact=8009659 a fost editat de 8 ori pana acum (S5 + acest test), fiecare generatie verificata in ACT:

cod randuri active la generare linii de corectie
1140887 10 0
1140896 10 0
1140897 10 0
1140898 10 0
1140900 10 0
1140904 10 0
1140905 10 0
1140906 (curent) 10 0

Numarul de randuri e identic la fiecare generatie — regenerare completa, nu acumulare incrementala, consistent cu punctul 4 din dovada pe cod (blocul vechi se retrage integral).

Ce NU acopera cercetarea

  • Niciun caz gasit in productie unde corectia se declanseaza PE UN DOCUMENT editat de mai multe ori — cautarea (an=2026, semnatura stricta) a gasit un singur exemplu real, pe un document editat o singura data. N-a fost fortata o neconcordanta artificiala pe id_vanzare=1049 (ar fi cerut modificarea logicii de calcul a notei, scrie_nota, cateva mii de linii, in afara bugetului acestei cercetari) si nici o cautare exhaustiva pe alti ani/luni.
  • Ramura ntip in (48,49) (a treia linie de corectie, :16577-16688) — nu se aplica facturii de test (tip=1), neexercitata.
  • PACK_CONTAFIN (flux-ul care muta randurile din ACT_TEMP in ACT persistenta) a fost citit doar punctual (INITIALIZEAZA_SCRIERE_ACT_RUL), via ALL_SOURCE (read-only, sqlplus) — nu integral; concluzia despre golirea lui ACT_TEMP se bazeaza pe metadata ALL_TABLES.DURATION (autoritara), nu pe citirea completa a fluxului de flush.

Date de test consumate

Continuare pe id_vanzare = 1049 (deja in lucru din S5, handoff intermediar (sters)): cod realocat suplimentar 1140900 -> 1140901 -> 1140902 -> 1140903 (prima rulare, cu interogarea de numarare gresita — pastrata doar ca generatie reala, nu s-a revenit peste ea) -> 1140904 -> 1140905 -> 1140906 (rularea finala, cea raportata mai sus). Cod curent: 1140906. Niciun det schimbat sau sters suplimentar fata de S5 (toate cele trei treceri au fost reeditari pure); totalurile documentului raman 747.96 / 157.06 / 905.02, identice cu starea de la finalul S5. id_vanzare = 1050 si 1037 — neatinse.

Fisiere atinse

Un singur fisier nou, in COMUN (necomis): COMUN\utile\Teste\editare_factura\test_s7_rotunjire.prg

  • logul test_s7_rotunjire_log.txt. Niciun fisier de productie (.vc2/.sc2/.prg de aplicatie), niciun script de migrare. Zero commit git/SVN.

Stare finala — verificata, nu presupusa

  • Tranzactii Oracle deschise: 0 (v$transaction join v$session pe MARIUSM_AUTO).
  • Procese vfp9.exe ramase: 0 (tasklist).
  • Documentul de test: id_vanzare=1049, cod=1140906, sters=0, totaluri neschimbate.