* test_nnir_sincronizare.prg
* Test e2e (fluxul real): NNIR editabil in Registru Jurnal, cu sincronizare in tact/trul/trul_obinv
* si in ACT/RUL/RUL_OBINV (Oracle). Vezi cerinta initiala (todos.txt pct. 9) si
* date_test_nnir.md (datele de test alese, an/luna/cod, stare implementare la data scrierii).
*
* Instantiaza frm_modific2024 direct (ca test_repro_cnrcrt_footer.prg din achizitie_import),
* cu cursoarele tact/trul/trul_obinv construite exact ca afisjurcom.do_modifica (comun.vc2:2352-
* 2434), dar pe AN/LUNA proprii notei - do_modifica limiteaza editarea la luna curenta de lucru
* (comun.vc2:2265-2268), iar notele de test nu sunt toate in luna curenta.
*
* Editarea NNIR se simuleaza ca un utilizator: pozitionare pe rand, declansarea evenimentelor
* reale ale coloanei (When la intrare, LostFocus la iesire - textboxul nu comite valoarea in
* ControlSource inainte de Valid, de-aia implementarea sincronizeaza pe LostFocus), NU apel
* direct al metodei de sincronizare. Salvarea (Termin) replica blocul din
* afisjurcom.do_modifica (comun.vc2:2456-2487): oscrie_in_fisiere + pack_contafin.
* finalizeaza_modificare_nota. Termin reatribuie COD nou (pack_contafin), sub AN/LUNA de sesiune
* curenta - nu pastreaza COD-ul original; verificarea si curatenia de dupa salvare se fac dupa
* valoarea NNIR marcaj (nu poate coincide cu date reale), marcand sters=1 (conventia aplicatiei)
* orice a ajuns sub acea valoare - nota originala (COD/NNIR vechi) ramane intacta.
*
* Rulare headless (nu tine VFP IDE deschis; nu rula cu roagest.exe pornit):
*   & "C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe" -A -T ;
*     "D:\ROA\ROAGEST\COMUN\utile\Teste\nnir_registru_jurnal\test_nnir_sincronizare.prg"
* Timeout recomandat: minim 220s. Log: %TEMP%\test_nnir_sincronizare_log.txt (PASS/FAIL pe linie).
* STERGE .FXP-ul inainte de rulare: VFP nu recompileaza automat si ruleaza tacut versiunea
* veche a scriptului - scenariile adaugate intre timp lipsesc cu totul din log.

LPARAMETERS tcMode
tcMode = IIF(EMPTY(tcMode), 'ALL', UPPER(ALLTRIM(tcMode)))

SET SAFETY OFF
SET TALK OFF

PUBLIC gcLogFile, gnFail, gnPass
gcLogFile = ADDBS(SYS(2023)) + 'test_nnir_sincronizare_log.txt'
gnFail = 0
gnPass = 0
STRTOFILE('START ' + tcMode + ' ' + TTOC(DATETIME()) + CHR(13)+CHR(10), gcLogFile)

ON ERROR DO NnirErr WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
ON SHUTDOWN QUIT

* mock amessagebox incarcat INAINTE de mediul aplicatiei: optiuni_firma (in mediul de test)
* poate afisa un dialog real daca SCRIE_OPTIUNI raporteaza eroare
SET PROCEDURE TO D:\ROA\ROAGEST\COMUN\utile\Teste\mock_amessagebox.prg ADDITIVE
DO D:\ROA\ROAGEST\COMUN\utile\Teste\test_init_env_auto_roagest.prg WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT'
IF gnHandle <= 0
	DO NnirLog WITH 'EROARE: conectare Oracle esuata'
	DO NnirLog WITH 'REZULTAT SUITA: NEDETERMINAT'
	QUIT
ENDIF
DO NnirLog WITH 'mediu OK, gnAn=' + TRANSFORM(gnAn) + ' gnLuna=' + TRANSFORM(gnLuna)

* garda anti-blocaj: o variabila lipsa folosita ca ?param intr-un SQL pass-through NU da eroare
* catchabila - VFP deschide dialogul modal nativ "Enter the value for <var>", care blocheaza
* headless-ul la nesfarsit si nu lasa nimic in log (vezi date_test_nnir.md). Verificare
* explicita INAINTE de orice apel care le foloseste, opreste testul cu FAIL clar daca lipseste ceva.
IF !NnirGardaVariabile()
	DO NnirLog WITH 'REZULTAT SUITA: NEDETERMINAT (garda variabile a picat)'
	QUIT
ENDIF

* mock amessagebox - se incarca ULTIMUL (dupa fisierele aplicatiei), vezi antetul mock-ului
SET PROCEDURE TO D:\ROA\ROAGEST\COMUN\utile\Teste\mock_amessagebox.prg ADDITIVE

* Grid1.Column63 (explicatie TVA pe rulaje) face Seek pe alias 'crsJtvaTemp' la CONSTRUCTIA
* formularului (inainte de Init) - fara cursorul deschis, CREATEOBJECT('frm_modific2024',...)
* pica cu "File 'crsjtvatemp.dbf' does not exist"
update_jtva_coloane('', 'crsJtvaTemp', 6)

LOCAL Omodif, lcCallWhen, lcCallLostFocus, lcCall

