Files
roafacturare/docs/cercetare/rec_garda_idset.md
Marius Mutu d9f5ca4226 docs: planurile, proiectarile si rapoartele de lucru intra in versionare
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
2026-08-11 22:17:17 +03:00

107 lines
7.0 KiB
Markdown

# Cercetare: garda "id_set distincte in nota" din `do_editare_factura` vs discount editabil (#6)
Sursa: export proaspat `PACK_FACTURARE.pck` din `MARIUSM_AUTO@ROA_CENTRAL` (facut in aceasta
sesiune, 08.08.2026), plus `SELECT text FROM user_views WHERE view_name = 'VACT_TOT'` pe aceeasi
schema. Cod verificat: `COMUN\clase\ofacturare_comun.vc2`, metoda `do_editare_factura`.
## 1. Ce scrie `scrie_discount` si unde ajunge
`PACK_FACTURARE.scrie_discount` (pck:12859-13057): la intrare face
`pack_facturare.nid_set := pack_facturare.nid_set + 5` (:12901), scrie randul `DISCOUNT` in
`ACT_TEMP` cu `ID_SET = pack_facturare.nid_set` (deci +5), cheama `scrie_tva` (tot cu acelasi
`nid_set` +5, deci si randul `TVA DISCOUNT` primeste +5) daca `V_CU_TVA = 1`, apoi **restaureaza**
`pack_facturare.nid_set` la valoarea veche (:13054) inainte de a reveni la apelant. Deci exact
randurile `DISCOUNT`/`TVA DISCOUNT` (si numai ele) ies cu `id_set` +5 fata de restul notei -
confirmat pe cod, nu doar pe progres.md anterior.
`ACT_TEMP` se copiaza in `ACT` la commit-ul tranzactiei (mecanism comun, neschimbat). `vact_tot`
(`user_views`, verificat direct) e un JOIN simplu peste `ACT`, cu `A.ID_SET` expus **neschimbat, ca
atare** - nu exista nicio normalizare/filtrare de `id_set` in view. Deci orice factura ale carei
randuri `ACT` au 2 `id_set` diferite le arata identic si `vact_tot`, si `actactan` (incarcat din
`vact_tot` in `IncarcaCursoareModificareNota`, `COMUN\programe\ofacturare_editare.prg:53`, cu
`ORDER BY id_act`).
**Descoperire suplimentara, relevanta pentru corectitudinea codului (nu doar garda)**: randurile
`DISCOUNT`/`TVA DISCOUNT` scriu `ID_FACT = -1` (variabila locala `V_ID_FACT` initializata `-1` si
niciodata reasignata in nicio ramura a `CASE`-ului din `scrie_discount`) si nu populeaza deloc
`ID_FACTD` (coloana absenta din lista INSERT) - deci raman `NULL`. Un `Go Top` orb pe `actactan`
poate ateriza pe un rand de discount si prelua `id_fact = -1` / `id_factd = NULL` in loc de valorile
reale ale documentului, daca acel rand s-ar intampla sa fie primul in ordinea `id_act`. Cu codul
actual randurile de discount se scriu mereu DUPA liniile de marfa (vezi pct. 2), deci `id_act` le
pune ultimele si `Go Top` "merge" din intamplare - dar nu e o garantie de contract, e o coincidenta
de ordine de scriere.
## 2. Cand se cheama `scrie_discount`
Confirmat 3 cai de apel la nivel de **document** (parametrul `V_DISCOUNT_FACTURA`, discountul de pe
`VANZARI.DISCOUNT`), toate cu tiparul identic "`IF V_DISCOUNT_FACTURA <> 0 THEN scrie_discount(...)`"
dupa bucla de linii:
- `scrie_factura2` (pck:6009-6212, discount la :6992-7006) - calea facturii emise **direct** (nu din
aviz), ex. `frm_facturare_articole`;
- `scrie_factura_avize` (pck:6648-7076, discount la :6985-7007) - facturare din aviz;
- (acelasi tipar exista si la nivel de **linie**, gardat de `pack_facturare.ndiscount_evidentiat = 1
AND discount_unitar <> 0`, in `scrie_factura_avize` :6919-6935, `contabilizeaza_articol` :7496,
`contabilizeaza_rata` :7594 - discount pe linie individuala, nu pe document, dar acelasi mecanism
`id_set+5`).
Deci **orice factura emisa cu codul curent, cu discount de document nenul (`VANZARI.DISCOUNT <>
0`), sau cu discount evidentiat pe cel putin o linie, iese cu 2 `id_set` distincte in `ACT`/
`vact_tot`**. Nu e un caz marginal - e calea normala pentru orice factura cu discount.
Pe `MARIUSM_AUTO` (date de test): 3 facturi cu `VANZARI.DISCOUNT <> 0`, 0 cu >1 `id_set` distinct in
`ACT` pe acelasi `cod` - verificat din nou in aceasta sesiune, acelasi rezultat ca la runda 2. Astea
sunt cele 3 randuri vechi 2008/2014 mentionate deja in `progres.md`, scrise cu o versiune de pachet
de dinainte de introducerea offset-ului `+5` (mecanism care, judecand dupa comentariile din cod,
tine de o reforma ulterioara a contabilizarii discountului). Nu exista nicio factura in datele de
test emisa cu discount **prin codul curent** - de-asta "0 cazuri in date" nu contrazice cazul
posibil prin cod, doar arata ca setul de date nu-l acopera.
## 3. Verdict asupra garzii: **trebuia inlocuita, si a fost**
Garda originala (`lnIdSetDistinct > 1` => refuza editarea) ar fi respins editarea a exact clasa de
facturi pe care decizia 17 (`docs\progres.md`, discountul de document editabil in #6) trebuie sa o
acopere. Confirmat pe cod la pct. 1-2, nu doar pe date.
**Schimbare aplicata** in `do_editare_factura` (`COMUN\clase\ofacturare_comun.vc2:3781-3805`):
in loc sa numere doar `id_set` distincte si sa refuze la >1, acum:
- daca exista un singur `id_set` - neschimbat, editare admisa (comportamentul de dinainte de runda
2);
- daca exista exact 2 `id_set` distincte **si diferenta e exact 5** (relatia exacta scrisa de
`scrie_discount`) - editare admisa, cu `id_set` **principal = cel mic** (liniile de marfa/servicii,
nu randurile de discount) transmis catre `frm_modific2024` si folosit pentru `Locate For id_set =
lnIdSet` (in loc de `Go Top` orb) la citirea `id_fact`/`id_factd` - evita exact capcana de la
pct. 1 (a lua `id_fact=-1` de pe un rand de discount);
- orice alta combinatie (>2 `id_set` distincte, sau exact 2 dar fara relatia +5) - refuza editarea,
cu acelasi mesaj ca inainte; ramane un semnal real ca nota nu e "o factura curata" editabila pe
aceasta cale.
`frm_modific2024` (`omodificari.vc2`) sustine asta structural: `Init(tnIdSet, ...)` seteaza
`This.nid_set` dintr-un SINGUR parametru (folosit pentru predefinire/validari, `:5204-5251`), dar
coloana `id_set` din grid e needitabila (`Column25.ReadOnly = .T.`) si update-ul de completare
`UPDATE tact SET id_set = This.nid_set WHERE EMPTY(NVL(id_set,0))` (`:13365`) **nu suprascrie**
randurile care au deja `id_set` populat - deci un cursor cu randuri mixte (principal + principal+5)
trece nemodificat prin formular, atata timp cat `id_set`-ul "de referinta" transmis la `Init` e cel
principal.
## Fisiere atinse
- `COMUN\clase\ofacturare_comun.vc2` (+ write-back `.vcx`/`.vct`, `txt2vcx.ps1 -AllowComun`,
fidelity check OK) - garda inlocuita, `Go Top` -> `Locate For id_set = lnIdSet`.
- `COMUN\utile\Teste\editare_factura\test_incarca_cursoare.prg` - `verifica_garda_idset_distinct`
inlocuita cu `verifica_garda_idset`, care reproduce exact mecanica noii garzi pe 4 cursoare
sintetice (1 id_set / 2 id_set +5 / 2 id_set fara relatia +5 / 3 id_set) - toate 4 + cele 2
cazuri de regresie (`cod=1140888`, `cod=1140885`) au dat rezultatul asteptat la rulare headless
(`vfp9.exe -A -T`).
- Patch: `docs\diff_runda3_garda_idset.patch` (netrimis la commit, asteapta review).
- Baseline: `COMUN\clase\ofacturare_comun.vc2.pre_runda3.bak`.
## Netestat
- Fluxul real UI (`frm_modific2024` deschis pe o factura cu discount de document) - nu exista
candidat in datele de test (0 facturi cu discount emise prin codul curent, cf. pct. 2). Verificat
doar prin harness fara UI, pe cursoare sintetice care reproduc exact forma datelor descrise de
cod.
- Write-back-ul real (`OSCRIE_IN_FISIERE` + `finalizeaza_modificare_nota`) pe un asemenea caz -
neatins, la fel ca in rundele anterioare (evitat deliberat, nu scrie in schema de dev intr-un test
automat).