Folderul docs\ era pana acum in afara oricarui control de versiuni - nici git, nici SVN - desi contine planurile pe puncte, proiectarile si rapoartele de cercetare pe care se sprijina modificarile din cod. O stergere acolo era definitiva. Fisierele intermediare (handoff-uri intre sesiuni, diff-uri deja aplicate) au fost sterse inainte, nu versionate: ce era durabil in ele a intrat in antetele fisierelor de test la care se refereau. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
205 lines
11 KiB
Markdown
205 lines
11 KiB
Markdown
# 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
|
|
`docs\handoff_s5.md`).
|
|
|
|
**1. `ACT_TEMP` e tabela de lucru (scratch), golita automat la fiecare COMMIT/ROLLBACK.**
|
|
Verificat direct din dictionar, nu presupus:
|
|
|
|
```sql
|
|
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
|
|
(`docs\handoff_s5.md`, 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:
|
|
|
|
```sql
|
|
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, `docs\handoff_punct6_dupa_s5.md`):
|
|
`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.
|