*=====================================================================================
* Scenariul 1: NIR/achizitie, cu rulaje in RUL, cu salvare (Termin) + verificare Oracle
*=====================================================================================
IF INLIST(tcMode, 'ALL', 'NIR')
	LOCAL lnCod, lnAn, lnLuna, lnIdSet, lnNnirVechi, lnNnirNou
	LOCAL lnCntTactVechi, lnCntTrulVechi, lnCntTactNou, lnCntTrulNou
	LOCAL i, llGasit, lnColOrder, llReadOnly, lnColCheck, lcColName

	lnCod = 1140841
	lnAn = 2026
	lnLuna = 7
	lnIdSet = 209
	lnNnirVechi = 3
	lnNnirNou = lnNnirVechi + 90000000

	DO NnirConstruiesteCursoare WITH lnCod, lnAn, lnLuna

	SELECT tact
	lnCntTactVechi = 0
	COUNT FOR NVL(nnir,0) = lnNnirVechi TO lnCntTactVechi
	SELECT trul
	lnCntTrulVechi = 0
	COUNT FOR NVL(nnir,0) = lnNnirVechi TO lnCntTrulVechi

	Omodif = CREATEOBJECT('frm_modific2024', lnIdSet)
	IF VARTYPE(Omodif) <> 'O'
		DO NnirAssert WITH 'instantiere', 'NIR', .F., 'frm_modific2024 nu s-a instantiat'
	ELSE
		SELECT tact
		Omodif.grid1.SetFocus
		Omodif.gridextra1.setup()
		Omodif.CalculeazaTotal()

		llGasit = .F.
		lnColOrder = 0
		llReadOnly = .T.
		lnColCheck = 0
		FOR i = 1 TO Omodif.grid1.ColumnCount
			lcColName = 'Omodif.grid1.Columns(' + TRANSFORM(i) + ')'
			IF NnirEsteColoanaNnir(EVALUATE(lcColName + '.ControlSource'))
				llGasit = .T.
				lnColOrder = EVALUATE(lcColName + '.ColumnOrder')
				llReadOnly = EVALUATE(lcColName + '.ReadOnly')
				lnColCheck = i
			ENDIF
		ENDFOR
		DO NnirAssert WITH 'coloana_grid', 'NIR', llGasit, 'ControlSource=nnir gasit=' + ;
			TRANSFORM(llGasit) + ' ColumnOrder=' + TRANSFORM(lnColOrder) + ' ReadOnly=' + TRANSFORM(llReadOnly)

		IF llGasit
			DO NnirAssert WITH 'coloana_editabila', 'NIR', !llReadOnly, 'nota normala: ReadOnly asteptat .F.'

			SELECT tact
			LOCATE FOR NVL(nnir,0) = lnNnirVechi
			IF FOUND()
				lcCallWhen = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheck) + ').Text1.When'
				&lcCallWhen
				REPLACE nnir WITH lnNnirNou
				lcCallLostFocus = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheck) + ').Text1.LostFocus'
				&lcCallLostFocus

				SELECT tact
				lnCntTactNou = 0
				COUNT FOR NVL(nnir,0) = lnNnirNou TO lnCntTactNou
				DO NnirAssert WITH 'sync_tact', 'NIR', lnCntTactNou = lnCntTactVechi, ;
					TRANSFORM(lnCntTactNou) + ' randuri tact cu nnir nou (asteptat ' + TRANSFORM(lnCntTactVechi) + ')'

				* trul = cursorul legat de pgfArticole.page1.grdRulaje (RecordSource) - verificare
				* explicita ca propagarea se vede in cursorul de rulaje, nu doar in tact
				SELECT trul
				lnCntTrulNou = 0
				COUNT FOR NVL(nnir,0) = lnNnirNou TO lnCntTrulNou
				DO NnirAssert WITH 'sync_trul', 'NIR', lnCntTrulNou = lnCntTrulVechi, ;
					TRANSFORM(lnCntTrulNou) + ' randuri trul (grid rulaje) cu nnir nou (asteptat ' + TRANSFORM(lnCntTrulVechi) + ')'
			ELSE
				DO NnirAssert WITH 'locate_rand_vechi', 'NIR', .F., 'nu s-a gasit randul cu nnir vechi in tact'
			ENDIF
		ENDIF

		DO NnirVerificaOracleNeschimbat WITH lnCod, lnNnirVechi, 'NIR'

		Omodif.Release()
		Omodif = NULL
		DO NnirSalveazaSiVerifica WITH lnCod, lnAn, lnLuna, lnIdSet, lnNnirVechi, lnNnirNou, 'NIR'
	ENDIF
	DO NnirCurataCursoare
ENDIF

*=====================================================================================
* Scenariul 2: obiecte de inventar, cu rulaje in RUL_OBINV, cu salvare + verificare Oracle
*=====================================================================================
IF INLIST(tcMode, 'ALL', 'OBINV')
	LOCAL lnCod2, lnAn2, lnLuna2, lnIdSet2, lnNnirVechi2, lnNnirNou2
	LOCAL lnCntTactVechi2, lnCntRobinvVechi2, lnCntTactNou2, lnCntRobinvNou2
	LOCAL i2, llGasit2, lnColOrder2, llReadOnly2, lnColCheck2, lcColName2

	lnCod2 = 1140835
	lnAn2 = 2026
	lnLuna2 = 6
	lnIdSet2 = 211
	lnNnirVechi2 = 2026060001
	lnNnirNou2 = lnNnirVechi2 + 90000000

	DO NnirConstruiesteCursoare WITH lnCod2, lnAn2, lnLuna2

	SELECT tact
	lnCntTactVechi2 = 0
	COUNT FOR NVL(nnir,0) = lnNnirVechi2 TO lnCntTactVechi2
	SELECT trul_obinv
	lnCntRobinvVechi2 = 0
	COUNT FOR NVL(nnir,0) = lnNnirVechi2 TO lnCntRobinvVechi2

	Omodif = CREATEOBJECT('frm_modific2024', lnIdSet2)
	IF VARTYPE(Omodif) <> 'O'
		DO NnirAssert WITH 'instantiere', 'OBINV', .F., 'frm_modific2024 nu s-a instantiat'
	ELSE
		SELECT tact
		Omodif.grid1.SetFocus
		Omodif.gridextra1.setup()
		Omodif.CalculeazaTotal()

		llGasit2 = .F.
		lnColOrder2 = 0
		llReadOnly2 = .T.
		lnColCheck2 = 0
		FOR i2 = 1 TO Omodif.grid1.ColumnCount
			lcColName2 = 'Omodif.grid1.Columns(' + TRANSFORM(i2) + ')'
			IF NnirEsteColoanaNnir(EVALUATE(lcColName2 + '.ControlSource'))
				llGasit2 = .T.
				lnColOrder2 = EVALUATE(lcColName2 + '.ColumnOrder')
				llReadOnly2 = EVALUATE(lcColName2 + '.ReadOnly')
				lnColCheck2 = i2
			ENDIF
		ENDFOR
		DO NnirAssert WITH 'coloana_grid', 'OBINV', llGasit2, 'ControlSource=nnir gasit=' + ;
			TRANSFORM(llGasit2) + ' ColumnOrder=' + TRANSFORM(lnColOrder2) + ' ReadOnly=' + TRANSFORM(llReadOnly2)

		IF llGasit2
			SELECT tact
			LOCATE FOR NVL(nnir,0) = lnNnirVechi2
			IF FOUND()
				lcCallWhen = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheck2) + ').Text1.When'
				&lcCallWhen
				REPLACE nnir WITH lnNnirNou2
				lcCallLostFocus = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheck2) + ').Text1.LostFocus'
				&lcCallLostFocus

				SELECT tact
				lnCntTactNou2 = 0
				COUNT FOR NVL(nnir,0) = lnNnirNou2 TO lnCntTactNou2
				DO NnirAssert WITH 'sync_tact', 'OBINV', lnCntTactNou2 = lnCntTactVechi2, ;
					TRANSFORM(lnCntTactNou2) + ' randuri tact cu nnir nou (asteptat ' + TRANSFORM(lnCntTactVechi2) + ')'

				SELECT trul_obinv
				lnCntRobinvNou2 = 0
				COUNT FOR NVL(nnir,0) = lnNnirNou2 TO lnCntRobinvNou2
				DO NnirAssert WITH 'sync_trul_obinv', 'OBINV', lnCntRobinvNou2 = lnCntRobinvVechi2, ;
					TRANSFORM(lnCntRobinvNou2) + ' randuri trul_obinv cu nnir nou (asteptat ' + TRANSFORM(lnCntRobinvVechi2) + ')'
			ELSE
				DO NnirAssert WITH 'locate_rand_vechi', 'OBINV', .F., 'nu s-a gasit randul cu nnir vechi in tact'
			ENDIF
		ENDIF

		Omodif.Release()
		Omodif = NULL
		DO NnirSalveazaSiVerificaObinv WITH lnCod2, lnAn2, lnLuna2, lnIdSet2, lnNnirVechi2, lnNnirNou2
	ENDIF
	DO NnirCurataCursoare
