Files
comun/utile/Teste/cache_anaf/test_timp_completare_tabel.prg
Marius Mutu 5c8a201438 Cache ANAF: verificarea in masa a codurilor fiscale, pe transe (SVN r17935)
Verificarea "in masa" (VerificaListaCIF ... 'MASA') pica pe ORA-01795 peste 1000
de coduri, iar esecul trimitea tot lotul la ANAF, cu pauze de o secunda la fiecare
100 de coduri. Pe langa asta, fiecare rand servit din cache era salvat inapoi in
istoric si logat separat.

- programe/validare.prg: CitesteIstoricPentruCoduri citeste pe transe de maxim
  1000 de coduri legate cu OR in aceeasi interogare (fara obiecte noi in baza,
  compatibil cu Oracle 10g); plasa de siguranta cere codurile neacoperite o
  singura data, nu cod cu cod; SalveazaIstoricDinCursor sare peste randurile cu
  sursa CACHE*; bucla de log per rand devine o singura linie cu totalul.
- clase/overificari.vc2: completarea tabelului de parteneri foloseste index pe
  codul normalizat si SEEK in loc de LOCATE cu UDF (era patratic).
- utile/Teste/cache_anaf/: harness-uri de masurare si non-regresie pentru
  timpii de mai jos.

Masurat pe MARIUSM_AUTO, cu ANAF blocat: 1000 de coduri 5,1 s -> 0,318 s;
1001 coduri 16,6 s cu ORA-01795 -> 0,553 s fara eroare; 3000 de coduri 1,565 s;
200 de coduri din cache 3,93 s -> 0,05 s, cu 0 randuri noi in istoric;
completarea tabelului pentru 2000 de parteneri 11,97 s -> 0,028 s.
Randurile intoarse si verdictele raman identice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JCzVWfqscv1xyo5uvJiWiW
2026-08-02 07:27:42 +03:00

248 lines
9.5 KiB
Plaintext

