Cache ANAF pe ISTORIC_CODURI_FISCALE: verificare din memorie, plasa la tacere ANAF

Verificarile de partener nu mai depind exclusiv de raspunsul ANAF: se citeste
intai cache-ul din ISTORIC_CODURI_FISCALE (mutat in CONTAFIN_ORACLE), cu
provenienta afisata pe ecrane (sursa / data_sursa) si cu plasa de siguranta
cand ANAF tace. Ordinea cache/ANAF e configurabila; cache-ul expira.

- programe/validare.prg: verificare single si pe loturi peste cache, contract
  404 separat de caderea de serviciu, expirarea cache-ului, corectii la
  verdictul pe firma si la etichetarea CACHE_INDISP.
- programe/ocautare.prg: plasa de siguranta si banda de provenienta la cautarea
  de partener.
- programe/oproceduri_comune.prg: VERIFICA_RTVAI_DATA citeste si cache-ul.
- clase/overificari.vc2: propagarea provenientei in interfata.
- utile/Teste/: harness-uri de testare headless - echivalenta cache/ANAF pe 200
  de coduri reale, marginile pe inactiv si TVA la incasare, mock batch ANAF,
  baseline D394 si sondele de diagnostic ANAF.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JCzVWfqscv1xyo5uvJiWiW
This commit is contained in:
2026-08-02 01:31:30 +03:00
parent ebb20fab7e
commit 859e67e874
17 changed files with 3889 additions and 84 deletions

View File

@@ -62,6 +62,13 @@
*!* programului si starea de pe calculator; utilizatorul isi poate sterge propria setare, ca sa revina
*!* la setarea firmei sau la implicitul programului
*!* 30.07.2026
*!* marius.mutu
*!* verificare ANAF: cand serviciul e cazut sau apelul esueaza, verdictul se citeste din istoricul de
*!* coduri fiscale (cache Oracle), daca istoricul are ceva proaspat; banda de stare si detaliile (F4)
*!* arata atunci data verificarii citite din istoric, cu mentiune explicita cand ANAF e indisponibil;
*!* ordinea de incercare ANAF/istoric e configurabila per firma
*!* #DEFINE CRLF CHR(13) + CHR(10)
#INCLUDE COMUN\ROA.H
@@ -69,6 +76,7 @@ Procedure ANAF_StarePartener
Lparameters tcCodFiscal, tdData, tlDoarCache, tlNecesitaApel, tlNegasit, tcClasaEsec, tnTipPersoana
Local lcCodFiscal, lcCui, loRezANAF, lcCheieCache, lnI, llValid, loOut, ldData, llNegasit, lcStareServiciu
Local lcOrdine, loVerificareANAF As "VerificareANAF", lcSelectOrig
tlNecesitaApel = .F.
tlNegasit = .F.
@@ -114,29 +122,54 @@ Procedure ANAF_StarePartener
Endif
lcCheieCache = 'C' + m.lcCui + '_' + Dtos(m.ldData)
If goCacheANAF_Sesiune.GetKey(m.lcCheieCache) = 0
lcStareServiciu = ANAF_StareServiciu()
Do Case
Case m.lcStareServiciu == 'CAZUT'
tlNecesitaApel = .F.
tcClasaEsec = 'FARA_RASPUNS'
Return .Null.
Case m.lcStareServiciu == 'SE_TESTEAZA'
tlNecesitaApel = .T.
tcClasaEsec = 'SE_TESTEAZA'
Return .Null.
Endcase
tlNecesitaApel = .T.
If m.tlDoarCache
Return .Null.
*** ordinea ANAF/istoric (OPTIUNI.ANAFCACHEORDINE_UNIC, VerificareANAF.OrdineCache din validare.prg);
*** implicit ANAF,CACHE - pe CACHE,ANAF se incearca intai istoricul, iar apelul ANAF se sare cand e proaspat
lcOrdine = 'ANAF,CACHE'
lcSelectOrig = Select()
Try
loVerificareANAF = Createobject("VerificareANAF")
lcOrdine = loVerificareANAF.OrdineCache('UNIC')
Catch
Endtry
If Select() <> m.lcSelectOrig And Used(m.lcSelectOrig)
Select (m.lcSelectOrig)
Endif
If m.lcOrdine == 'CACHE,ANAF'
loRezANAF = ANAF_CitesteDinIstoric(m.lcCui, m.ldData, 'CACHE')
Endif
If Vartype(m.loRezANAF) <> 'O'
lcStareServiciu = ANAF_StareServiciu()
Do Case
Case m.lcStareServiciu == 'CAZUT'
tlNecesitaApel = .F.
tcClasaEsec = 'FARA_RASPUNS'
*** plasa de siguranta: ANAF cazut - verdict din istoric, daca e proaspat, etichetat distinct
loRezANAF = ANAF_CitesteDinIstoric(m.lcCui, m.ldData, 'CACHE_INDISP')
If Vartype(m.loRezANAF) = 'O'
tcClasaEsec = ''
Endif
Case m.lcStareServiciu == 'SE_TESTEAZA'
tlNecesitaApel = .T.
tcClasaEsec = 'SE_TESTEAZA'
Otherwise
tlNecesitaApel = .T.
If !m.tlDoarCache
llNegasit = .F.
loRezANAF = ANAF_VerificaCuiSingle(m.lcCui, m.ldData, @llNegasit, @tcClasaEsec)
Do Case
Case m.tcClasaEsec == 'FARA_RASPUNS'
ANAF_SeteazaStareServiciu('CAZUT', 'CUI=' + m.lcCui)
*** plasa de siguranta: apelul a esuat - acelasi fallback pe istoric
loRezANAF = ANAF_CitesteDinIstoric(m.lcCui, m.ldData, 'CACHE_INDISP')
If Vartype(m.loRezANAF) = 'O'
tcClasaEsec = ''
Endif
Case m.tcClasaEsec == ''
ANAF_SeteazaStareServiciu('VIU', 'CUI=' + m.lcCui)
Endcase
Endif
Endcase
Endif
llNegasit = .F.
loRezANAF = ANAF_VerificaCuiSingle(m.lcCui, m.ldData, @llNegasit, @tcClasaEsec)
Do Case
Case m.tcClasaEsec == 'FARA_RASPUNS'
ANAF_SeteazaStareServiciu('CAZUT', 'CUI=' + m.lcCui)
Case m.tcClasaEsec == ''
ANAF_SeteazaStareServiciu('VIU', 'CUI=' + m.lcCui)
Endcase
If Vartype(m.loRezANAF) = 'O'
goCacheANAF_Sesiune.Add(m.loRezANAF, m.lcCheieCache)
Endif
@@ -160,9 +193,57 @@ Procedure ANAF_StarePartener
Addproperty(loOut, "dAnulareScpTVA", Iif(Pemstatus(loRezANAF, 'dAnulareScpTVA', 5), Nvl(loRezANAF.dAnulareScpTVA, {}), {}))
Addproperty(loOut, "cMesajScpTVA", Iif(Pemstatus(loRezANAF, 'cMesajScpTVA', 5), Alltrim(Nvl(loRezANAF.cMesajScpTVA, '')), ''))
Addproperty(loOut, "dData", m.ldData)
Addproperty(loOut, "cSursa", Iif(Pemstatus(loRezANAF, 'cSursa', 5), loRezANAF.cSursa, 'ANAF'))
Addproperty(loOut, "dDataSursa", Iif(Pemstatus(loRezANAF, 'dDataSursa', 5), Nvl(loRezANAF.dDataSursa, {}), {}))
Return loOut
Endproc && ANAF_StarePartener
*************************************
*** Citeste din ISTORIC_CODURI_FISCALE (VerificareANAF.CitesteIstoricPentruCoduri, validare.prg) verdictul
*** cache pentru un singur CUI normalizat, daca e proaspat; tcSursa eticheteaza rezultatul ('CACHE' sau
*** 'CACHE_INDISP'). Intoarce .NULL. cand istoricul nu are nimic proaspat pentru codul dat, fara eroare
*************************************
Procedure ANAF_CitesteDinIstoric
Lparameters tcCui, tdData, tcSursa
Local loVerificareANAF As "VerificareANAF", lcAliasCache, loRez, lcSelectOrig
loRez = .Null.
lcAliasCache = 'crsANAFIstoricOcautare'
lcSelectOrig = Select()
Try
Use In (Select(m.lcAliasCache))
loVerificareANAF = Createobject("VerificareANAF")
loVerificareANAF.CitesteIstoricPentruCoduri(m.tcCui, m.tdData, m.lcAliasCache)
If Used(m.lcAliasCache) And Reccount(m.lcAliasCache) > 0
Select (m.lcAliasCache)
Go Top
If !Empty(Nvl(denumire, ''))
loRez = Createobject("Empty")
Addproperty(loRez, "cui", cui)
Addproperty(loRez, "scpTVA", Nvl(scpTVA, .F.))
Addproperty(loRez, "statusInactivi", Nvl(statusInactivi, .F.))
Addproperty(loRez, "denumire", Nvl(denumire, ""))
Addproperty(loRez, "mesaj", Nvl(mesaj, ""))
Addproperty(loRez, "dInceputScpTVA", Nvl(data_inceput_ScpTVA, {}))
Addproperty(loRez, "dSfarsitScpTVA", Nvl(data_sfarsit_ScpTVA, {}))
Addproperty(loRez, "dAnulareScpTVA", Nvl(data_anul_imp_ScpTVA, {}))
Addproperty(loRez, "cMesajScpTVA", Nvl(mesaj_ScpTVA, ""))
Addproperty(loRez, "cSursa", m.tcSursa)
Addproperty(loRez, "dDataSursa", Nvl(data_sursa, {}))
Endif
Endif
Catch
loRez = .Null.
Endtry
If Used(m.lcAliasCache)
Use In (Select(m.lcAliasCache))
Endif
If Select() <> m.lcSelectOrig And Used(m.lcSelectOrig)
Select (m.lcSelectOrig)
Endif
Return m.loRez
Endproc && ANAF_CitesteDinIstoric
Procedure ANAF_StareServiciu
If Type('gcANAF_StareServiciu') = 'U'
Public gcANAF_StareServiciu, gtANAF_StareServiciuMoment, gnANAF_StareServiciuStamp
@@ -789,7 +870,26 @@ DEFINE CLASS anaf_verif_cautare AS Custom
lcPerioada = This.SufixPerioadaTVA(toStare)
Return 'ANAF: ' + This.TextStare(toStare, m.lcPerioada) + ' (' + ;
Iif(Empty(m.lcDenANAF), '', m.lcDenANAF + Iif(m.tlCuVirgula, ', ', ' ')) + m.lcCodOk + ')' + ;
Iif(Empty(m.lcPerioada), ' la ' + Dtoc(toStare.dData), '')
Iif(Empty(m.lcPerioada), ' la ' + Dtoc(toStare.dData), '') + ;
This.SufixSursa(toStare)
ENDPROC
PROCEDURE SufixSursa
Lparameters toStare
*** eticheteaza verdictele care nu vin dintr-un raspuns ANAF proaspat, ci din istoricul cache (contract 4.5)
If !Pemstatus(m.toStare, 'cSursa', 5)
Return ''
Endif
*!* 01.08.2026 marius.mutu: marcaj explicit al sursei, la fel ca in grid si in dialogul de verificare
Do Case
Case toStare.cSursa == 'ANAF'
Return ' (sursa: ANAF)'
Case toStare.cSursa == 'CACHE'
Return ' (sursa: CACHE ' + Dtoc(Nvl(toStare.dDataSursa, Date())) + ')'
Case toStare.cSursa == 'CACHE_INDISP'
Return ' (sursa: CACHE ' + Dtoc(Nvl(toStare.dDataSursa, Date())) + ', ANAF indisponibil)'
Endcase
Return ''
ENDPROC
PROCEDURE TextPerioadaTVA