ENDIF

*=====================================================================================
* Scenariul 3: nota fara rulaje - regresie (nu crapa), cu salvare + verificare Oracle
*=====================================================================================
IF INLIST(tcMode, 'ALL', 'FARARUL')
	LOCAL lnCod3, lnAn3, lnLuna3, lnIdSet3, lnNnirVechi3, lnNnirNou3
	LOCAL lnCntTactVechi3, lnCntTactNou3
	LOCAL i3, llGasit3, lnColCheck3, lcColName3

	lnCod3 = 1140848
	lnAn3 = 2026
	lnLuna3 = 7
	lnIdSet3 = 209
	lnNnirVechi3 = 124
	lnNnirNou3 = lnNnirVechi3 + 90000000

	DO NnirConstruiesteCursoare WITH lnCod3, lnAn3, lnLuna3

	SELECT tact
	lnCntTactVechi3 = 0
	COUNT FOR NVL(nnir,0) = lnNnirVechi3 TO lnCntTactVechi3

	Omodif = CREATEOBJECT('frm_modific2024', lnIdSet3)
	IF VARTYPE(Omodif) <> 'O'
		DO NnirAssert WITH 'instantiere', 'FARARUL', .F., 'frm_modific2024 nu s-a instantiat'
	ELSE
		SELECT tact
		Omodif.grid1.SetFocus
		Omodif.gridextra1.setup()
		Omodif.CalculeazaTotal()

		llGasit3 = .F.
		lnColCheck3 = 0
		FOR i3 = 1 TO Omodif.grid1.ColumnCount
			lcColName3 = 'Omodif.grid1.Columns(' + TRANSFORM(i3) + ')'
			IF NnirEsteColoanaNnir(EVALUATE(lcColName3 + '.ControlSource'))
				llGasit3 = .T.
				lnColCheck3 = i3
			ENDIF
		ENDFOR
		DO NnirAssert WITH 'coloana_grid', 'FARARUL', llGasit3, 'ControlSource=nnir gasit=' + TRANSFORM(llGasit3)

		IF llGasit3
			SELECT tact
			LOCATE FOR NVL(nnir,0) = lnNnirVechi3
			IF FOUND()
				lcCallWhen = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheck3) + ').Text1.When'
				&lcCallWhen
				REPLACE nnir WITH lnNnirNou3
				lcCallLostFocus = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheck3) + ').Text1.LostFocus'
				&lcCallLostFocus

				SELECT tact
				lnCntTactNou3 = 0
				COUNT FOR NVL(nnir,0) = lnNnirNou3 TO lnCntTactNou3
				DO NnirAssert WITH 'sync_tact', 'FARARUL', lnCntTactNou3 = lnCntTactVechi3, ;
					TRANSFORM(lnCntTactNou3) + ' randuri tact cu nnir nou (asteptat ' + TRANSFORM(lnCntTactVechi3) + ')'
				DO NnirAssert WITH 'nu_crapa', 'FARARUL', .T., 'editarea pe nota fara rulaje nu a generat eroare'
			ELSE
				DO NnirAssert WITH 'locate_rand_vechi', 'FARARUL', .F., 'nu s-a gasit randul cu nnir vechi in tact'
			ENDIF
		ENDIF

		Omodif.Release()
		Omodif = NULL
		DO NnirSalveazaSiVerifica WITH lnCod3, lnAn3, lnLuna3, lnIdSet3, lnNnirVechi3, lnNnirNou3, 'FARARUL'
	ENDIF
	DO NnirCurataCursoare
ENDIF