* test_timp_completare_tabel.prg - masoara PARTEA DE APELANT a verificarii in masa: bucla care
* muta rezultatele din crsANAF in tabelul afisat (crsVerificareParteneri), din
* frm_verificare_parteneri.do_verifica (COMUN\clase\overificari.vc2:2741-2756).
*
* Bucla reala face, pentru fiecare rezultat, un LOCATE cu expresie care apeleaza un UDF
* (loVerificare.GetCodTara) pe fiecare rand parcurs => N x N apeluri de functie.
* Se compara cu aceeasi completare pe cursor indexat (SEEK).
*
* Fara Oracle in bucla masurata: cursoarele sunt construite local, deci timpul e pur VFP.
*
* Rulare: vfp9.exe -A -T "...\test_timp_completare_tabel.prg"
SET SAFETY OFF
SET TALK OFF
SET DELETED ON
SET EXACT ON
SET CENTURY ON
SET DATE DMY
SET NULLDISPLAY TO ''
CLOSE DATABASES
PUBLIC gcTestLog
gcTestLog = "D:\ROA\ROACONT\COMUN\utile\Teste\cache_anaf\test_timp_completare_tabel_log.txt"
STRTOFILE("START " + TTOC(DATETIME()) + CHR(13) + CHR(10), gcTestLog)
ON ERROR DO ErrCompl WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
ON SHUTDOWN QUIT
DO D:\ROA\ROACONT\COMUN\utile\Teste\test_init_env_auto.prg WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT'
DO WrLog3 WITH 'mediu OK'
SET PROCEDURE TO "D:\ROA\ROACONT\COMUN\utile\Teste\mock_amessagebox.prg" ADDITIVE
* goLog dezactivat aici: masor doar bucla de VFP, nu scrierea in log
goLog.cLogFile = 'D:\ROA\ROACONT\COMUN\utile\Teste\cache_anaf\_log_inexistent.txt'
LOCAL lnI
FOR lnI = 1 TO 4
DO MasoaraLot WITH IIF(lnI = 1, 200, IIF(lnI = 2, 500, IIF(lnI = 3, 1000, 2000)))
ENDFOR
DO TestSemanticaData
DO WrLog3 WITH 'GATA ' + TTOC(DATETIME())
QUIT
* verifica varianta LOCATE (A) vs SEEK+SKIP (C) pe acelasi cod fiscal cu mai multe randuri
* cu date diferite - trebuie sa aleaga acelasi rand (primul, in ordinea fizica, care satisface conditia)
PROCEDURE TestSemanticaData
LOCAL loVerificare, ldData
loVerificare = CREATEOBJECT('verificarecod', .F., .F.)
ldData = DATE()
DO WrLog3 WITH ''
DO WrLog3 WITH '=== test semantica: acelasi cod, date diferite ==='
* caz 1: doua randuri cu data GRESITA inaintea celui cu data corecta -> trebuie 2 SKIP pana la potrivire
DO ConstrTabelDuplicat WITH ldData - 60, ldData - 30, ldData
DO VerificaSemantica WITH loVerificare, ldData, 'caz 1 (2 SKIP pana la data corecta)', 'PARTENER 3'
* caz 2: randul cu data GOALA vine inaintea celui cu data corecta -> primul (cu data goala) trebuie ales
DO ConstrTabelDuplicat WITH ldData - 30, {}, ldData
DO VerificaSemantica WITH loVerificare, ldData, 'caz 2 (data goala inaintea celei corecte)', 'PARTENER 2'
ENDPROC
PROCEDURE ConstrTabelDuplicat
LPARAMETERS tdData1, tdData2, tdData3
IF USED('crsTabel')
USE IN crsTabel
ENDIF
CREATE CURSOR crsTabel (ales L, denumire C(100) NULL, cod_fiscal C(30) NULL, Valid L NULL, ;
firma C(100) NULL, cod C(100) NULL, adresa C(250) NULL, judet C(100) NULL, regcom C(30) NULL, ;
datatvamfin C(30) NULL, platitortvamfin L NULL, IsCIF L NULL, duplicat L, atribut_fiscal C(2), ;
stare C(100), atentie C(100), cod_fiscalfro C(30) NULL, tvaincasare L, splittva L, inactiv L, Data D NULL)
INSERT INTO crsTabel (cod_fiscal, denumire, Valid, IsCIF, Data) VALUES ('RO9999999', 'ALT PARTENER', .T., .T., tdData1)
INSERT INTO crsTabel (cod_fiscal, denumire, Valid, IsCIF, Data) VALUES ('RO1234567', 'PARTENER 1', .T., .T., tdData1)
INSERT INTO crsTabel (cod_fiscal, denumire, Valid, IsCIF, Data) VALUES ('RO1234567', 'PARTENER 2', .T., .T., tdData2)
INSERT INTO crsTabel (cod_fiscal, denumire, Valid, IsCIF, Data) VALUES ('RO1234567', 'PARTENER 3', .T., .T., tdData3)
ENDPROC
PROCEDURE VerificaSemantica
LPARAMETERS toVerificare, tdData, tcEticheta, tcAsteptat
LOCAL lcCheieCauta, llGasit, lcRezA, lcRezC
* varianta A: LOCATE cu UDF, exact bucla veche
SELECT crsTabel
LOCATE FOR ALLTRIM(STRTRAN(cod_fiscal, toVerificare.GetCodTara(cod_fiscal), '')) = '1234567' AND (EMPTY(NVL(data, {})) OR data = tdData)
lcRezA = IIF(FOUND(), ALLTRIM(denumire), '<niciunul>')
* varianta C: SEEK pe cod_fiscalfro + SKIP cat timp cheia ramane egala, pana la data care se potriveste
SELECT crsTabel
REPLACE ALL cod_fiscalfro WITH ALLTRIM(STRTRAN(cod_fiscal, toVerificare.GetCodTara(cod_fiscal), ''))
INDEX ON cod_fiscalfro TAG cfro
lcCheieCauta = PADR('1234567', 30)
llGasit = .F.
IF SEEK(lcCheieCauta, 'crsTabel', 'cfro')
llGasit = .T.
DO WHILE !(EMPTY(NVL(data, {})) OR data = tdData)
SKIP
IF EOF() OR cod_fiscalfro <> lcCheieCauta
llGasit = .F.
EXIT
ENDIF
ENDDO
ENDIF
lcRezC = IIF(llGasit, ALLTRIM(denumire), '<niciunul>')
DO WrLog3 WITH ' ' + tcEticheta + ': A=' + lcRezA + ' C=' + lcRezC + ' asteptat=' + tcAsteptat
DO WrLog3 WITH IIF(lcRezA == lcRezC AND lcRezA == tcAsteptat, ' PASS', ' FAIL')
USE IN (SELECT('crsTabel'))
ENDPROC
PROCEDURE MasoaraLot
LPARAMETERS tnN
LOCAL lnT1, lnT2, lnT3, lnK, loVerificare, ldData
loVerificare = CREATEOBJECT('verificarecod', .F., .F.)
ldData = DATE()
DO WrLog3 WITH ''
DO WrLog3 WITH '=== lot ' + TRANSFORM(tnN) + ' parteneri ==='
* rezultatele ANAF/cache (forma crsANAF, doar campurile folosite de bucla)
IF USED('crsRezANAF')
USE IN crsRezANAF
ENDIF
CREATE CURSOR crsRezANAF (cui N(13), denumire V(100), adresa C(244), mesaj V(100), ;
tva L, tvaincasare L, splittva L, inactiv L)
FOR lnK = 1 TO tnN
INSERT INTO crsRezANAF (cui, denumire, adresa, mesaj, tva, tvaincasare, splittva, inactiv) ;
VALUES (10000000 + lnK, 'FIRMA ' + ALLTRIM(STR(lnK)), 'ADRESA ' + ALLTRIM(STR(lnK)), '', .T., .F., .F., .F.)
ENDFOR
* varianta 1: exact bucla din overificari.vc2
DO ConstrTabel WITH tnN
lnT1 = SECONDS()
SELECT crsRezANAF
SCAN
SCATTER NAME loRec
WITH loRec
SELECT crsTabel
LOCATE FOR ALLTRIM(STRTRAN(cod_fiscal, loVerificare.GetCodTara(cod_fiscal), '')) = ALLTRIM(STR(.cui)) AND (EMPTY(NVL(data, {})) OR data = ldData)
IF FOUND()
REPLACE firma WITH .denumire, adresa WITH .adresa, stare WITH .mesaj, ;
cod WITH ALLTRIM(STR(.cui)), tvaincasare WITH .tvaincasare, ;
splittva WITH .splittva, inactiv WITH .inactiv
ENDIF
ENDWITH
SELECT crsRezANAF
ENDSCAN
lnT1 = SECONDS() - lnT1
DO WrLog3 WITH 'A LOCATE + UDF (cod real) = ' + TRANSFORM(ROUND(lnT1, 3)) + ' s'
SELECT COUNT(*) AS n FROM crsTabel WHERE !EMPTY(NVL(firma, '')) INTO CURSOR crsCtrl1
DO WrLog3 WITH ' randuri completate: ' + TRANSFORM(crsCtrl1.n)
USE IN (SELECT('crsCtrl1'))
* varianta 2: aceeasi completare pe cursor indexat
DO ConstrTabel WITH tnN
lnT2 = SECONDS()
SELECT crsTabel
REPLACE ALL cod_fiscalfro WITH ALLTRIM(STRTRAN(STRTRAN(UPPER(NVL(cod_fiscal, '')), 'RO', ''), ' ', ''))
INDEX ON cod_fiscalfro TAG cfro
SELECT crsRezANAF
SCAN
SCATTER NAME loRec
WITH loRec
IF SEEK(PADR(ALLTRIM(STR(.cui)), 30), 'crsTabel', 'cfro')
SELECT crsTabel
REPLACE firma WITH .denumire, adresa WITH .adresa, stare WITH .mesaj, ;
cod WITH ALLTRIM(STR(.cui)), tvaincasare WITH .tvaincasare, ;
splittva WITH .splittva, inactiv WITH .inactiv
ENDIF
ENDWITH
SELECT crsRezANAF
ENDSCAN
lnT2 = SECONDS() - lnT2
DO WrLog3 WITH 'B SEEK pe cursor indexat = ' + TRANSFORM(ROUND(lnT2, 3)) + ' s'
SELECT COUNT(*) AS n FROM crsTabel WHERE !EMPTY(NVL(firma, '')) INTO CURSOR crsCtrl2
DO WrLog3 WITH ' randuri completate: ' + TRANSFORM(crsCtrl2.n)
USE IN (SELECT('crsCtrl2'))
DO WrLog3 WITH 'raport A/B = ' + TRANSFORM(ROUND(lnT1 / MAX(lnT2, 0.001), 1)) + 'x'
* varianta 3: exact codul propus in overificari.vc2 (SEEK + parcurgere pe cheie egala pentru data)
DO ConstrTabel WITH tnN
lnT3 = SECONDS()
SELECT crsTabel
REPLACE ALL cod_fiscalfro WITH ALLTRIM(STRTRAN(cod_fiscal, loVerificare.GetCodTara(cod_fiscal), ''))
INDEX ON cod_fiscalfro TAG cfro
SELECT crsRezANAF
SCAN
SCATTER NAME loRec
WITH loRec
lcCheieCauta = PADR(ALLTRIM(STR(.cui)), 30)
SELECT crsTabel
llGasit = .F.
IF SEEK(m.lcCheieCauta, 'crsTabel', 'cfro')
llGasit = .T.
DO WHILE !(EMPTY(NVL(data, {})) OR data = ldData)
SKIP
IF EOF() OR cod_fiscalfro <> m.lcCheieCauta
llGasit = .F.
EXIT
ENDIF
ENDDO
ENDIF
IF llGasit
REPLACE firma WITH .denumire, adresa WITH .adresa, stare WITH .mesaj, ;
cod WITH ALLTRIM(STR(.cui)), tvaincasare WITH .tvaincasare, ;
splittva WITH .splittva, inactiv WITH .inactiv
ENDIF
ENDWITH
SELECT crsRezANAF
ENDSCAN
lnT3 = SECONDS() - lnT3
DO WrLog3 WITH 'C SEEK + SKIP pe cheie (cod propus) = ' + TRANSFORM(ROUND(lnT3, 3)) + ' s'
SELECT COUNT(*) AS n FROM crsTabel WHERE !EMPTY(NVL(firma, '')) INTO CURSOR crsCtrl3
DO WrLog3 WITH ' randuri completate: ' + TRANSFORM(crsCtrl3.n)
USE IN (SELECT('crsCtrl3'))
DO WrLog3 WITH 'raport A/C = ' + TRANSFORM(ROUND(lnT1 / MAX(lnT3, 0.001), 1)) + 'x'
ENDPROC
PROCEDURE ConstrTabel
LPARAMETERS tnN
LOCAL lnK
IF USED('crsTabel')
USE IN crsTabel
ENDIF
CREATE CURSOR crsTabel (ales L, denumire C(100) NULL, cod_fiscal C(30) NULL, Valid L NULL, ;
firma C(100) NULL, cod C(100) NULL, adresa C(250) NULL, judet C(100) NULL, regcom C(30) NULL, ;
datatvamfin C(30) NULL, platitortvamfin L NULL, IsCIF L NULL, duplicat L, atribut_fiscal C(2), ;
stare C(100), atentie C(100), cod_fiscalfro C(30) NULL, tvaincasare L, splittva L, inactiv L, Data D)
FOR lnK = 1 TO tnN
INSERT INTO crsTabel (cod_fiscal, denumire, Valid, IsCIF, Data) ;
VALUES ('RO' + ALLTRIM(STR(10000000 + lnK)), 'PARTENER ' + ALLTRIM(STR(lnK)), .T., .T., DATE())
ENDFOR
ENDPROC
PROCEDURE WrLog3
LPARAMETERS tcText
STRTOFILE(TRANSFORM(tcText) + CHR(13) + CHR(10), gcTestLog, .T.)
ENDPROC
PROCEDURE ErrCompl
LPARAMETERS tnError, tcMessage, tcProgram, tnLine
DO WrLog3 WITH 'EROARE ' + TRANSFORM(tnError) + ' [' + TRANSFORM(tcMessage) + '] in ' + ;
TRANSFORM(tcProgram) + ' linia ' + TRANSFORM(tnLine)
RETURN
ENDPROC