View File

@@ -64,6 +64,10 @@
*!* 22.07.2025
*!* GetNamePermutations - limitare la 4 cuvinte si maxim 10 permutari
*!* 31.07.2026
*!* marius.mutu
*!* verifica_partener_show_info: marcaj de provenienta (cache ANAF) langa denumirea firmei, cand disponibil
#Include COMUN\ROA.H
Define Class oexecutor As Custom
@@ -4597,6 +4601,7 @@ Procedure verificare_parteneri
Endproc && verificare_parteneri
*!* 01.08.2026 marius.mutu istoricul e comun tuturor firmelor, nu se mai filtreaza pe schema_sursa
Procedure verificare_parteneri_istoric
Lparameters tcCodFiscal, tcNume
@@ -4613,7 +4618,7 @@ Procedure verificare_parteneri_istoric
Endif
Text To lcSql Noshow
select id, dataora, id_util, dataorav, id_utilv, cod_fiscal, firma, adresa, judet, regcom, codpostal, telefon, fax, datatvamfin, platitortvamfin, stare, platitortvavies, util, utilv
select id, dataora, id_util, dataorav, id_utilv, cod_fiscal, firma, adresa, judet, regcom, codpostal, telefon, fax, datatvamfin, platitortvamfin, stare, platitortvavies, util, utilv
from vistoric_coduri_fiscale
where cod_fiscal = ?pcCodFiscal
Endtext
@@ -4764,7 +4769,7 @@ Function verifica_partener_show_info
*** tcMesajIntrebare: IN, optional, daca se intreaba ceva la sfarsitul formularului (ex: Se completeaza datele in formularul partener nou?)
Local lcCodFiscal, lcDenumire, lcText, llCodRO, llPlatitorTVAMfin, llPlatitorTVAVIES, lnDialogType
Local lnRaspuns, loPartener
Local lnRaspuns, loPartener, lcProvenienta
lcCodFiscal = Transform(m.tcCodFiscal)
lcDenumire = Transform(m.tcDenumire)
@@ -4776,9 +4781,16 @@ Function verifica_partener_show_info
llTvaIncasare = loPartener.tvaincasare
llSplitTVA = loPartener.splittva
llInactiv = loPartener.inactiv
*!* 01.08.2026 marius.mutu: marcaj explicit al sursei (ANAF live / cache), nu doar pe randurile din cache
lcProvenienta = ''
If Pemstatus(m.loPartener, 'sursa', 5) And !Empty(Alltrim(Nvl(loPartener.sursa, '')))
lcProvenienta = Iif(Alltrim(Nvl(loPartener.sursa, '')) == 'ANAF', '(sursa: ANAF)', ;
'(sursa: CACHE ' + Dtoc(Nvl(loPartener.data_sursa, Date())) + Iif(Alltrim(Nvl(loPartener.sursa, '')) == 'CACHE_INDISP', ', ANAF indisponibil', '') + ')')
Endif
lcText = 'VERIFICARE CIF: ' + m.lcCodFiscal + ' ' + m.lcDenumire + crlf + crlf + ;
Alltrim(loPartener.firma) + crlf + ;
Iif(!Empty(m.lcProvenienta), m.lcProvenienta + crlf, '') + ;
Iif((m.llPlatitorTVAMfin And !m.llCodRO) Or (!m.llPlatitorTVAMfin And m.llCodRO), ' *** ATENTIE *** ', '') + ;
Iif(m.llPlatitorTVAMfin, "PLATITOR TVA (" + Alltrim(loPartener.datatvamfin) + ")", "NEPLATITOR TVA") + crlf + ;
'Stare: ' + Alltrim(loPartener.stare) + crlf + ;

View File