*=====================================================================================
* Scenariul 4: nota de inventar (id_set=90101) - regresie blocare editare NNIR
*=====================================================================================
IF INLIST(tcMode, 'ALL', 'INVENTAR')
	LOCAL lnCod4, lnAn4, lnLuna4, lnIdSet4
	LOCAL i4, llGasit4, llReadOnly4, lcColName4

	lnCod4 = 1140716
	lnAn4 = 2026
	lnLuna4 = 3
	lnIdSet4 = 90101

	DO NnirConstruiesteCursoare WITH lnCod4, lnAn4, lnLuna4

	Omodif = CREATEOBJECT('frm_modific2024', lnIdSet4)
	IF VARTYPE(Omodif) <> 'O'
		DO NnirAssert WITH 'instantiere', 'INVENTAR', .F., 'frm_modific2024 nu s-a instantiat'
	ELSE
		SELECT tact
		Omodif.grid1.SetFocus
		Omodif.gridextra1.setup()
		Omodif.CalculeazaTotal()

		llGasit4 = .F.
		llReadOnly4 = .F.
		FOR i4 = 1 TO Omodif.grid1.ColumnCount
			lcColName4 = 'Omodif.grid1.Columns(' + TRANSFORM(i4) + ')'
			IF NnirEsteColoanaNnir(EVALUATE(lcColName4 + '.ControlSource'))
				llGasit4 = .T.
				llReadOnly4 = EVALUATE(lcColName4 + '.ReadOnly')
			ENDIF
		ENDFOR
		DO NnirAssert WITH 'coloana_grid', 'INVENTAR', llGasit4, 'ControlSource=nnir gasit=' + TRANSFORM(llGasit4)
		IF llGasit4
			* nu se incearca editarea - doar se verifica blocarea, ca sa nu se altereze o nota
			* reala de inventar cat timp blocarea nu e implementata
			DO NnirAssert WITH 'coloana_blocata', 'INVENTAR', llReadOnly4, ;
				'id_set=90101: ReadOnly asteptat .T., gasit ' + TRANSFORM(llReadOnly4)
		ENDIF

		Omodif.Release()
		Omodif = NULL
	ENDIF
	DO NnirCurataCursoare
ENDIF

*=====================================================================================
* Scenariul 5: stergere NNIR (-> 0) pe randul unei note cu rulaje - propagare la 0.
* Comportament nou (runda 4): garda EMPTY(NVL(tnNnirNou,0)) eliminata din sincronizeaza_nnir,
* ramane doar egalitatea - stergerea celulei (0 scris pe rand inainte de LostFocus) trebuie sa
* se propage la toate liniile cu valoarea veche, nu doar schimbarile intre doua valori nenule.
* Doar la nivel de cursoare (tact/trul) - nu se salveaza in Oracle.
*=====================================================================================
IF INLIST(tcMode, 'ALL', 'ZERO')
	LOCAL lnCodZ, lnAnZ, lnLunaZ, lnIdSetZ, lnNnirVechiZ
	LOCAL lnCntTactVechiZ, lnCntTrulVechiZ, lnCntTactRamasVechiZ, lnCntTrulRamasVechiZ
	LOCAL lnCntTactZeroZ, lnCntTrulZeroZ
	LOCAL iz, llGasitZ, lnColCheckZ, lcColNameZ

	lnCodZ = 1140841
	lnAnZ = 2026
	lnLunaZ = 7
	lnIdSetZ = 209
	lnNnirVechiZ = 3

	DO NnirConstruiesteCursoare WITH lnCodZ, lnAnZ, lnLunaZ

	SELECT tact
	lnCntTactVechiZ = 0
	COUNT FOR NVL(nnir,0) = lnNnirVechiZ TO lnCntTactVechiZ
	SELECT trul
	lnCntTrulVechiZ = 0
	COUNT FOR NVL(nnir,0) = lnNnirVechiZ TO lnCntTrulVechiZ

	Omodif = CREATEOBJECT('frm_modific2024', lnIdSetZ)
	IF VARTYPE(Omodif) <> 'O'
		DO NnirAssert WITH 'instantiere', 'ZERO', .F., 'frm_modific2024 nu s-a instantiat'
	ELSE
		SELECT tact
		Omodif.grid1.SetFocus
		Omodif.gridextra1.setup()
		Omodif.CalculeazaTotal()

		llGasitZ = .F.
		lnColCheckZ = 0
		FOR iz = 1 TO Omodif.grid1.ColumnCount
			lcColNameZ = 'Omodif.grid1.Columns(' + TRANSFORM(iz) + ')'
			IF NnirEsteColoanaNnir(EVALUATE(lcColNameZ + '.ControlSource'))
				llGasitZ = .T.
				lnColCheckZ = iz
			ENDIF
		ENDFOR
		DO NnirAssert WITH 'coloana_grid', 'ZERO', llGasitZ, 'ControlSource=nnir gasit=' + TRANSFORM(llGasitZ)

		IF llGasitZ
			SELECT tact
			LOCATE FOR NVL(nnir,0) = lnNnirVechiZ
			IF FOUND()
				lcCallWhen = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheckZ) + ').Text1.When'
				&lcCallWhen
				* simuleaza stergerea celulei: utilizatorul goleste campul, valoarea ajunge 0
				REPLACE nnir WITH 0
				lcCallLostFocus = 'Omodif.grid1.Columns(' + TRANSFORM(lnColCheckZ) + ').Text1.LostFocus'
				&lcCallLostFocus

				SELECT tact
				lnCntTactRamasVechiZ = 0
				COUNT FOR NVL(nnir,0) = lnNnirVechiZ TO lnCntTactRamasVechiZ
				lnCntTactZeroZ = 0
				COUNT FOR NVL(nnir,0) = 0 TO lnCntTactZeroZ
				DO NnirAssert WITH 'sync_tact_zero', 'ZERO', lnCntTactRamasVechiZ = 0 AND lnCntTactZeroZ >= lnCntTactVechiZ, ;
					TRANSFORM(lnCntTactRamasVechiZ) + ' randuri tact au ramas pe valoarea veche (asteptat 0), ' + ;
					TRANSFORM(lnCntTactZeroZ) + ' au ajuns la 0 (asteptat cel putin ' + TRANSFORM(lnCntTactVechiZ) + ')'

				* verificare explicita in cursorul legat de grid-ul de rulaje (pgfArticole.page1.grdRulaje)
				SELECT trul
				lnCntTrulRamasVechiZ = 0
				COUNT FOR NVL(nnir,0) = lnNnirVechiZ TO lnCntTrulRamasVechiZ
				lnCntTrulZeroZ = 0
				COUNT FOR NVL(nnir,0) = 0 TO lnCntTrulZeroZ
				DO NnirAssert WITH 'sync_trul_zero', 'ZERO', lnCntTrulRamasVechiZ = 0 AND lnCntTrulZeroZ >= lnCntTrulVechiZ, ;
					TRANSFORM(lnCntTrulRamasVechiZ) + ' randuri trul au ramas pe valoarea veche (asteptat 0), ' + ;
					TRANSFORM(lnCntTrulZeroZ) + ' au ajuns la 0 (asteptat cel putin ' + TRANSFORM(lnCntTrulVechiZ) + ')'
			ELSE
				DO NnirAssert WITH 'locate_rand_vechi', 'ZERO', .F., 'nu s-a gasit randul cu nnir vechi in tact'
			ENDIF
		ENDIF

		Omodif.Release()
		Omodif = NULL
	ENDIF
	DO NnirCurataCursoare
