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