# Date de test - NNIR editabil in Registru Jurnal Baza: `MARIUSM_AUTO@ROA_CENTRAL` (test, nu productie). Verificare: `verif_nnir_cod.sql` in acest folder (`sqlplus ... @verif_nnir_cod.sql `). | Caz | COD | AN | LUNA | ID_SET | NNIR curent | ACT randuri | RUL randuri | RUL_OBINV randuri | |---|---|---|---|---|---|---|---|---| | NIR/achizitie (principal) | 1140841 | 2026 | 7 | 209 | 3 | 7 (doar 1 cu nnir=3, restul 0) | 1 (nnir=3) | 0 | | Obiecte de inventar | 1140835 | 2026 | 6 | 211 | 2026060001 | 1 | 0 | 2 (nnir=2026060001) | | Fara rulaje | 1140848 | 2026 | 7 | 209 | 124 | 2 (ambele nnir=124) | 0 | 0 | | Nota de inventar (blocare) | 1140716 | 2026 | 3 | 90101 | 2026030004 | 1 | 1 (nnir=2026030004) | 0 | Note: - ACT e pe linii (nu pe antet) - la COD 1140841 doar linia efectiv legata de rulaj are NNIR-ul real, restul liniilor documentului au NNIR=0. Sincronizarea (`WHERE Nvl(nnir,0) = vechi`) trebuie sa lase liniile cu 0 neatinse. - Nu exista nicio nota cu `id_set=90101` sau cu rulaje in `RUL_OBINV` in luna curenta de lucru (AN=2026, LUNA=7) - alese din perioade anterioare. Editarea reala prin `afisjurcom.do_modifica` e limitata la luna curenta (`comun.vc2:2265-2268`); testul instantiaza `frm_modific2024` direct (ca `test_repro_cnrcrt_footer.prg`), cu cursoare construite pe AN/LUNA propriu notei, ocolind acel filtru - la fel ca precedentul deja acceptat in `achizitie_import`. ## Stare implementare (livrata, 03.08.2026) `COMUN\clase\omodificari.vc2` (frm_modific2024): - `Grid1.ColumnCount = 44`, `Column44.ControlSource = "nnir"` (la runtime apare calificat automat de VFP cu aliasul cursorului: `tact.nnir`), `ReadOnly = .F.` - confirmat prin instantiere reala (nu doar citire de sursa). - `PROCEDURE sincronizeaza_nnir(tnNnirVechi, tnNnirNou)` (`omodificari.vc2:13762`) - update pe `tact`/`trul`/`trul_obinv` unde `Nvl(nnir,0) = vechi`, cu revenire pe recno. Propaga si valoarea 0 (stergerea NNIR) - nu exista garda `EMPTY` pe valoarea noua. - Legare pe coloana: `Grid1.Column44.Text1.When` retine valoarea veche in `thisform.nnnirvechi`; **`Grid1.Column44.Text1.LostFocus`** apeleaza `sincronizeaza_nnir` si `Thisform.Grid1.Refresh()` - `Valid` a fost eliminat (la textbox valoarea nu ajunge in ControlSource decat DUPA ce Valid returneaza .T., deci nu propaga). Testul declanseaza `LostFocus`. - Blocarea pentru `id_set = 90101` (nota de inventar): in `Init` (`omodificari.vc2:13654`) SI reimpusa in `Grid1.AfterRowColChange` (14289-14292), dupa `SetAll("ReadOnly", ...)` - fara a doua, `SetAll` anuleaza blocarea la prima navigare in grid. - `ColumnOrder = 7` in clasa, plus repozitionare la runtime in `Show()`, dupa `gridextra1.setup()` (13729-13738) - preferintele de grid salvate per utilizator impingeau coloana noua la coada (vezi `COMUN\docs\capcana_grid_preferinte_utilizator.md`). Pozitia NU e o asertiune stabila intre masini; asertat tare in test: `ControlSource = "nnir"`, `ReadOnly` (.F. normal / .T. pe id_set 90101), propagarea valorii. ## Cerinte de mediu descoperite la construirea harness-ului (deja tratate in scripturile livrate) - `COMUN\utile\Teste\test_init_env_auto.prg` (generic) e de fapt specific ROACONT (`gcAppPath`, classlib-uri si proceduri hardcodate `D:\ROA\ROACONT\`) - inutilizabil pentru ROAGEST. S-a scris `COMUN\utile\Teste\test_init_env_auto_roagest.prg`, cu SET PATH/CLASSLIB/PROCEDURE reconstruite din `Programe\roagest.prg`. - `gcUserName` trebuie setat explicit inainte de `optiuni_firma` (`oinit_optiuni.prg`) - altfel `SCRIE_OPTIUNI(gcUserName)` da "Operator/operand type mismatch" (PUBLIC nedeclarat ramane logic .F.). **`gcUserName` e schema/userul de conectare Oracle** (`Programe\roagest.prg:560,575`) - `SCRIE_OPTIUNI` il foloseste direct in `from .optiuni`, deci trebuie `gcUserName = m.gcS`, NU un nume de persoana (ex. 'MARIUS M' da ORA-00907, identificator invalid - incercare gresita initiala). Numele de persoana e `gcUserNameApp` (variabila separata). - `frm_modific2024` face `Seek(..,'crsJtvaTemp','id_jtva')` in ControlSource-ul coloanei de explicatie TVA a rulajelor (Column63) - evaluat la CONSTRUCTIA formularului. Fara cursorul deschis, `CREATEOBJECT('frm_modific2024',...)` pica cu "File 'crsjtvatemp.dbf' does not exist". Fix: `update_jtva_coloane('', 'crsJtvaTemp', 6)` (in `COMUN\programe\updateserver.prg:553`) inainte de instantiere - construieste direct cursorul cu indexul cerut, fara pasii intermediari folositi de exemplul ROACONT (`update_jtva_coloana`/`crsExplicatiiTVATemp`, care oricum nu exista in ROAGEST). - Mock-ul `amessagebox` trebuie incarcat **INAINTE** de `test_init_env_auto_roagest.prg` (nu doar dupa, cum sugereaza exemplele din `achizitie_import`) - `optiuni_firma` poate afisa un dialog real daca `SCRIE_OPTIUNI` raporteaza eroare, inainte sa apuce sa se incarce mock-ul "la coada". - La citirea unei coloane de grid prin ControlSource dintr-un cursor legat ca RecordSource, VFP calificat automat campul simplu cu aliasul (`nnir` -> `tact.nnir`) - comparatiile exacte `== 'NNIR'` trebuie sa accepte si forma calificata. - Coloanele de grid nu sunt garantat numite `Column` - unele au `Name` custom (ex. `cAles` pe pozitia 41 in acest grid); accesul dinamic la coloana trebuie facut prin colectia `Grid1.Columns(i)`, nu prin constructia textuala a numelui `"column" + TRANSFORM(i)`. - `frm_modific2024.Grid1.AfterRowColChange` are propria logica de blocare pe sucursala (SetAll ReadOnly pe toate coloanele daca `Nvl(gnIdSucursala,0) <> Nvl(tAct.id_sucursala,0)`) - independenta de blocarea 90101, se declanseaza automat la pozitionare in grid. COD 1140835 (cazul obiecte de inventar) are `id_sucursala` diferit de sesiunea de test (`gnIdSucursala = NULL`), deci Column44 iese `ReadOnly=.T.` in acest scenariu - nu e o eroare, e comportament existent, neplanificat de NNIR; sincronizarea tot functioneaza (apelul e direct, nu prin UI). - **Termin reatribuie COD nou**: `afisjurcom.do_modifica` (comun.vc2:2444-2487) cheama `oscrie_in_fisiere` de DOUA ori - intai `(2,.T.,llRul)` (STERGE, marcheaza `sters=1` pe COD-ul ORIGINAL, din `actactan` neatins de editare), apoi `(0,.T.,llRul)` (SCRIE varianta editata sub COD nou, generat de `pack_contafin`, sub AN/LUNA de sesiune curenta - nu pastreaza COD-ul/AN/LUNA notei editate). Verificarea si curatenia testului se fac dupa NNIR (marcaj distinct), nu dupa COD, si readuc nota originala la `sters=0` dupa test (pasul STERGE o dezactiveaza altfel permanent). - Salvarea reala cere tranzactie manuala explicita: `SQLSetProp(gnHandle,'Transactions',2)` inainte de blocul STERGE+SCRIE+finalizeaza, apoi `SQLCOMMIT(gnHandle)`/`SQLROLLBACK` + `SQLSetProp(...,1)` dupa - echivalentul direct al `thisform.do_deschide_tranzactie()`/ `do_inchide_tranzactie()` din `afisjurcom` (`_frm_base.vc2:252-305`, mostenite, apelate pe formularul de jurnal - nu pe `frm_modific2024`, deci invizibile la o privire doar pe clasa notei). Fara acest wrapping, `oscrie_in_fisiere`/`finalizeaza_modificare_nota` raporteaza succes dar nu se vede nimic persistat, nici in aceeasi sesiune. ## Capcana: .FXP stale ascunde scenariile noi VFP nu recompileaza .prg-ul daca exista un .FXP mai vechi - ruleaza tacut versiunea veche a scriptului. Simptom: suita raporteaza PASS-uri corecte, dar scenariile adaugate dupa ultima compilare nu apar deloc in log (verifica numarul de assert-uri, nu doar `0 FAIL`). Sterge .FXP-ul inainte de fiecare rulare. ## Capcana: dialog modal "Enter the value for " in loc de eroare catchabila O variabila memorie lipsa/umbrita folosita ca `?param` intr-un SQL pass-through (SQLEXEC/ `goExecutor.oExecuta`) NU da o eroare VFP catchabila (ON ERROR) - deschide dialogul nativ "View Parameter" ("Enter the value for "), MODAL, care blocheaza tot procesul headless la nesfarsit si nu lasa nimic in log (spre deosebire de un `REPLACE`/expresie cu aceeasi variabila lipsa, care DA eroare catchabila - vezi cazul `gnIdUtil` scapat o data ca `PRIVATE` neasignat). Simptom: proces `vfp9.exe` care nu mai raspunde, fara `.ERR`, fara linie noua in log. Remediu: **garda explicita inainte de orice rulare care ajunge la cod ce foloseste `?param`** - verifica `TYPE() == 'U'` pe toate variabilele relevante (nu doar cele proprii testului, ci si cele din codul apelat: `oscrie_in_fisiere`, `pack_contafin`/`pack_sesiune`, `oinit_optiuni.prg`) si opreste testul cu FAIL clar in log daca lipseste ceva, inainte sa ajunga la SQLEXEC. Implementat in `test_nnir_sincronizare.prg` (`NnirGardaVariabile`, apelata imediat dupa init mediu). `TYPE()` returneaza `'X'` (nu `'U'`) pentru NULL - o valoare NULL e un bind valid, doar variabila absenta e problema. ## Rezultat test complet (03.08.2026, pe binarul livrat) **33 PASS, 0 FAIL** pe cele 6 scenarii: NIR, obiecte de inventar si nota fara rulaje (toate cu salvare reala prin Termin + verificare in Oracle), blocare `id_set=90101`, `NNIR -> 0`, si blocare `id_set=90101` pe sucursala curenta. Baza de test verificata dupa rulare: cele 4 note originale (1140841, 1140835, 1140848, 1140716) raman intacte (NNIR si `sters` la valorile initiale); notele noi create de Termin (COD reatribuit) au fost marcate `sters=1` de curatenia din test. Scenariul 6 (`INVENTAR2`) exista pentru ca scenariul 4 ruleaza pe o nota din ALTA sucursala, unde `AfterRowColChange` blocheaza oricum tot gridul - trecea din motivul gresit. Scenariul 6 aliniaza `gnIdSucursala` la nota (`llReadOnly` iese `.F.`) si asertesteaza si ca restul coloanelor raman editabile, altfel blocarea NNIR nu dovedeste nimic.