ENDIF

*=====================================================================================
* Scenariul 6: nota de inventar (id_set=90101) pe sucursala CURENTA - blocarea NNIR trebuie sa
* vina din regula 90101, nu din blocarea pe sucursala din AfterRowColChange. Scenariul 4 ruleaza
* pe o nota din alta sucursala, unde SetAll("ReadOnly",.T.) blocheaza oricum tot gridul, deci ar
* trece si fara implementare. Aici gnIdSucursala se aliniaza la id_sucursala notei (llReadOnly
* iese .F.), se declanseaza AfterRowColChange (care face SetAll dupa Init) si se verifica ca
* Column44 ramane blocata cat timp restul coloanelor sunt editabile.
*=====================================================================================
IF INLIST(tcMode, 'ALL', 'INVENTAR2')
	LOCAL lnCod6, lnAn6, lnLuna6, lnIdSet6
	LOCAL i6, llGasit6, llReadOnly6, lnEditabile6, lnSucVechi6, llMamaVechi6
	LOCAL lnIdSucNota6, lcColName6

	lnCod6 = 1140716
	lnAn6 = 2026
	lnLuna6 = 3
	lnIdSet6 = 90101

	DO NnirConstruiesteCursoare WITH lnCod6, lnAn6, lnLuna6

	SELECT tact
	GO TOP
	lnIdSucNota6 = NVL(tact.id_sucursala, 0)
	lnSucVechi6 = gnIdSucursala
	llMamaVechi6 = glEMama
	gnIdSucursala = lnIdSucNota6
	glEMama = .F.

	Omodif = CREATEOBJECT('frm_modific2024', lnIdSet6)
	IF VARTYPE(Omodif) <> 'O'
		DO NnirAssert WITH 'instantiere', 'INVENTAR2', .F., 'frm_modific2024 nu s-a instantiat'
	ELSE
		SELECT tact
		GO TOP
		Omodif.grid1.SetFocus
		Omodif.gridextra1.setup()
		Omodif.CalculeazaTotal()

		* AfterRowColChange face SetAll("ReadOnly", llReadOnly) peste blocarea pusa in Init
		Omodif.grid1.AfterRowColChange(1)

		llGasit6 = .F.
		llReadOnly6 = .F.
		lnEditabile6 = 0
		FOR i6 = 1 TO Omodif.grid1.ColumnCount
			lcColName6 = 'Omodif.grid1.Columns(' + TRANSFORM(i6) + ')'
			IF NnirEsteColoanaNnir(EVALUATE(lcColName6 + '.ControlSource'))
				llGasit6 = .T.
				llReadOnly6 = EVALUATE(lcColName6 + '.ReadOnly')
			ELSE
				IF !EVALUATE(lcColName6 + '.ReadOnly')
					lnEditabile6 = lnEditabile6 + 1
				ENDIF
			ENDIF
		ENDFOR

		DO NnirAssert WITH 'coloana_grid', 'INVENTAR2', llGasit6, 'ControlSource=nnir gasit=' + TRANSFORM(llGasit6)
		* control: daca gridul e blocat integral, testul de blocare NNIR nu dovedeste nimic
		DO NnirAssert WITH 'grid_editabil', 'INVENTAR2', lnEditabile6 > 0, ;
			'coloane editabile (fara nnir): ' + TRANSFORM(lnEditabile6) + ' (asteptat > 0, ' + ;
			'gnIdSucursala=' + TRANSFORM(lnIdSucNota6) + ')'
		IF llGasit6
			DO NnirAssert WITH 'coloana_blocata', 'INVENTAR2', llReadOnly6, ;
				'id_set=90101 pe sucursala curenta: ReadOnly asteptat .T., gasit ' + TRANSFORM(llReadOnly6)
		ENDIF

		Omodif.Release()
		Omodif = NULL
	ENDIF

	gnIdSucursala = lnSucVechi6
	glEMama = llMamaVechi6
	DO NnirCurataCursoare
ENDIF

DO NnirLog WITH 'REZULTAT SUITA: ' + TRANSFORM(gnPass) + ' PASS, ' + TRANSFORM(gnFail) + ' FAIL'
QUIT

*=====================================================================================
* proceduri ajutatoare (fara CREATEOBJECT - vezi depanare_testare_vfp.md / capcana l:
* CREATEOBJECT apelat dintr-o procedura se comporta gresit in acest runtime headless)
*=====================================================================================

PROCEDURE NnirLog
	LPARAMETERS tcMsg
	STRTOFILE(tcMsg + CHR(13)+CHR(10), gcLogFile, 1)
ENDPROC

PROCEDURE NnirAssert
	LPARAMETERS tcPas, tcCaz, llOk, tcDetaliu
	LOCAL lcRez
	lcRez = IIF(llOk, 'PASS', 'FAIL')
	IF llOk
		gnPass = gnPass + 1
	ELSE
		gnFail = gnFail + 1
	ENDIF
	DO NnirLog WITH lcRez + ' [' + tcCaz + '/' + tcPas + '] ' + tcDetaliu
ENDPROC

PROCEDURE NnirErr
	LPARAMETERS tnErr, tcMsg, tcProg, tnLine
	DO NnirLog WITH 'ERR ' + TRANSFORM(tnErr) + ' [' + tcProg + ':' + TRANSFORM(tnLine) + '] ' + tcMsg
ENDPROC

