Files
roafacturare/docs/cercetare/rec_garda_idset.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

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: diff aplicat (sters) (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).