@@ -73,6 +73,33 @@
*!* anulare din oficiu) si mesajul ANAF integral (mesaj_ScpTVA), citite din cursorul deja parsat de
*!* ParseJsonANAFv8; parsarea esuata a datelor de perioada se logheaza
*!* 31.07.2026
*!* marius.mutu
*!* VerificareANAF: cache ANAF pe ISTORIC_CODURI_FISCALE (SalveazaIstoricDinCursor/CitesteIstoricPentruCoduri/
*!* OrdineCache/ZileCache/NormalizeazaCoduriCursor); VerificaListaCIF si ANAF_VerificaCuiSingle salveaza
*!* rezultatele ANAF in istoric; VerificaListaCIF primeste al patrulea parametru optional tcTraseu
*!* ('UNIC'/'MASA', implicit MASA) si citeste ordinea cu OrdineCache(tcTraseu), cu plasa de siguranta la
*!* tacere din istoric si provenienta (sursa/data_sursa) marcata in crsANAF si logata; VERIFICARE_CIF
*!* trimite si tvaincasare/splittva/inactiv la salvare; sursa/data_sursa ajung si pana la obiectul
*!* intors de VERIFICARE_CIF (GetEmptyMfinObj, Procedure ANAF, cursorul cVerificareCod)
*!* 01.08.2026
*!* marius.mutu
*!* VerificaListaCIF, ramura CACHE,ANAF: apelul ramas catre ANAF_SincronWebService_PlatitorTva foloseste
*!* acum un alias temporar (mergeuit apoi in crsANAF), ca randurile deja citite din cache sa nu mai fie
*!* sterse si reetichetate gresit CACHE_INDISP; plus golire explicita a aliasului la intrarea in
*!* VerificaListaCIF, ca sa nu mai acumuleze intre apeluri succesive cu alias implicit (Procedure ANAF) -
*!* defecte gasite la revizia de ansamblu dupa transa cache ANAF
*!* 01.08.2026
*!* marius.mutu
*!* SalveazaIstoricDinCursor trimite acum provenienta randului (sursa) la save_istoric_cod_fiscal, al
*!* 27-lea parametru pnDinCache; pachetul Oracle nu mai improspateaza DATAORAV_ANAF cand randul vine
*!* din cache (CACHE/CACHE_INDISP) - doar cand vin efectiv date noi de la ANAF - dar DATAORAV/ID_UTILV
*!* (urma de audit "cine si cand a verificat partenerul") se actualizeaza in continuare, indiferent de
*!* provenienta; altfel cache-ul isi reseta singur ceasul de prospetime la fiecare citire si nu mai
*!* expira niciodata
*!* http://ec.europa.eu/taxation_customs/vies/viesquer.do
*!* http://localhost/contafinupdate/verificarecod.aspx/verificarecod/verificare/CIF/1879855/MFIN
*!* http://localhost/contafinupdate/verificarecod.aspx/verificarecod/verificare/CNP/1810228134187
@@ -598,7 +625,7 @@ Define Class VerificareCod As Custom
Local loEx As Exception
Local lcMfinanteURL, lcMfinanteParams, lcRomfastURL, llMFINURL, loMFIN, loVIES, lcProcedura, llInterogareAnaf
Local lStare, lcApart, lcBloc, lcDataTVAMFIN, lcEtaj, lcLocalitate, lcNr, lcScara, lcStrada
Local llPlatitorTVAMFIN, lnSucces, llTVAIncasare, llSplitTVA, llInactiv, ldData
Local llPlatitorTVAMFIN, lnSucces, llTVAIncasare, llSplitTVA, llInactiv, ldData, lcSqlIstoric, lcSursa, ldDataSursa
Local lcTipInterogare, llInterogareVies, llInterogareMfin
If Empty(tcTipInterogare) Or Type('tcTipInterogare') <> 'C'
@@ -653,11 +680,13 @@ Define Class VerificareCod As Custom
llTVAIncasare = .F.
llSplitTVA = .F.
llInactiv = .F.
lcSursa = ''
ldDataSursa = {}
Create Cursor cVerificareCod (Valid L, eroare c(250), cod V(100) Null, firma V(100), adresa V(250), judet V(100), ;
regcom V(30), codpostal V(20), telefon V(30), fax V(30), datatvamfin V(30), platitortvamfin L, VIES L, PlatitorTVA L, ;
stare V(100), strada V(100), nr V(25), localitate V(100), Bloc V(30), Scara V(10), Etaj V(10), Apart V(20), ;
tvaincasare L, splittva L, inactiv L)
tvaincasare L, splittva L, inactiv L, sursa C(20), data_sursa D)
Cursortoxml("cVerificareCod", "lcXML", 1, 0, 0, "1")
Select cVerificareCod
@@ -698,6 +727,8 @@ Define Class VerificareCod As Custom
llTvaIncasare = loMFIN.tvaIncasare
llSplitTVA = loMFIN.SplitTVA
llInactiv = loMFIN.Inactiv
lcSursa = Nvl(loMFIN.sursa, 'ANAF')
ldDataSursa = Nvl(loMFIN.data_sursa, {})
Endif && llValid AND llInterogareMfin
If m.llValid And m.llRO And m.llInterogareMfin
@@ -723,7 +754,9 @@ Define Class VerificareCod As Custom
lcApart = loMFIN.apart
llTvaIncasare = loMFIN.tvaIncasare
llSplitTVA = loMFIN.SplitTVA
llInactiv = loMFIN.Inactiv
llInactiv = loMFIN.Inactiv
lcSursa = Nvl(loMFIN.sursa, 'ANAF')
ldDataSursa = Nvl(loMFIN.data_sursa, {})
Endif && llValid AND llInterogareMfin
*!* VERIFICARE VIES pentru platitori TVA
@@ -747,8 +780,8 @@ Define Class VerificareCod As Custom
lcStrada = This.RemoveCharacters(m.lcStrada)
TRY
Insert Into cVerificareCod(Valid, eroare, cod, firma, adresa, judet, regcom, codpostal, telefon, fax, datatvamfin, platitortvamfin, VIES, PlatitorTVA, stare, strada, nr, localitate, bloc, scara, etaj, apart, tvaincasare, splittva, inactiv) ;
Values (m.llValid, Left(m.lcEroare, 250), m.lcVerificareCod, m.lcFirma, m.lcAdresa, m.lcJudet, m.lcRegCom, m.lcCodpostal, m.lcTelefon, m.lcFax, m.lcDataTVAMFIN, m.llPlatitorTVAMFIN, m.llVies, m.llPlatitorTVA, m.lcStare, m.lcStrada, m.lcNr, m.lcLocalitate, m.lcBloc, m.lcscara, m.lcetaj, m.lcapart, m.llTVAIncasare, m.llSplitTVA, m.llInactiv)
Insert Into cVerificareCod(Valid, eroare, cod, firma, adresa, judet, regcom, codpostal, telefon, fax, datatvamfin, platitortvamfin, VIES, PlatitorTVA, stare, strada, nr, localitate, bloc, scara, etaj, apart, tvaincasare, splittva, inactiv, sursa, data_sursa) ;
Values (m.llValid, Left(m.lcEroare, 250), m.lcVerificareCod, m.lcFirma, m.lcAdresa, m.lcJudet, m.lcRegCom, m.lcCodpostal, m.lcTelefon, m.lcFax, m.lcDataTVAMFIN, m.llPlatitorTVAMFIN, m.llVies, m.llPlatitorTVA, m.lcStare, m.lcStrada, m.lcNr, m.lcLocalitate, m.lcBloc, m.lcscara, m.lcetaj, m.lcapart, m.llTVAIncasare, m.llSplitTVA, m.llInactiv, m.lcSursa, m.ldDataSursa)
Select cVerificareCod
Go Top
@@ -757,7 +790,8 @@ Define Class VerificareCod As Custom
*** ROA salvez datele in istoric_coduri_fiscale
If Type('goExecutor') = 'O'
Private pcCodFiscal, pcFirma, pcAdresa, pcJudet, pcRegCom, pcCodPostal, pcTelefon, pcFax, pcDataTvamfin, pnPlatitorTvaMfin, pcStare, pnPlatitorTvaVies, pnInterogareVies
Private pcCodFiscal, pcFirma, pcAdresa, pcJudet, pcRegCom, pcCodPostal, pcTelefon, pcFax, pcDataTvamfin, pnPlatitorTvaMfin, pcStare, pnPlatitorTvaVies, pnInterogareVies, ;
pnInactiv, pnTvaIncasare, pnSplitTva
pcCodFiscal = m.lcVerificareCod
pcFirma = m.lcFirma && Strtran(Strtran(Upper(Alltrim(Nvl(m.lcFirma, ''))), Chr(170), 'S'), Chr(222), 'T')
pcAdresa = m.lcAdresa && Strtran(Strtran(Upper(Alltrim(Nvl(m.lcAdresa, ''))), Chr(170), 'S'), Chr(222), 'T')
@@ -771,8 +805,14 @@ Define Class VerificareCod As Custom
pcStare = Upper(Alltrim(Nvl(m.lcStare, '')))
pnPlatitorTvaVies = Iif(m.llPlatitorTVA, 1, 0)
pnInterogareVies = Iif(m.llVies, 1, 0)
pnInactiv = Iif(m.llInactiv, 1, 0)
pnTvaIncasare = Iif(m.llTVAIncasare, 1, 0)
pnSplitTva = Iif(m.llSplitTVA, 1, 0)
If !Empty(m.pcFirma)
lnSucces = goExecutor.oExecuta("begin pack_parteneri.save_istoric_cod_fiscal(?pcCodFiscal,?pcFirma,?pcAdresa,?pcJudet,?pcRegCom,?pcCodPostal,?pcTelefon,?pcFax,?pcDataTvamfin,?pnPlatitorTvaMfin,?pcStare,?pnPlatitorTvaVies,?pnInterogareVies,?gnIdUtil); end;")
*!* 02.08.2026 marius.mutu: tnDinCache = 2 - salvare fara date de interval, nu marcheaza prospetime de cache
lcSqlIstoric = "begin pack_parteneri.save_istoric_cod_fiscal(?pcCodFiscal,?pcFirma,?pcAdresa,?pcJudet,?pcRegCom,?pcCodPostal,?pcTelefon,?pcFax,?pcDataTvamfin,?pnPlatitorTvaMfin,?pcStare," + ;
"?pnPlatitorTvaVies,?pnInterogareVies,?gnIdUtil,?pnInactiv,?pnTvaIncasare,?pnSplitTva,tnDinCache=>2); end;"
lnSucces = goExecutor.oExecuta(m.lcSqlIstoric)
Endif
Endif
*** CONTAFIN salvez datele in istoric_coduri_fiscale
@@ -810,7 +850,8 @@ Define Class VerificareCod As Custom
&& verificare serviciu web ANAF
loVerificareANAF = Createobject("VerificareANAF") && validare.prg
lcCursorVerificareANAF = loVerificareANAF.VerificaListaCIF(m.lcCodFiscal, m.ldData)
*!* 01.08.2026 marius.mutu: verificare unui singur CIF cerut manual - traseu UNIC (ANAF intai), nu implicitul MASA
lcCursorVerificareANAF = loVerificareANAF.VerificaListaCIF(m.lcCodFiscal, m.ldData, , 'UNIC')
If Used(m.lcCursorVerificareANAF)
If Reccount(m.lcCursorVerificareANAF) >= 1
Select (m.lcCursorVerificareANAF)
@@ -836,6 +877,8 @@ Define Class VerificareCod As Custom
loMFIN.TVAIncasare = tvaincasare
loMFIN.SplitTVA = splittva
loMFIN.Inactiv = inactiv
loMFIN.sursa = Nvl(sursa, 'ANAF')
loMFIN.data_sursa = Nvl(data_sursa, {})
Endif
Endif
@@ -1559,7 +1602,9 @@ Define Class VerificareCod As Custom
AddProperty(loMFIN, "Apart", "")
AddProperty(loMFIN, "TvaIncasare", .F.)
AddProperty(loMFIN, "SplitTVA", .F.)
AddProperty(loMFIN, "Inactiv", .F.)
AddProperty(loMFIN, "Inactiv", .F.)
AddProperty(loMFIN, "sursa", '')
AddProperty(loMFIN, "data_sursa", {})
Return loMFIN
Endfunc && GetEmptyMfinObj
Enddefine
@@ -1637,6 +1682,7 @@ Function ANAF_VerificaCuiSingle
If !Empty(m.lcJsonString) And Left(m.lcJsonString, 1) = '{'
Use In (Select(m.lcAliasTemp))
loVerificareANAF.ParseJsonANAFv8(nfjsonread(m.lcJsonString), m.lcAliasTemp)
loVerificareANAF.SalveazaIstoricDinCursor(m.lcAliasTemp, gnIdUtil)
loResult = ANAF_VerdictDinCursor(m.lcAliasTemp, m.lnCuiCautat, @tlNegasit, @tcClasaEsec)
Else
tcClasaEsec = 'RASPUNS_NEINTELES'
@@ -1671,6 +1717,8 @@ Function ANAF_VerdictDinCursor
If Used(m.tcAlias)
Select (m.tcAlias)
*!* 01.08.2026 marius.mutu: pozitionare explicita - apelantul poate lasa cursorul pe EOF
Go Top
lnReccountTemp = Reccount()
If m.lnReccountTemp = 1 And !Empty(denumire)
loResult = Createobject("empty")
@@ -1813,6 +1861,9 @@ Endfunc && ANAF_SondaOpreste
*********************************************
Define Class VerificareANAF As Custom
*!* 01.08.2026 marius.mutu: ultimul esec ANAF de pe traseul batch - se arata o singura data, la final, doar daca raman coduri neacoperite
cMesajANAF = ''
Procedure Init
If !'nfjsonread' $ Lower(Set("Procedure"))
Set Procedure To nfjsonread.prg Additive
@@ -1826,16 +1877,27 @@ Define Class VerificareANAF As Custom
*** VerificaListaCIF("31103995,1879855", Date(), "crsANAF")
*** Verifica codurile fiscale din lista, la data
*** Intoarce un cursor crsANAF (cui N(13), Data d, denumire c(60), adresa c(244), tva L, data_sfarsit d, data_anul_imp d, mesaj c(100))
*** Ordinea ANAF/cache vine din OrdineCache(tcTraseu) - tcTraseu optional ('UNIC'/'MASA'), implicit 'MASA'
*** cand lipseste sau e gol; pe CACHE,ANAF codurile cu rand proaspat in istoric nu se mai trimit la ANAF;
*** indiferent de ordine, codurile ramase fara raspuns (tacere) se completeaza din istoric drept plasa de
*** siguranta - codul gasit explicit "notFound" de ANAF nu atinge cache-ul, pentru ca primeste deja un
*** rand in crsANAF (denumire goala) si nu mai e considerat "tacere"
*************************************
Function VerificaListaCIF
Lparameters tcListaCIF, tdData, tcAlias
Lparameters tcListaCIF, tdData, tcAlias, tcTraseu
* tcListaCIF: lista coduri fiscale sau numele unui cursor cu coduri fiscale
* tcTraseu: optional, 'UNIC' sau 'MASA' (vezi OrdineCache); implicit 'MASA' cand lipseste - apelantii
* existenti (fara al patrulea parametru) raman pe comportamentul de azi
Local llUsed, lcCursorListaCIF, lnRec, lnRecs, lcAlias
*!* 31.07.2026 marius.mutu: al patrulea parametru tcTraseu forteaza OrdineCache(tcTraseu) in loc de 'MASA' fix
Local lcOrdine, ldData, lcAliasNorm, lcListaCoduriN, lcCursorRamas, lnCuiCurent, lcCodFiscalCurent, ldDataCurenta, llGasitCache, lcCursorAnafTemp, loRandAnaf, lnFaraRaspuns
lcCursorListaCIF = ""
llUsed = .F.
lcAlias = ""
lnFaraRaspuns = 0
This.cMesajANAF = ''
goLog.Log('tcListaCIF: ' + tcListaCIF, 'VerificaListaCIF')
If Used(tcListaCIF)
@@ -1844,7 +1906,8 @@ Define Class VerificareANAF As Custom
llUsed = .T.
Else
* lista
lcCursorListaCIF = "cListaCIFTemp"
*!* 01.08.2026 marius.mutu: nume unic - "cListaCIFTemp" colida cu variabila locala din overificari.vc2:2734
lcCursorListaCIF = "crsListaCIFIntern"
lnRecs = Getwordcount(m.tcListaCIF, ',')
Create Cursor (lcCursorListaCIF) (cod_fiscal c(30) Null, data D null)
For lnRec = 1 To m.lnRecs
@@ -1853,14 +1916,150 @@ Define Class VerificareANAF As Custom
Endfor
Endif
lcAlias = This.ANAF_SincronWebService_PlatitorTva(m.lcCursorListaCIF, m.tdData, m.tcAlias)
ldData = Iif(!Empty(m.tdData) And Type('tdData') = "D", m.tdData, Date())
lcAlias = Iif(!Empty(m.tcAlias) And Type('tcAlias') = "C", m.tcAlias, "crsANAF")
*!* 01.08.2026 marius.mutu: golire explicita la intrare - dupa fixul de mai jos, nimic altceva nu mai garanteaza un alias curat pe niciun traseu
Use In (Select(m.lcAlias))
lcOrdine = This.OrdineCache(Iif(Empty(m.tcTraseu), 'MASA', Upper(Alltrim(m.tcTraseu))))
lcAliasNorm = This.NormalizeazaCoduriCursor(m.lcCursorListaCIF, m.ldData)
If Left(m.lcOrdine, 5) == 'CACHE'
* CACHE,ANAF: codurile cu rand proaspat in istoric nu se mai trimit la ANAF
lcListaCoduriN = ''
Select (m.lcAliasNorm)
Scan For cui_n <> 0
lcListaCoduriN = m.lcListaCoduriN + Iif(Empty(m.lcListaCoduriN), '', ',') + Alltrim(Str(cui_n))
Select (m.lcAliasNorm)
Endscan
This.CitesteIstoricPentruCoduri(m.lcListaCoduriN, m.ldData, m.lcAlias, 'CACHE')
lcCursorRamas = 'crsListaRamasANAF'
Use In (Select(m.lcCursorRamas))
Create Cursor (m.lcCursorRamas) (cod_fiscal c(30) Null, data D null)
Select (m.lcAliasNorm)
Scan
lnCuiCurent = cui_n
lcCodFiscalCurent = cod_fiscal
ldDataCurenta = data
llGasitCache = .F.
If m.lnCuiCurent <> 0 And Used(m.lcAlias) And Reccount(m.lcAlias) > 0
Select (m.lcAlias)
Locate For cui = m.lnCuiCurent
llGasitCache = Found()
Endif
If !m.llGasitCache
Insert Into (m.lcCursorRamas) (cod_fiscal, data) Values (m.lcCodFiscalCurent, m.ldDataCurenta)
Endif
Select (m.lcAliasNorm)
Endscan
If Reccount(m.lcCursorRamas) > 0
*!* 01.08.2026 marius.mutu: alias temporar - ANAF_SincronWebService_PlatitorTva goleste neconditionat aliasul primit (:2025), iar aici e deja populat din cache
lcCursorAnafTemp = 'crsAnafBatchTemp'
Use In (Select(m.lcCursorAnafTemp))
lcCursorAnafTemp = This.ANAF_SincronWebService_PlatitorTva(m.lcCursorRamas, m.tdData, m.lcCursorAnafTemp)
If Used(m.lcCursorAnafTemp) And Reccount(m.lcCursorAnafTemp) > 0
Select (m.lcCursorAnafTemp)
Scan
Scatter Name loRandAnaf Memo
Insert Into (m.lcAlias) FROM NAME loRandAnaf
Select (m.lcCursorAnafTemp)
Endscan
Endif
Use In (Select(m.lcCursorAnafTemp))
Endif
Use In (Select(m.lcCursorRamas))
Else
* ANAF,CACHE: comportamentul de azi, ANAF intai pentru toate codurile
lcAlias = This.ANAF_SincronWebService_PlatitorTva(m.lcCursorListaCIF, m.tdData, m.lcAlias)
Endif
If !m.llUsed
Use In (Select(lcCursorListaCIF))
Endif
* plasa de siguranta la tacere, indiferent de ordine: codurile fara rand in crsANAF (nici din ANAF,
* nici din cache) se completeaza acum din istoric, marcate CACHE_INDISP; un rand deja prezent
* (raspuns ANAF gasit sau notFound, sau deja servit din cache mai sus) nu e atins
Select (m.lcAliasNorm)
Scan For cui_n <> 0
lnCuiCurent = cui_n
llGasitCache = .F.
If Used(m.lcAlias) And Reccount(m.lcAlias) > 0
Select (m.lcAlias)
Locate For cui = m.lnCuiCurent
llGasitCache = Found()
Endif
If !m.llGasitCache
This.CitesteIstoricPentruCoduri(Transform(m.lnCuiCurent), m.ldData, m.lcAlias, 'CACHE_INDISP')
If Used(m.lcAlias)
Select (m.lcAlias)
Locate For cui = m.lnCuiCurent
Endif
lnFaraRaspuns = m.lnFaraRaspuns + Iif(Used(m.lcAlias) And Found(), 0, 1)
Endif
Select (m.lcAliasNorm)
Endscan
Use In (Select(m.lcAliasNorm))
*!* 01.08.2026 marius.mutu: un singur mesaj la final, doar cand au ramas coduri fara verdict (nici de la ANAF, nici din cache)
If m.lnFaraRaspuns > 0 And !Empty(This.cMesajANAF)
AMESSAGEBOX(This.cMesajANAF + Chr(13) + Chr(10) + Alltrim(Str(m.lnFaraRaspuns)) + ' coduri fiscale nu au putut fi verificate.', 0 + 48, _Screen.Caption)
Endif
If Used(m.lcAlias) And Reccount(m.lcAlias) > 0
This.SalveazaIstoricDinCursor(m.lcAlias, gnIdUtil)
Endif
* criteriul 9: fiecare rand completat din cache (CACHE sau CACHE_INDISP) se lasa si in goLog, cu codul si data_sursa
If Used(m.lcAlias) And Reccount(m.lcAlias) > 0
Select (m.lcAlias)
Scan For Left(Nvl(sursa, ''), 5) == 'CACHE'
goLog.Log('cache cui=' + Transform(cui) + ' sursa=' + Alltrim(sursa) + ' data_sursa=' + Dtoc(Nvl(data_sursa, {})), 'VerificaListaCIF')
Select (m.lcAlias)
Endscan
Endif
Return m.lcAlias
Endfunc && AnafPlatitorTVA
*************************************
*** Normalizeaza codurile fiscale dintr-un cursor in forma tcCursorListaCIF (cod_fiscal C(30)[, data D]),
*** dupa acelasi tipar ca ANAF_SincronWebService_PlatitorTva (cod tara RO, doar cifre, <=10 caractere).
*** Cand sursa nu are coloana data (ex. orapoarte.prg:1994/2311, cursor doar cu cod_fiscal), se
*** foloseste tdData pentru toate randurile - acelasi fallback ca llDataCursor din functia de mai sus
*** Intoarce un cursor nou (cod_fiscal, data, cui_n N(13)) - cui_n = 0 cand codul nu e un CUI RO valid
*************************************
Function NormalizeazaCoduriCursor
Lparameters tcCursorListaCIF, tdData
Local loVerificareCod As "VerificareCod", lcCodFiscal, lcCodTara, lcCodFiscalFRO, lcAliasNorm, lcSelect, llDataCursor, ldDataRand, ldDataImplicit
lcSelect = Select()
lcAliasNorm = 'crsCoduriNormalizate'
Use In (Select(m.lcAliasNorm))
Create Cursor (m.lcAliasNorm) (cod_fiscal C(30), data D, cui_n N(13))
ldDataImplicit = Iif(Type('tdData') = 'D' And !Empty(m.tdData), m.tdData, Date())
llDataCursor = (Type(m.tcCursorListaCIF + '.data') = 'D')
loVerificareCod = Createobject("VerificareCod")
Select (m.tcCursorListaCIF)
Scan
*!* 01.08.2026 marius.mutu: cursoarele sursa au cod_fiscal/data nullable - fara Nvl, insertul de mai jos pica pe coloanele not null
lcCodFiscal = Alltrim(Nvl(cod_fiscal, ''))
lcCodTara = loVerificareCod.GetCodTara(m.lcCodFiscal)
lcCodFiscalFRO = Strtran(m.lcCodFiscal, m.lcCodTara, '')
lcCodFiscalFRO = Strtran(Strtran(Strtran(m.lcCodFiscalFRO, ' ', ''), 'RO', ''), 'R', '')
ldDataRand = Iif(m.llDataCursor And !Empty(Nvl(data, {})), Nvl(data, {}), m.ldDataImplicit)
Insert Into (m.lcAliasNorm) (cod_fiscal, data, cui_n) Values ;
(m.lcCodFiscal, m.ldDataRand, Iif(m.lcCodTara = 'RO' And Isdigit(m.lcCodFiscalFRO) And Len(m.lcCodFiscalFRO) <= 10, Int(Val(m.lcCodFiscalFRO)), 0))
Select (m.tcCursorListaCIF)
Endscan
Select (m.lcSelect)
Return m.lcAliasNorm
Endfunc && NormalizeazaCoduriCursor
*
Function ANAF_SincronWebService_PlatitorTva
Lparameters tcCursorListaCIF, tdData, tcAlias
@@ -1903,7 +2102,7 @@ Define Class VerificareANAF As Custom
Try
loHTTP = Createobject('Microsoft.XMLHTTP') && 04.07.2016
Catch To loEx
AMESSAGEBOX(loEx.Message, 0 + 16, _Screen.Caption)
This.cMesajANAF = loEx.Message
Endtry
Endif
If Type('loHTTP') <> 'O'
@@ -1960,46 +2159,16 @@ Define Class VerificareANAF As Custom
lcSend = nfjsoncreate(@laCoduri)
goLog.Log('lcSend: ' + m.lcSend, 'ANAF_SincronWebService_PlatitorTva')
lcJsonString = ''
*!* 31.07.2026 marius.mutu: procesarea raspunsului (status+corp) mutata in ProceseazaRaspunsHTTP, mai jos
Try
loHTTP.Open('POST', lcServer, .F.) && !!! POST e blocat de furnizor
loHTTP.setRequestHeader("Content-Type", "application/json;")
loHTTP.Send(lcSend)
If loHTTP.Status = 200
lcJsonString = ALLTRIM(loHTTP.responseText)
IF LEFT(m.lcJsonString,1) <> '{'
IF 'mentenanta'$LOWER(m.lcJsonString)
AMESSAGEBOX('Serviciul web ANAF este in mentenanta!',0+48,_screen.Caption)
ELSE
AMESSAGEBOX('Serviciul web ANAF nu a intors un raspuns corespunzator.!' + CHR(13) + CHR(10) + m.lcJsonString,0+48,_screen.Caption)
ENDIF
lcJsonString = ''
ENDIF
ENDIF
lcAlias = This.ProceseazaRaspunsHTTP(loHTTP.Status, loHTTP.responseText, m.tcAlias)
Catch To loEx
AMESSAGEBOX(loEx.Message, 0 + 16, _Screen.Caption)
Endtry
This.cMesajANAF = loEx.Message
Endtry
*
goLog.Log('lcJsonString: ' + m.lcJsonString, 'ANAF_SincronWebService_PlatitorTva')
*
If Not Empty(m.lcJsonString)
TRY
loJsonObject = nfjsonread(m.lcJsonString) && nfJson from http://vfpx.codeplex.com/
lcCodJudet = ""
IF TYPE('loJsonObject.found_vfpsafe_[1].adresa_domiciliu_fiscal.dcod_judet') <> 'U'
lcCodJudet = loJsonObject.found_vfpsafe_[1].adresa_domiciliu_fiscal.dcod_judet
ENDIF
IF !EMPTY(m.lcCodJudet)
lcAlias = This.ParseJsonANAFv8(loJsonObject, m.tcAlias)
ELSE
lcMesaj = 'Serviciul web ANAF intors mesaj de eroare: ' + IIF(TYPE('loJsonObject.message') = 'C', loJsonObject.message, '')
AMESSAGEBOX(m.lcMesaj, 0+48, _screen.Caption)
ENDIF
CATCH TO loEx
AMESSAGEBOX(loEx.Message, 0 + 16, _Screen.Caption)
ENDTRY
Endif
If m.lnGrup < m.lnGrupuri
INKEY(m.lnWaitSeconds)&& astept o secunda intre interogari
ENDIF
@@ -2008,6 +2177,51 @@ Define Class VerificareANAF As Custom
Return m.lcAlias
Endfunc && ANAF_SincronWebService_PlatitorTva
*************************************
*** Proceseaza UN raspuns HTTP deja primit pe calea batch (status + corp), separat de trimiterea
*** cererii ca sa poata fi testat direct, cu status+corp fabricate, fara transport HTTP real.
*** Corpul se citeste indiferent de status (nu doar pe 200) - ANAF poate intoarce si 404 cu corp
*** JSON complet cand toate codurile din grup sunt inexistente (masurat 27.07.2026), la fel ca pe
*** calea single-CUI (ANAF_VerificaCuiSingle). Un raspuns e considerat inteles cand are structura
*** found/notFound, chiar daca found e gol (lot integral notFound); altfel ramane tacere - cursorul
*** nu se modifica, deci codurile din grup raman fara rand in crsANAF, ca la o cadere reala de serviciu
*************************************
Function ProceseazaRaspunsHTTP
Lparameters tnStatus, tcResponseText, tcAlias
Local lcAlias, lcJsonString, loJsonObject, loEx As Exception, lcMesaj, llRaspunsInteles
lcAlias = Iif(!Empty(m.tcAlias) And Type('tcAlias') = "C", m.tcAlias, "crsANAF")
lcJsonString = Alltrim(Nvl(m.tcResponseText, ''))
goLog.Log('tnStatus: ' + Transform(m.tnStatus) + ' lcJsonString: ' + m.lcJsonString, 'ANAF_SincronWebService_PlatitorTva')
If Empty(m.lcJsonString) Or Left(m.lcJsonString, 1) <> '{'
If !Empty(m.lcJsonString)
IF 'mentenanta'$LOWER(m.lcJsonString)
This.cMesajANAF = 'Serviciul web ANAF este in mentenanta!'
ELSE
This.cMesajANAF = 'Serviciul web ANAF nu a intors un raspuns corespunzator.'
ENDIF
Endif
Return m.lcAlias && tacere: fara corp folosibil, cursorul ramane neschimbat
Endif
Try
loJsonObject = nfjsonread(m.lcJsonString) && nfJson from http://vfpx.codeplex.com/
llRaspunsInteles = (Type('loJsonObject') = 'O' And Pemstatus(m.loJsonObject, 'found_vfpsafe_', 5))
If m.llRaspunsInteles
lcAlias = This.ParseJsonANAFv8(m.loJsonObject, m.tcAlias)
Else
lcMesaj = 'Serviciul web ANAF a intors mesaj de eroare: ' + IIF(TYPE('loJsonObject.message') = 'C', loJsonObject.message, '')
This.cMesajANAF = m.lcMesaj
Endif
Catch To loEx
This.cMesajANAF = loEx.Message
Endtry
Return m.lcAlias
Endfunc && ProceseazaRaspunsHTTP
*************************************
*** Parseaza obiectul cu raspunsul de la ANAF si creeaza cursorul crsANAF
*** intoarce numele cursorului creat
@@ -2027,7 +2241,8 @@ Define Class VerificareANAF As Custom
dataInceputTvaInc D, dataSfarsitTvaInc D, dataActualizareTvaInc D, dataPublicareTvaInc D, tipActTvaInc C(100), statusTvaIncasare L, dataInactivare D, dataReactivare D, dataPublicare D, dataRadiere D, statusInactivi L, ;
dataInceputSplitTVA D, dataAnulareSplitTVA D, statusSplitTVA L, ;
tva L, tvaincasare L, splittva L, inactiv L, ;
mesaj V(100), judet V(100), strada V(100), nr V(20), localitate V(100), Bloc V(20), scara V(20), etaj V(20), apart V(20))
mesaj V(100), judet V(100), strada V(100), nr V(20), localitate V(100), Bloc V(20), scara V(20), etaj V(20), apart V(20), ;
sursa C(20), data_sursa D)
Endif
If !Isnull(loJsonObject)
@@ -2130,7 +2345,8 @@ Define Class VerificareANAF As Custom
loDate.splittva = loDate.statusSplitTVA
loDate.inactiv = loDate.statusInactivi
loDate.mesaj = loDate.mesaj_ScpTVA
loDate.sursa = 'ANAF'
IF !EMPTY(NVL(loDate.cui, 0))
Insert Into (m.lcAlias) FROM NAME loDate
ENDIF
@@ -2143,7 +2359,8 @@ Define Class VerificareANAF As Custom
SCATTER NAME loDate MEMO BLANK
loDate.cui = m.lnCUI
loDate.sursa = 'ANAF'
IF !EMPTY(NVL(loDate.cui, 0))
Insert Into (m.lcAlias) FROM NAME loDate
ENDIF
@@ -2385,6 +2602,232 @@ Define Class VerificareANAF As Custom
Return loAdresa
Endproc
*************************************
*** Parcurge un cursor in forma crsANAF si salveaza fiecare rand in ISTORIC_CODURI_FISCALE
*** prin pack_parteneri.save_istoric_cod_fiscal (26 parametri); commit din 100 in 100 si la final
*** Intoarce numarul de randuri salvate cu succes
*************************************
Function SalveazaIstoricDinCursor
Lparameters tcAlias, tnIdUtil
Local lnSalvate, lcSelect, lcSqlIstoric, lnRecnoInit
Private pcCodFiscal, pcFirma, pcAdresa, pcJudet, pcRegCom, pcCodPostal, pcTelefon, pcFax, pcDataTvamfin, ;
pnPlatitorTvaMfin, pcStare, pnPlatitorTvaVies, pnInterogareVies, pnIdUtil, ;
pnInactiv, pnTvaIncasare, pnSplitTva, ;
pdInceputScpTva, pdSfarsitScpTva, pdAnulImpScpTva, pdInceputTvaInc, pdSfarsitTvaInc, ;
pdInactivare, pdReactivare, pdInceputSplitTva, pdAnulareSplitTva, pnDinCache
lnSalvate = 0
If Empty(m.tcAlias) Or !Used(m.tcAlias)
Return m.lnSalvate
Endif
lcSelect = Select()
pnIdUtil = m.tnIdUtil
Select (m.tcAlias)
lnRecnoInit = Recno()
Scan For cui <> 0
pcCodFiscal = Transform(cui)
pcFirma = Nvl(firma, '')
pcAdresa = Nvl(adresa, '')
pcJudet = Nvl(judet, '')
pcRegCom = Nvl(nrRegCom, '')
pcCodPostal = ''
pcTelefon = ''
pcFax = ''
pcDataTvamfin = ''
pnPlatitorTvaMfin = 0
pcStare = ''
pnPlatitorTvaVies = 0
pnInterogareVies = 0
pnInactiv = Iif(Nvl(inactiv, .F.), 1, 0)
pnTvaIncasare = Iif(Nvl(tvaincasare, .F.), 1, 0)
pnSplitTva = Iif(Nvl(splittva, .F.), 1, 0)
pdInceputScpTva = data_inceput_ScpTVA
pdSfarsitScpTva = data_sfarsit_ScpTVA
pdAnulImpScpTva = data_anul_imp_ScpTVA
pdInceputTvaInc = dataInceputTvaInc
pdSfarsitTvaInc = dataSfarsitTvaInc
pdInactivare = dataInactivare
pdReactivare = dataReactivare
pdInceputSplitTva = dataInceputSplitTVA
pdAnulareSplitTva = dataAnulareSplitTVA
*!* 01.08.2026 marius.mutu: pnDinCache=1 cand randul vine din cache - opreste improspatarea DATAORAV_ANAF pe ecoul din cache, jos in pachet
pnDinCache = Iif(Left(Nvl(sursa, ''), 5) == 'CACHE', 1, 0)
lcSqlIstoric = "begin pack_parteneri.save_istoric_cod_fiscal(?pcCodFiscal,?pcFirma,?pcAdresa,?pcJudet,?pcRegCom,?pcCodPostal,?pcTelefon,?pcFax,?pcDataTvamfin,?pnPlatitorTvaMfin,?pcStare," + ;
"?pnPlatitorTvaVies,?pnInterogareVies,?pnIdUtil,?pnInactiv,?pnTvaIncasare,?pnSplitTva,?pdInceputScpTva,?pdSfarsitScpTva," + ;
"?pdAnulImpScpTva,?pdInceputTvaInc,?pdSfarsitTvaInc,?pdInactivare,?pdReactivare,?pdInceputSplitTva,?pdAnulareSplitTva,?pnDinCache); end;"
If goExecutor.oExecuta(m.lcSqlIstoric)
lnSalvate = m.lnSalvate + 1
If Mod(m.lnSalvate, 100) = 0
goExecutor.oExecuta('COMMIT')
Endif
Endif
Select (m.tcAlias)
Endscan
If m.lnSalvate > 0
goExecutor.oExecuta('COMMIT')
Endif
*!* 01.08.2026 marius.mutu: Scan lasa pointerul pe EOF - il pun la loc, ca sa nu afectez apelantul
Select (m.tcAlias)
Try
Go m.lnRecnoInit
Catch
Go Top
Endtry
Select (m.lcSelect)
Return m.lnSalvate
Endfunc && SalveazaIstoricDinCursor
*************************************
*** Citeste din ISTORIC_CODURI_FISCALE ultima verificare proaspata (pe DATAORAV_ANAF) pentru
*** codurile din tcListaCoduriN (normalizate, numerice, separate prin virgula) si calculeaza
*** in SQL, la tdData, verdictele din intervale (platitor TVA, TVA la incasare, split TVA, inactiv)
*** Adauga randurile in tcAlias (cursor in forma crsANAF + sursa/data_sursa), creandu-l daca lipseste
*** tcSursa (optional, implicit 'CACHE') eticheteaza randurile inserate - 'CACHE' sau 'CACHE_INDISP'
*** Un rand NU se intoarce cand tdData e inainte de inceputul unui interval cunoscut (scpTVA/TVAINC/
*** inactivare) - ANAF intoarce o singura perioada, nu istoricul complet, deci pentru o data anterioara
*** primei perioade memorate cache-ul nu poate afirma "nu era" - codul ramane netratat, merge la ANAF
*** Intoarce numele cursorului; ramane gol, fara eroare, cand nu gaseste nimic
*************************************
Function CitesteIstoricPentruCoduri
Lparameters tcListaCoduriN, tdData, tcAlias, tcSursa
Local lcAlias, lcCursorIstoric, lcSql, ldData, lnZileCache, lcSelect, lcSursa
*!* 30.07.2026 marius.mutu: pdDataCache/pnZileCache Private, nu Local, ca sa fie vizibile in goExecutor.oExecuta la bind
Private pdDataCache, pnZileCache
lcAlias = Iif(!Empty(m.tcAlias) And Type('tcAlias') = "C", m.tcAlias, "crsANAF")
ldData = Iif(Type('tdData') = 'D' And !Empty(m.tdData), m.tdData, Date())
lcSursa = Iif(!Empty(m.tcSursa) And Type('tcSursa') = 'C', Upper(Alltrim(m.tcSursa)), 'CACHE')
pdDataCache = m.ldData
lcSelect = Select()
If !Used(m.lcAlias)
*!* 31.07.2026 marius.mutu: aceeasi forma ca crsANAF din ParseJsonANAFv8 - Null pe cele 9 campuri de data muta problema in ParseJsonANAFv8 (SCATTER/aritmetica pe date); NULL-ul din Oracle e tratat cu Nvl la Insert Into, mai jos
Create Cursor (m.lcAlias) (cui N(13), data D, denumire V(100), firma V(100), adresa C(244), nrRegCom C(30), scpTVA L, data_inceput_ScpTVA D, data_sfarsit_ScpTVA D, data_anul_imp_ScpTVA D, mesaj_ScpTVA C(244), ;
dataInceputTvaInc D, dataSfarsitTvaInc D, dataActualizareTvaInc D, dataPublicareTvaInc D, tipActTvaInc C(100), statusTvaIncasare L, dataInactivare D, dataReactivare D, dataPublicare D, dataRadiere D, statusInactivi L, ;
dataInceputSplitTVA D, dataAnulareSplitTVA D, statusSplitTVA L, ;
tva L, tvaincasare L, splittva L, inactiv L, ;
mesaj V(100), judet V(100), strada V(100), nr V(20), localitate V(100), Bloc V(20), scara V(20), etaj V(20), apart V(20), ;
sursa C(20), data_sursa D)
Endif
If Empty(m.tcListaCoduriN)
Select (m.lcSelect)
Return m.lcAlias
Endif
lnZileCache = This.ZileCache()
pnZileCache = m.lnZileCache
lcCursorIstoric = 'crsIstoricCacheTemp'
Use In (Select(m.lcCursorIstoric))
*!* 01.08.2026 marius.mutu: v_tvainc - margine exclusiva (data_sfarsit_tvainc - 1), aliniata cu pack_roartvai; ground truth rtvai_istoric confirma [inceput,sfarsit)
TEXT To lcSql TEXTMERGE Noshow
select cod_fiscal_n, firma, adresa, judet, regcom, dataorav_anaf,
data_inceput_scptva, data_sfarsit_scptva, data_anul_imp_scptva,
data_inceput_tvainc, data_sfarsit_tvainc, data_inactivare, data_reactivare,
data_inceput_splittva, data_anulare_splittva,
case when ?pdDataCache between data_inceput_scptva and nvl(data_sfarsit_scptva, to_date('29991231','yyyymmdd')) then 1 else 0 end as v_scptva,
case when ?pdDataCache between data_inceput_tvainc and nvl(data_sfarsit_tvainc - 1, to_date('29991231','yyyymmdd')) then 1 else 0 end as v_tvainc,
case when ?pdDataCache between data_inceput_splittva and nvl(data_anulare_splittva, to_date('29991231','yyyymmdd')) then 1 else 0 end as v_splittva,
case when data_inactivare is not null and ?pdDataCache >= data_inactivare and (data_reactivare is null or ?pdDataCache < data_reactivare) then 1 else 0 end as v_inactiv
from (select i.*, row_number() over (partition by cod_fiscal_n order by id desc) as rn
from istoric_coduri_fiscale i
where cod_fiscal_n in (<<m.tcListaCoduriN>>)
and dataorav_anaf is not null
and sysdate - dataorav_anaf <= ?pnZileCache)
where rn = 1
and (data_inceput_scptva is null or ?pdDataCache >= data_inceput_scptva)
and (data_inceput_tvainc is null or ?pdDataCache >= data_inceput_tvainc)
and (data_inactivare is null or ?pdDataCache >= data_inactivare)
ENDTEXT
If goExecutor.oExecuta(m.lcSql, m.lcCursorIstoric) And Used(m.lcCursorIstoric)
Select (m.lcCursorIstoric)
Scan
*!* 31.07.2026 marius.mutu: campurile din VALUES calificate cu alias literal crsIstoricCacheTemp - necalificat da eroare 12 (inghitita de ON ERROR), Insert Into ramanea mereu gol
Insert Into (m.lcAlias) (cui, data, denumire, firma, adresa, judet, nrRegCom, ;
data_inceput_ScpTVA, data_sfarsit_ScpTVA, data_anul_imp_ScpTVA, ;
dataInceputTvaInc, dataSfarsitTvaInc, dataInactivare, dataReactivare, ;
dataInceputSplitTVA, dataAnulareSplitTVA, ;
scpTVA, statusTvaIncasare, statusSplitTVA, statusInactivi, ;
tva, tvaincasare, splittva, inactiv, sursa, data_sursa) Values ;
(crsIstoricCacheTemp.cod_fiscal_n, m.ldData, Nvl(crsIstoricCacheTemp.firma, ''), Nvl(crsIstoricCacheTemp.firma, ''), Nvl(crsIstoricCacheTemp.adresa, ''), Nvl(crsIstoricCacheTemp.judet, ''), Nvl(crsIstoricCacheTemp.regcom, ''), ;
Nvl(crsIstoricCacheTemp.data_inceput_scptva, {}), Nvl(crsIstoricCacheTemp.data_sfarsit_scptva, {}), Nvl(crsIstoricCacheTemp.data_anul_imp_scptva, {}), ;
Nvl(crsIstoricCacheTemp.data_inceput_tvainc, {}), Nvl(crsIstoricCacheTemp.data_sfarsit_tvainc, {}), Nvl(crsIstoricCacheTemp.data_inactivare, {}), Nvl(crsIstoricCacheTemp.data_reactivare, {}), ;
Nvl(crsIstoricCacheTemp.data_inceput_splittva, {}), Nvl(crsIstoricCacheTemp.data_anulare_splittva, {}), ;
(crsIstoricCacheTemp.v_scptva = 1), (crsIstoricCacheTemp.v_tvainc = 1), (crsIstoricCacheTemp.v_splittva = 1), (crsIstoricCacheTemp.v_inactiv = 1), ;
(crsIstoricCacheTemp.v_scptva = 1), (crsIstoricCacheTemp.v_tvainc = 1), (crsIstoricCacheTemp.v_splittva = 1), (crsIstoricCacheTemp.v_inactiv = 1), m.lcSursa, crsIstoricCacheTemp.dataorav_anaf)
Endscan
Use In (Select(m.lcCursorIstoric))
Endif
Select (m.lcSelect)
Return m.lcAlias
Endfunc && CitesteIstoricPentruCoduri
*************************************
*** Citeste din OPTIUNI (per schema) ordinea traseelor de verificare ANAF/cache
*** tcTraseu: 'UNIC' (un singur cod) sau 'MASA' (lot); implicit cand randul lipseste din OPTIUNI:
*** 'ANAF,CACHE' pe UNIC, 'CACHE,ANAF' pe MASA
*************************************
Function OrdineCache
Lparameters tcTraseu
Local lcTraseu, lcVarName, lcImplicit, lcSql, lcCursor, lcOrdine, lcSelect
*!* 31.07.2026 marius.mutu: lcSelect salvat/restaurat - fara asta apelantul ramanea cu work area-ul schimbat
lcSelect = Select()
lcTraseu = Upper(Alltrim(Nvl(m.tcTraseu, '')))
lcImplicit = Iif(m.lcTraseu == 'MASA', 'CACHE,ANAF', 'ANAF,CACHE')
lcVarName = 'ANAFCACHEORDINE_' + Iif(m.lcTraseu == 'MASA', 'MASA', 'UNIC')
lcCursor = 'crsOptiuneOrdineCache'
lcOrdine = ''
lcSql = "select varvalue from optiuni where varname = '" + m.lcVarName + "'"
If goExecutor.oExecuta(m.lcSql, m.lcCursor) And Used(m.lcCursor)
If Reccount(m.lcCursor) > 0
lcOrdine = Upper(Strtran(Alltrim(Nvl(&lcCursor..varvalue, '')), ' ', ''))
Endif
Use In (Select(m.lcCursor))
Endif
Select (m.lcSelect)
Return Iif(Empty(m.lcOrdine), m.lcImplicit, m.lcOrdine)
Endfunc && OrdineCache
*************************************
*** Citeste din OPTIUNI (per schema) vechimea maxima a cache-ului, in zile, masurata pe DATAORAV_ANAF
*** Implicit cand randul lipseste din OPTIUNI: 30
*************************************
Function ZileCache
Local lcCursor, lcSql, lnZile, lcSelect
*!* 31.07.2026 marius.mutu: lcSelect salvat/restaurat - acelasi defect ca la OrdineCache
lcSelect = Select()
lcCursor = 'crsOptiuneZileCache'
lnZile = 30
lcSql = "select varvalue from optiuni where varname = 'ANAFCACHEZILE'"
If goExecutor.oExecuta(m.lcSql, m.lcCursor) And Used(m.lcCursor)
If Reccount(m.lcCursor) > 0 And !Empty(Alltrim(Nvl(&lcCursor..varvalue, '')))
lnZile = Val(Alltrim(&lcCursor..varvalue))
Endif
Use In (Select(m.lcCursor))
Endif
If m.lnZile <= 0
lnZile = 30
Endif
Select (m.lcSelect)
Return m.lnZile
Endfunc && ZileCache
Enddefine && VerificareANAF