* verifica ca toate variabilele folosite ca ?param in SQL pass-through pe calea de test (env-init,
* optiuni_firma, oscrie_in_fisiere, pack_contafin/pack_sesiune) sunt definite - o variabila
* PUBLIC lipsa/umbrita da direct dialogul modal "Enter the value for <var>", nu o eroare catchabila
FUNCTION NnirGardaVariabile
	LOCAL laVar(9), i, llOk
	laVar(1) = 'gnIdUtil'
	laVar(2) = 'gnAn'
	laVar(3) = 'gnLuna'
	laVar(4) = 'gnIdFirma'
	laVar(5) = 'gnIdSucursala'
	laVar(6) = 'gcS'
	laVar(7) = 'gnIdProgram'
	laVar(8) = 'gnId_Prg_Owner'
	laVar(9) = 'gnHandle'
	llOk = .T.
	FOR i = 1 TO ALEN(laVar)
		IF TYPE(laVar(i)) == 'U'
			DO NnirLog WITH 'FAIL [garda_variabile] ' + laVar(i) + ' nu exista (TYPE U) - ar fi dat dialog modal "Enter the value"'
			llOk = .F.
		ENDIF
	ENDFOR
	RETURN llOk
ENDFUNC

* VFP calificat automat ControlSource-ul unui camp simplu cu aliasul cursorului (RecordSource) -
* "nnir" definit in sursa apare la runtime ca "tact.nnir" - se accepta ambele forme
FUNCTION NnirEsteColoanaNnir
	LPARAMETERS tcControlSource
	LOCAL lcCs
	lcCs = UPPER(ALLTRIM(TRANSFORM(tcControlSource)))
	RETURN lcCs == 'NNIR' OR RIGHT(lcCs, 5) == '.NNIR'
ENDFUNC

* construieste tact/trul/trul_obinv exact ca afisjurcom.do_modifica (comun.vc2:2352-2434),
* dar pe AN/LUNA proprii notei (nu gnAn/gnLuna) - vezi antetul fisierului
PROCEDURE NnirConstruiesteCursoare
	LPARAMETERS tnCod, tnAn, tnLuna
	LOCAL lcSql, lnSucces

	DO NnirCurataCursoare

	lcSql = [select * from vact_tot where sters = 0 and an = ] + TRANSFORM(tnAn) + ;
		[ and luna = ] + TRANSFORM(tnLuna) + [ and cod = ] + TRANSFORM(tnCod) + [ order by id_act]
	lnSucces = goExecutor.oExecute(lcSql, 'v_act')
	goExecutor.oReset()
	IF lnSucces < 0
		DO NnirLog WITH 'EROARE construire tact: ' + goExecutor.cEroare
		RETURN .F.
	ENDIF
	SELECT * FROM v_act INTO CURSOR actactan
	SELECT .F. AS ales, T.*, CAST(0 AS N(2)) AS tipnota FROM actactan T INTO CURSOR tact READWRITE
	USE IN v_act

	lcSql = [select * from vrul_tot where sters = 0 and an = ] + TRANSFORM(tnAn) + ;
		[ and luna = ] + TRANSFORM(tnLuna) + [ and cod = ] + TRANSFORM(tnCod) + [ order by id_rul]
	goExecutor.oExecute(lcSql, 'v_rul')
	goExecutor.oReset()
	SELECT *, valoare + valtva AS valoarectva, valoarev + valtvav AS valoarevctva ;
		FROM v_rul INTO CURSOR RUL_TEMP READWRITE
	SELECT * FROM RUL_TEMP INTO CURSOR trul READWRITE
	USE IN v_rul

	lcSql = [select * from vrul_obinv_tot where sters = 0 and an = ] + TRANSFORM(tnAn) + ;
		[ and luna = ] + TRANSFORM(tnLuna) + [ and cod = ] + TRANSFORM(tnCod) + [ order by id_rul_obinv]
	goExecutor.oExecute(lcSql, 'v_rul_obinv')
	goExecutor.oReset()
	SELECT *, valoare + valtva AS valoarectva, valoarev + valtvav AS valoarevctva ;
		FROM v_rul_obinv INTO CURSOR RUL_TEMP_OBINV READWRITE
	SELECT * FROM RUL_TEMP_OBINV INTO CURSOR trul_obinv READWRITE
	USE IN v_rul_obinv

	SELECT a.*, IIF(NVL(a.id_jtva_coloana,0)=0,0,1) AS cu_tva FROM tact a INTO CURSOR tact READWRITE
	SELECT tact
	GO TOP
	RETURN .T.
ENDPROC

PROCEDURE NnirCurataCursoare
	IF USED('tact')
		USE IN tact
	ENDIF
	IF USED('trul')
		USE IN trul
	ENDIF
	IF USED('trul_obinv')
		USE IN trul_obinv
	ENDIF
	IF USED('actactan')
		USE IN actactan
	ENDIF
	IF USED('rul_temp')
		USE IN rul_temp
	ENDIF
	IF USED('rul_temp_obinv')
		USE IN rul_temp_obinv
	ENDIF
ENDPROC

FUNCTION NnirOraCount
	LPARAMETERS tcSql
	LOCAL lnVal, llOk
	lnVal = -1
	llOk = goExecutor.oExecuta(tcSql, 'cNnirOraCnt')
	IF llOk AND USED('cNnirOraCnt') AND RECCOUNT('cNnirOraCnt') > 0
		lnVal = cNnirOraCnt.cnt
	ENDIF
	IF USED('cNnirOraCnt')
		USE IN cNnirOraCnt
	ENDIF
	RETURN lnVal
ENDFUNC

* verifica ca in Oracle nu s-a scris nimic dupa editarea DOAR in cursoare (echivalent Renunt)
PROCEDURE NnirVerificaOracleNeschimbat
	LPARAMETERS tnCod, tnNnirVechi, tcCaz
	LOCAL lnCnt, lcSql
	lcSql = [select count(*) cnt from act where cod = ] + TRANSFORM(tnCod) + ;
		[ and nnir = ] + TRANSFORM(tnNnirVechi)
	lnCnt = NnirOraCount(lcSql)
	DO NnirAssert WITH 'renunt_neschimbat', tcCaz, lnCnt > 0, ;
		'ACT.NNIR in Oracle inainte de Termin ramane ' + TRANSFORM(tnNnirVechi) + ' (' + TRANSFORM(lnCnt) + ' randuri)'
