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

7.0 KiB

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).