From fb38ab99d6d0628157d7c0ec9653fa584856aa81 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Thu, 17 Sep 2026 22:44:25 +0300 Subject: [PATCH] sync SVN r18175 --- clase/onom_curs.vc2 | 100 +++++++++++-- utile/Teste/_test_curs_bnr_out.txt | 17 +++ utile/Teste/test_curs_bnr_headless.prg | 189 +++++++++++++++++++++++++ 3 files changed, 297 insertions(+), 9 deletions(-) create mode 100644 utile/Teste/_test_curs_bnr_out.txt create mode 100644 utile/Teste/test_curs_bnr_headless.prg diff --git a/clase/onom_curs.vc2 b/clase/onom_curs.vc2 index 4042942..7fb9fd6 100644 --- a/clase/onom_curs.vc2 +++ b/clase/onom_curs.vc2 @@ -15,6 +15,8 @@ DEFINE CLASS actualizare_curs_bnr AS _custom OF "_baza.vcx" *m: scrie_curs_bnr *p: ccursor *p: clink + *p: clinkan + *p: clinkarhiva *p: ctempfile *p: ddata *p: ncurs @@ -26,6 +28,8 @@ DEFINE CLASS actualizare_curs_bnr AS _custom OF "_baza.vcx" * ccursor = ccrsbnr clink = https://curs.bnr.ro/nbrfxrates.xml + clinkan = https://curs.bnr.ro/files/xml/years/nbrfxrates%.xml + clinkarhiva = https://curs.bnr.ro/nbrfxrates10days.xml ctempfile = C:\temp\temp.xml ddata = {} Height = 17 @@ -37,6 +41,8 @@ DEFINE CLASS actualizare_curs_bnr AS _custom OF "_baza.vcx" _memberdata = + + @@ -98,8 +104,13 @@ DEFINE CLASS actualizare_curs_bnr AS _custom OF "_baza.vcx" ENDPROC PROCEDURE citeste_curs_bnr + Lparameters tnSursa Local loHTTP As 'winHTTP.winHTTPrequest.5.1' - Local lcData, lcFisier, lcServer + Local lcData, lcFisier, lcServer, lcCubeCautat, ldCandidat, lnIncercari, lnAnCautat, llRetrasAnAnterior, lnStatus + + If Vartype(tnSursa) <> "N" + tnSursa = 0 + Endif If Empty(This.cCursor) This.cCursor = [ccrsbnr] @@ -109,30 +120,90 @@ DEFINE CLASS actualizare_curs_bnr AS _custom OF "_baza.vcx" Use In (This.cCursor) Endif - lcServer = This.cLink + Do Case + Case tnSursa = 1 + lcServer = This.cLinkArhiva + Case tnSursa = 2 + lnAnCautat = Year(This.dData - 1) + lcServer = Strtran(This.cLinkAn,"%",Alltrim(Str(lnAnCautat))) + Otherwise + lcServer = This.cLink + Endcase loHTTP = Createobject('winHTTP.winHTTPrequest.5.1') loHTTP.Open('GET', lcServer, .F.) + loHTTP.SetTimeouts(5000,5000,5000,15000) loHTTP.setRequestHeader("Content-Type", "application/xml;") poLog.Log(m.lcServer) - loHTTP.Send() + Try + loHTTP.Send() + lnStatus = loHTTP.Status + Catch + lnStatus = 0 + Endtry - If loHTTP.Status = 200 + If lnStatus = 200 lcFisier = loHTTP.Responsebody lcFisier = Strextract(lcFisier,[],[]) - lcData = Strextract(lcFisier,[date="],["]) - lcFisier= Strtran(lcFisier,[date="]+lcData+["],[]) + If tnSursa = 0 + lcData = Strextract(lcFisier,[date="],["]) + lcFisier= Strtran(lcFisier,[date="]+lcData+["],[]) + Else + lcCubeCautat = [] + ldCandidat = This.dData - 1 + lnIncercari = 0 + llRetrasAnAnterior = .F. + Do While Empty(lcCubeCautat) And lnIncercari < 10 + If tnSursa = 2 And Year(ldCandidat) < lnAnCautat And !llRetrasAnAnterior + llRetrasAnAnterior = .T. + lnAnCautat = lnAnCautat - 1 + lcServer = Strtran(This.cLinkAn,"%",Alltrim(Str(lnAnCautat))) + loHTTP = Createobject('winHTTP.winHTTPrequest.5.1') + loHTTP.Open('GET', lcServer, .F.) + loHTTP.SetTimeouts(5000,5000,5000,15000) + loHTTP.setRequestHeader("Content-Type", "application/xml;") + poLog.Log(m.lcServer) + Try + loHTTP.Send() + lnStatus = loHTTP.Status + Catch + lnStatus = 0 + Endtry + If lnStatus <> 200 + repune_backup_cursoare(This.cCursor) + Release loUpdate,loIp,loUrl,lcData,lnSize,lcFisier,lcData + Return 1 + Endif + lcFisier = Strextract(loHTTP.Responsebody,[],[]) + Endif + lcData = Str(Year(ldCandidat),4) + "-" + Padl(Alltrim(Str(Month(ldCandidat))),2,"0") + "-" + Padl(Alltrim(Str(Day(ldCandidat))),2,"0") + lcCubeCautat = Strextract(lcFisier,[],[]) + ldCandidat = ldCandidat - 1 + lnIncercari = lnIncercari + 1 + Enddo + If Empty(lcCubeCautat) + repune_backup_cursoare(This.cCursor) + Release loUpdate,loIp,loUrl,lcData,lnSize,lcFisier,lcData + Return 2 + Endif + lcFisier = [] + lcCubeCautat + [] + Endif lcFisier= Strtran(Strtran(lcFisier,[">],[" curs="]),[],[" />]) Xmltocursor(lcFisier,This.cCursor) - This.dData = Ttod(Ctot(lcData+[T000000]))+1 + If tnSursa = 0 + This.dData = Ttod(Ctot(lcData+[T000000]))+1 + Endif *!* modificare 03.06.2013 sterge_backup_cursoare(This.cCursor) Else repune_backup_cursoare(This.cCursor) + Release loUpdate,loIp,loUrl,lcData,lnSize,lcFisier,lcData + Return 1 Endif *!* modificare 03.06.2013 ^ Release loUpdate,loIp,loUrl,lcData,lnSize,lcFisier,lcData + Return 0 ENDPROC PROCEDURE Destroy @@ -168,9 +239,20 @@ DEFINE CLASS actualizare_curs_bnr AS _custom OF "_baza.vcx" Case (This.dData = Ttod(ltDataOra) And Hour(ltDataOra) <13) Or (This.dData = Ttod(ltDataOra) + 1 And Hour(ltDataOra) >= 13) This.citeste_curs_bnr() Case This.dData < Ttod(ltDataOra) Or This.dData = Ttod(ltDataOra) And Hour(ltDataOra) >= 13 - If amessagebox("Nu poate fi preluat automat cursul BNR. Doriti sa accesati pagina BNR?",4+32,"Confirmare") = 6 - goUrl("http://www.bnr.ro") && din wwutils.prg + lnStareBnr = This.citeste_curs_bnr(1) + If lnStareBnr = 2 + lnStareBnr = This.citeste_curs_bnr(2) Endif + Do Case + Case lnStareBnr = 0 + && curs preluat din arhiva sau fisierul anual BNR + Case lnStareBnr = 2 + amessagebox("Nu exista cursul BNR pentru data specificata!",48,"Atentie") + Otherwise + If amessagebox("Nu poate fi preluat automat cursul BNR. Doriti sa accesati pagina cursbnr.ro?",4+32,"Confirmare") = 6 + goUrl("https://www.cursbnr.ro/") + Endif + Endcase Otherwise amessagebox("Nu exista cursul BNR pentru data specificata!",48,"Atentie") Endcase diff --git a/utile/Teste/_test_curs_bnr_out.txt b/utile/Teste/_test_curs_bnr_out.txt new file mode 100644 index 0000000..1abcd18 --- /dev/null +++ b/utile/Teste/_test_curs_bnr_out.txt @@ -0,0 +1,17 @@ +RUN 09/17/26 10:36:54 PM marca=_7KA1CGZRZ +env init OK, ClassLibrary onom_curs incarcat: DA +PASS CAZ1_sursa1_azi :: Return obtinut=0 asteptat=0 durata=0.234s Reccount=37 EUR curs=5.2637 (OK) +CAZ2 dData(luni)=14/09/2026 +PASS CAZ2_sursa1_luni :: Return obtinut=0 asteptat=0 durata=0.052s Reccount=37 EUR curs=5.2557 (OK) +PASS CAZ3_sursa2_martie :: Return obtinut=0 asteptat=0 durata=0.187s Reccount=37 EUR curs=5.0947 (OK) +PASS CAZ4_sursa2_2ian :: Return obtinut=0 asteptat=0 durata=0.240s Reccount=38 EUR curs=5.0985 (OK) + [ON ERROR] 13 Alias 'CCRSBNR' is not found. in REPUNE_BACKUP_CURSOARE linia 6363 +PASS CAZ5_sursa1_veche :: Return obtinut=2 asteptat=2 durata=0.053s +PASS CAZ8_cascada_sursa1_apoi_sursa2 :: Return obtinut=0 asteptat=0 durata=0.119s Reccount=38 EUR curs=5.0985 (OK) + [ON ERROR] 13 Alias 'CCRSBNR' is not found. in REPUNE_BACKUP_CURSOARE linia 6363 +CAZ6 durata=0.062s +PASS CAZ6_sursa1_host_invalid :: Return obtinut=1 asteptat=1 durata=0.062s +CAZ7 dData inainte=18/08/2026 dData dupa=18/09/2026 (trebuie sa difere, s-a suprascris ca la sursa 0) +PASS CAZ7_fara_parametru :: Return obtinut=0 asteptat=0 durata=0.050s Reccount=37 EUR curs=5.2601 (OK) +=== SUMAR: PASS=8 FAIL=0 === +Nicio scriere in Oracle: nu s-a apelat initializeaza() nici scrie_curs_bnr() in acest test. diff --git a/utile/Teste/test_curs_bnr_headless.prg b/utile/Teste/test_curs_bnr_headless.prg new file mode 100644 index 0000000..1b7e451 --- /dev/null +++ b/utile/Teste/test_curs_bnr_headless.prg @@ -0,0 +1,189 @@ +* test_curs_bnr_headless.prg +* Proba headless pentru citeste_curs_bnr (clasa actualizare_curs_bnr, onom_curs.vcx) dupa +* patch-ul arhiva 10 zile + fisier anual BNR. Apeleaza metoda DIRECT (nu initializeaza), ca sa +* nu atinga Oracle (initializeaza ar chema scrie_curs_bnr la succes). +* +* Capcana descoperita si ocolita AICI, in test, nu in cod: citeste_curs_bnr incepe cu +* creeaza_backup_cursoare(This.cCursor), care cheama copiaza_structura_cursor() din +* oproceduri_comune.prg (linia ~3024). Daca cursorul cCursor ("ccrsbnr") nu e deja deschis, +* copiaza_structura_cursor cade pe ramura Else si cheama amessagebox("Eroare interna 2 - +* copiaza structura cursor",...) - apel INTRA-FISIER (amessagebox e tot in oproceduri_comune.prg), +* deci mock_amessagebox.prg NU il intercepteaza (limita documentata in antetul mock-ului). Rezultat: +* dialog real, headless agata. In productie nu se intampla pentru ca initializeaza() creeaza +* cursorul via goExecutor.oExecute(lcSql, This.cCursor) INAINTE de a chema citeste_curs_bnr. +* Aici, apeland metoda direct, precream cursorul ccrsbnr gol (crea_cursor_gol) inainte de FIECARE +* apel - metoda oricum il inchide (Use In) si il reface din raspunsul HTTP (Xmltocursor). + +SET SAFETY OFF +SET TALK OFF +SET DELETED ON + +LOCAL lcLog +lcLog = "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\_test_curs_bnr_out.txt" +STRTOFILE("RUN " + TTOC(DATETIME()) + " marca=" + SYS(2015) + CHR(13) + CHR(10), lcLog) + +ON ERROR DO log_eroare WITH ERROR(), MESSAGE(), PROGRAM(), LINENO() + +DO (ADDBS("D:\ROA\ROAFACTURARE\COMUN\utile\Teste") + "test_init_env_auto_roafacturare.prg") WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT' + +DO log_txt WITH "env init OK, ClassLibrary onom_curs incarcat: " + IIF(('ONOM_CURS' $ UPPER(SET('CLASSLIB'))), 'DA', 'NU') + +LOCAL lnPass, lnFail +lnPass = 0 +lnFail = 0 + +* ---------- Caz 1: sursa 1, azi (zi lucratoare) -> Return 0, cursor populat, EUR>0 ---------- +LOCAL loCurs, lnRet, ldData, lnT0, lnT1, lnDur +loCurs = CREATEOBJECT("actualizare_curs_bnr", 1) +DO crea_cursor_gol WITH loCurs.cCursor +ldData = DATE() +loCurs.dData = ldData +lnT0 = SECONDS() +lnRet = loCurs.citeste_curs_bnr(1) +lnT1 = SECONDS() +DO verifica_caz WITH "CAZ1_sursa1_azi", lnRet, 0, loCurs, .T., (lnT1-lnT0), lnPass, lnFail + +* ---------- Caz 2: sursa 1, luni recenta -> Return 0 (cade pe publicarea de vineri) ---------- +LOCAL ldLuni +ldLuni = DATE() - (DOW(DATE(),2) - 1) +IF ldLuni = DATE() + ldLuni = ldLuni - 7 +ENDIF +loCurs = CREATEOBJECT("actualizare_curs_bnr", 1) +DO crea_cursor_gol WITH loCurs.cCursor +loCurs.dData = ldLuni +lnT0 = SECONDS() +lnRet = loCurs.citeste_curs_bnr(1) +lnT1 = SECONDS() +DO log_txt WITH "CAZ2 dData(luni)=" + DTOC(ldLuni) +DO verifica_caz WITH "CAZ2_sursa1_luni", lnRet, 0, loCurs, .T., (lnT1-lnT0), lnPass, lnFail + +* ---------- Caz 3: sursa 2, martie anul curent -> Return 0 ---------- +LOCAL ldMartie +ldMartie = DATE(YEAR(DATE()), 3, 15) +loCurs = CREATEOBJECT("actualizare_curs_bnr", 1) +DO crea_cursor_gol WITH loCurs.cCursor +loCurs.dData = ldMartie +lnT0 = SECONDS() +lnRet = loCurs.citeste_curs_bnr(2) +lnT1 = SECONDS() +DO verifica_caz WITH "CAZ3_sursa2_martie", lnRet, 0, loCurs, .T., (lnT1-lnT0), lnPass, lnFail + +* ---------- Caz 4: sursa 2, 2 ianuarie anul curent -> Return 0 (trecere in anul precedent) ---------- +LOCAL ld2Ian +ld2Ian = DATE(YEAR(DATE()), 1, 2) +loCurs = CREATEOBJECT("actualizare_curs_bnr", 1) +DO crea_cursor_gol WITH loCurs.cCursor +loCurs.dData = ld2Ian +lnT0 = SECONDS() +lnRet = loCurs.citeste_curs_bnr(2) +lnT1 = SECONDS() +DO verifica_caz WITH "CAZ4_sursa2_2ian", lnRet, 0, loCurs, .T., (lnT1-lnT0), lnPass, lnFail + +* ---------- Caz 5: sursa 1, data mult mai veche decat arhiva 10 zile -> Return 2 ---------- +LOCAL ldVeche, loCurs5 +ldVeche = DATE(YEAR(DATE()), 1, 1) +loCurs5 = CREATEOBJECT("actualizare_curs_bnr", 1) +DO crea_cursor_gol WITH loCurs5.cCursor +loCurs5.dData = ldVeche +lnT0 = SECONDS() +lnRet = loCurs5.citeste_curs_bnr(1) +lnT1 = SECONDS() +DO verifica_caz WITH "CAZ5_sursa1_veche", lnRet, 2, loCurs5, .F., (lnT1-lnT0), lnPass, lnFail + +* ---------- Caz 8 (cascada dubla, cerut suplimentar): acelasi obiect/data, sursa 2 dupa ---------- +* ---------- Return 2 pe sursa 1 - verifica ca ccrsbnr e refacut de repune_backup_cursoare si ---------- +* ---------- ca al doilea apel NU mai loveste "Eroare interna 2" (creeaza_backup_cursoare cere ---------- +* ---------- Used(cCursor) la intrare). ---------- +lnT0 = SECONDS() +lnRet = loCurs5.citeste_curs_bnr(2) +lnT1 = SECONDS() +DO verifica_caz WITH "CAZ8_cascada_sursa1_apoi_sursa2", lnRet, 0, loCurs5, .T., (lnT1-lnT0), lnPass, lnFail + +* ---------- Caz 6: sursa 1, host invalid -> Return 1, fara agatare (timeouts 5s/5s/5s/15s) ---------- +LOCAL loCurs6 +loCurs6 = CREATEOBJECT("actualizare_curs_bnr", 1) +DO crea_cursor_gol WITH loCurs6.cCursor +loCurs6.cLinkArhiva = "https://host-inexistent-romfast-test.invalid/nbrfxrates10days.xml" +loCurs6.dData = DATE() +lnT0 = SECONDS() +lnRet = loCurs6.citeste_curs_bnr(1) +lnT1 = SECONDS() +lnDur = lnT1 - lnT0 +DO log_txt WITH "CAZ6 durata=" + TRANSFORM(lnDur) + "s" +DO verifica_caz WITH "CAZ6_sursa1_host_invalid", lnRet, 1, loCurs6, .F., lnDur, lnPass, lnFail + +* ---------- Caz 7: fara parametru -> comportament ca sursa 0, This.dData se actualizeaza ---------- +LOCAL loCurs7, ldDataInainte +loCurs7 = CREATEOBJECT("actualizare_curs_bnr", 1) +DO crea_cursor_gol WITH loCurs7.cCursor +ldDataInainte = DATE() - 30 +loCurs7.dData = ldDataInainte +lnT0 = SECONDS() +lnRet = loCurs7.citeste_curs_bnr() +lnT1 = SECONDS() +DO log_txt WITH "CAZ7 dData inainte=" + DTOC(ldDataInainte) + " dData dupa=" + DTOC(loCurs7.dData) + " (trebuie sa difere, s-a suprascris ca la sursa 0)" +DO verifica_caz WITH "CAZ7_fara_parametru", lnRet, 0, loCurs7, .T., (lnT1-lnT0), lnPass, lnFail + +DO log_txt WITH "=== SUMAR: PASS=" + TRANSFORM(lnPass) + " FAIL=" + TRANSFORM(lnFail) + " ===" +DO log_txt WITH "Nicio scriere in Oracle: nu s-a apelat initializeaza() nici scrie_curs_bnr() in acest test." + +QUIT + +* ============================================================ +PROCEDURE crea_cursor_gol + LPARAMETERS tcCursor + IF USED(tcCursor) + USE IN (tcCursor) + ENDIF + CREATE CURSOR (tcCursor) (Currency C(10), multiplier N(10,4), Curs N(14,6)) +ENDPROC + +PROCEDURE log_txt + LPARAMETERS tcTxt + STRTOFILE(TRANSFORM(tcTxt) + CHR(13) + CHR(10), "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\_test_curs_bnr_out.txt", 1) +ENDPROC + +PROCEDURE log_eroare + LPARAMETERS tnErr, tcMsg, tcProg, tnLine + DO log_txt WITH " [ON ERROR] " + TRANSFORM(tnErr) + " " + TRANSFORM(tcMsg) + " in " + TRANSFORM(tcProg) + " linia " + TRANSFORM(tnLine) +ENDPROC + +PROCEDURE verifica_caz + LPARAMETERS tcLabel, tnRetObtinut, tnRetAsteptat, toCurs, tlAsteaptaDate, tnDur, tnPassRef, tnFailRef + LOCAL llOk, lcDetaliu, lnRc, lcEur + llOk = (tnRetObtinut = tnRetAsteptat) + lcDetaliu = "Return obtinut=" + TRANSFORM(tnRetObtinut) + " asteptat=" + TRANSFORM(tnRetAsteptat) + " durata=" + TRANSFORM(tnDur) + "s" + + IF tlAsteaptaDate + IF USED(toCurs.cCursor) + lnRc = RECCOUNT(toCurs.cCursor) + lcDetaliu = lcDetaliu + " Reccount=" + TRANSFORM(lnRc) + IF lnRc > 0 + SELECT (toCurs.cCursor) + LOCATE FOR UPPER(ALLTRIM(NVL(Currency,""))) = "EUR" + IF FOUND() AND Curs > 0 + lcEur = "EUR curs=" + TRANSFORM(Curs) + " (OK)" + ELSE + lcEur = "EUR NU s-a gasit sau curs<=0" + llOk = .F. + ENDIF + lcDetaliu = lcDetaliu + " " + lcEur + ELSE + llOk = .F. + lcDetaliu = lcDetaliu + " (cursor gol, esuat)" + ENDIF + ELSE + llOk = .F. + lcDetaliu = lcDetaliu + " (cursor neincarcat)" + ENDIF + ENDIF + + IF llOk + tnPassRef = tnPassRef + 1 + DO log_txt WITH "PASS " + tcLabel + " :: " + lcDetaliu + ELSE + tnFailRef = tnFailRef + 1 + DO log_txt WITH "FAIL " + tcLabel + " :: " + lcDetaliu + ENDIF +ENDPROC