ENDPROC

* replica blocul de salvare din afisjurcom.do_modifica (comun.vc2:2456-2487): scrie tact/trul/
* trul_obinv in ACT/RUL/RUL_OBINV prin oscrie_in_fisiere + pack_contafin.finalizeaza_modificare_
* nota, verifica in Oracle, apoi reface valoarea originala (revert - baza de test ramane
* neschimbata pentru rulari repetate)
PROCEDURE NnirSalveazaSiVerifica
	LPARAMETERS tnCod, tnAn, tnLuna, tnIdSet, tnNnirVechi, tnNnirNou, tcCaz
	PRIVATE pnAn, pnLuna, pdDataOra
	LOCAL lnIdFact, lnIdfactd, llRul, lnSuccesSalvare, lcSqlFin, lnCnt, lcSql

	pnAn = tnAn
	pnLuna = tnLuna
	pdDataOra = NULL

	SELECT tact
	LOCATE FOR NVL(nnir,0) = tnNnirNou
	lnIdFact = NVL(id_fact, 0)
	lnIdfactd = NVL(id_factd, 0)

	llRul = (RECCOUNT('trul') > 0) OR (RECCOUNT('trul_obinv') > 0)

	* thisform.do_deschide_tranzactie()/do_inchide_tranzactie() din afisjurcom (_frm_base.vc2:252-
	* 305, mostenite, apelate pe formularul de jurnal, nu pe frm_modific2024) - echivalent direct,
	* fara instanta de forma: manual pe durata scrierii, apoi commit/rollback + revenire pe auto
	SQLSetProp(gnHandle, 'Transactions', 2)

	* replica exact secventa din afisjurcom.do_modifica: intai STERGE nota veche (COD-ul
	* original, din actactan neatins de editare), abia apoi SCRIE varianta editata
	SELECT actactan
	lnSuccesSalvare = oscrie_in_fisiere(2, .T., llRul)
	DO NnirAssert WITH 'oscrie_in_fisiere_sterge', tcCaz, lnSuccesSalvare > 0, 'a returnat ' + TRANSFORM(lnSuccesSalvare)

	IF lnSuccesSalvare > 0
		SELECT * FROM tact INTO CURSOR actactan READWRITE
		REPLACE ALL id_util WITH gnIdUtil, sters WITH 0 IN actactan

		IF llRul
			SELECT * FROM trul INTO CURSOR rul_temp READWRITE
			REPLACE ALL id_util WITH gnIdUtil, sters WITH 0 IN rul_temp
			SELECT * FROM trul_obinv INTO CURSOR rul_temp_obinv READWRITE
			REPLACE ALL id_util WITH gnIdUtil, sters WITH 0 IN rul_temp_obinv
		ENDIF

		lnSuccesSalvare = oscrie_in_fisiere(0, .T., llRul)
		DO NnirAssert WITH 'oscrie_in_fisiere', tcCaz, lnSuccesSalvare > 0, 'a returnat ' + TRANSFORM(lnSuccesSalvare)
	ENDIF

	IF lnSuccesSalvare > 0
		lcSqlFin = [begin pack_contafin.finalizeaza_modificare_nota(?pnLuna,?pnAn,?pdDataOra,] + ;
			TRANSFORM(tnIdSet) + [,] + TRANSFORM(tnCod) + [,] + TRANSFORM(lnIdFact) + [,] + ;
			TRANSFORM(lnIdfactd) + [,?gnIdUtil); end;]
		lnSuccesSalvare = IIF(goExecutor.oExecuta(lcSqlFin), 1, -1)
		DO NnirAssert WITH 'finalizeaza_modificare_nota', tcCaz, lnSuccesSalvare > 0, 'a returnat ' + TRANSFORM(lnSuccesSalvare)
	ENDIF

	IF lnSuccesSalvare > 0
		SQLCOMMIT(gnHandle)
	ELSE
		SQLROLLBACK(gnHandle)
	ENDIF
	SQLSetProp(gnHandle, 'Transactions', 1)

	* Termin reatribuie COD nou (pack_contafin), sub AN/LUNA de sesiune curente - nu pastreaza
	* COD-ul original notei editate. Verificarea si curatenia se fac dupa valoarea NNIR marcaj
	* (distincta, nu poate coincide cu date reale), nu dupa COD-ul original.
	lcSql = [select count(*) cnt from act where sters = 0 and nnir = ] + TRANSFORM(tnNnirNou)
	lnCnt = NnirOraCount(lcSql)
	DO NnirAssert WITH 'oracle_act_final', tcCaz, lnCnt > 0, TRANSFORM(lnCnt) + ' randuri ACT cu nnir nou in Oracle'

	IF RECCOUNT('trul') > 0
		lcSql = [select count(*) cnt from rul where sters = 0 and nnir = ] + TRANSFORM(tnNnirNou)
		lnCnt = NnirOraCount(lcSql)
		DO NnirAssert WITH 'oracle_rul_final', tcCaz, lnCnt > 0, TRANSFORM(lnCnt) + ' randuri RUL cu nnir nou in Oracle'
	ENDIF

	* curatenie: pasul STERGE (oscrie_in_fisiere param 2) marcheaza sters=1 pe COD-ul ORIGINAL -
	* readuc nota originala activa, apoi marchez sters=1 (conventia aplicatiei) pe orice a ajuns
	* sub NNIR-ul marcaj (COD nou, atribuit de pack_contafin la scriere)
	goExecutor.oExecuta([update act set sters = 0 where cod = ] + TRANSFORM(tnCod))
	goExecutor.oExecuta([update rul set sters = 0 where cod = ] + TRANSFORM(tnCod))
	goExecutor.oExecuta([update rul_obinv set sters = 0 where cod = ] + TRANSFORM(tnCod))
	goExecutor.oExecuta([update act set sters = 1 where nnir = ] + TRANSFORM(tnNnirNou) + [ and cod <> ] + TRANSFORM(tnCod))
	goExecutor.oExecuta([update rul set sters = 1 where nnir = ] + TRANSFORM(tnNnirNou) + [ and cod <> ] + TRANSFORM(tnCod))
	goExecutor.oExecuta([update rul_obinv set sters = 1 where nnir = ] + TRANSFORM(tnNnirNou) + [ and cod <> ] + TRANSFORM(tnCod))
	goExecutor.oExecuta('commit')
