Files
comun/utile/Teste/nnir_registru_jurnal/date_test_nnir.md

9.4 KiB

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

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 <gcUserName>.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<N> - 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(<nume>) == '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.