ENDPROC

* varianta pt. scenariul RUL_OBINV (verifica RUL_OBINV in loc de RUL)
PROCEDURE NnirSalveazaSiVerificaObinv
	LPARAMETERS tnCod, tnAn, tnLuna, tnIdSet, tnNnirVechi, tnNnirNou
	PRIVATE pnAn, pnLuna, pdDataOra
	LOCAL lnIdFact, lnIdfactd, llRul, lnSuccesSalvare, lcSqlFin, lnCnt, lcSql

	pnAn = tnAn
	pnLuna = tnLuna
	pdDataOra = NULL

	SELECT tact
	LOCATE FOR NVL(nnir,0) = tnNnirNou
	lnIdFact = NVL(id_fact, 0)
	lnIdfactd = NVL(id_factd, 0)

	llRul = (RECCOUNT('trul') > 0) OR (RECCOUNT('trul_obinv') > 0)

	* thisform.do_deschide_tranzactie()/do_inchide_tranzactie() din afisjurcom (_frm_base.vc2:252-
	* 305, mostenite, apelate pe formularul de jurnal, nu pe frm_modific2024) - echivalent direct,
	* fara instanta de forma: manual pe durata scrierii, apoi commit/rollback + revenire pe auto
	SQLSetProp(gnHandle, 'Transactions', 2)

	* replica exact secventa din afisjurcom.do_modifica: intai STERGE nota veche (COD-ul
	* original, din actactan neatins de editare), abia apoi SCRIE varianta editata
	SELECT actactan
	lnSuccesSalvare = oscrie_in_fisiere(2, .T., llRul)
	DO NnirAssert WITH 'oscrie_in_fisiere_sterge', 'OBINV', lnSuccesSalvare > 0, 'a returnat ' + TRANSFORM(lnSuccesSalvare)

	IF lnSuccesSalvare > 0
		SELECT * FROM tact INTO CURSOR actactan READWRITE
		REPLACE ALL id_util WITH gnIdUtil, sters WITH 0 IN actactan

		IF llRul
			SELECT * FROM trul INTO CURSOR rul_temp READWRITE
			REPLACE ALL id_util WITH gnIdUtil, sters WITH 0 IN rul_temp
			SELECT * FROM trul_obinv INTO CURSOR rul_temp_obinv READWRITE
			REPLACE ALL id_util WITH gnIdUtil, sters WITH 0 IN rul_temp_obinv
		ENDIF

		lnSuccesSalvare = oscrie_in_fisiere(0, .T., llRul)
		DO NnirAssert WITH 'oscrie_in_fisiere', 'OBINV', lnSuccesSalvare > 0, 'a returnat ' + TRANSFORM(lnSuccesSalvare)
	ENDIF

	IF lnSuccesSalvare > 0
		lcSqlFin = [begin pack_contafin.finalizeaza_modificare_nota(?pnLuna,?pnAn,?pdDataOra,] + ;
			TRANSFORM(tnIdSet) + [,] + TRANSFORM(tnCod) + [,] + TRANSFORM(lnIdFact) + [,] + ;
			TRANSFORM(lnIdfactd) + [,?gnIdUtil); end;]
		lnSuccesSalvare = IIF(goExecutor.oExecuta(lcSqlFin), 1, -1)
		DO NnirAssert WITH 'finalizeaza_modificare_nota', 'OBINV', lnSuccesSalvare > 0, 'a returnat ' + TRANSFORM(lnSuccesSalvare)
	ENDIF

	IF lnSuccesSalvare > 0
		SQLCOMMIT(gnHandle)
	ELSE
		SQLROLLBACK(gnHandle)
	ENDIF
	SQLSetProp(gnHandle, 'Transactions', 1)

	* Termin reatribuie COD nou (pack_contafin), sub AN/LUNA de sesiune curente - nu pastreaza
	* COD-ul original notei editate. Verificarea si curatenia se fac dupa valoarea NNIR marcaj
	* (distincta, nu poate coincide cu date reale), nu dupa COD-ul original.
	lcSql = [select count(*) cnt from act where sters = 0 and nnir = ] + TRANSFORM(tnNnirNou)
	lnCnt = NnirOraCount(lcSql)
	DO NnirAssert WITH 'oracle_act_final', 'OBINV', lnCnt > 0, TRANSFORM(lnCnt) + ' randuri ACT cu nnir nou in Oracle'

	lcSql = [select count(*) cnt from rul_obinv where sters = 0 and nnir = ] + TRANSFORM(tnNnirNou)
	lnCnt = NnirOraCount(lcSql)
	DO NnirAssert WITH 'oracle_rul_obinv_final', 'OBINV', lnCnt > 0, TRANSFORM(lnCnt) + ' randuri RUL_OBINV cu nnir nou in Oracle'

	* curatenie: pasul STERGE (oscrie_in_fisiere param 2) marcheaza sters=1 pe COD-ul ORIGINAL -
	* readuc nota originala activa, apoi marchez sters=1 (conventia aplicatiei) pe orice a ajuns
	* sub NNIR-ul marcaj (COD nou, atribuit de pack_contafin la scriere)
	goExecutor.oExecuta([update act set sters = 0 where cod = ] + TRANSFORM(tnCod))
	goExecutor.oExecuta([update rul set sters = 0 where cod = ] + TRANSFORM(tnCod))
	goExecutor.oExecuta([update rul_obinv set sters = 0 where cod = ] + TRANSFORM(tnCod))
	goExecutor.oExecuta([update act set sters = 1 where nnir = ] + TRANSFORM(tnNnirNou) + [ and cod <> ] + TRANSFORM(tnCod))
	goExecutor.oExecuta([update rul set sters = 1 where nnir = ] + TRANSFORM(tnNnirNou) + [ and cod <> ] + TRANSFORM(tnCod))
	goExecutor.oExecuta([update rul_obinv set sters = 1 where nnir = ] + TRANSFORM(tnNnirNou) + [ and cod <> ] + TRANSFORM(tnCod))
	goExecutor.oExecuta('commit')
ENDPROC
