TODO 21: perioade TVA la verificarea codurilor fiscale + diacritice ANAF

- validare.prg: cele 7 campuri de perioada (inregistrare TVA, TVA la incasare,
  inactivare/reactivare) duse din raspunsul ANAF pana in cVerificareCod
- validare.prg: AnafDecodeResponseText - raspunsul HTTP se citeste din responseBody
  prin ADODB.Stream cu Charset utf-8, cu cadere inapoi pe comportamentul vechi;
  repara diacriticele pierdute la marshalling-ul COM al lui responseText
- oproceduri_comune.prg: perioadele in mesajul de detalii; fix id_part N(16), data D
  in crsXMLParteneriVerificare (Insert Into esua tacit, lista ramanea goala)
- overificari.vc2: 7 coloane noi in grid, dublu-click pe Denumire/Cod fiscal deschide
  fisa partenerului, captionuri corectate in "inregistrare TVA"
- oparteneri / ofacturare_comun / onomenclatoare: id_part in SELECT-urile care
  alimenteaza verificarea
- teste headless noi: utile/Teste/test_todo21_perioade_anaf.prg, utile/Teste/todo21/

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GztNyTRxjHqBg5kyNMmcy1
This commit is contained in:
2026-08-22 18:26:17 +03:00
parent 02f4c9ec94
commit 2b695b3656
11 changed files with 1011 additions and 45 deletions

View File

@@ -4541,7 +4541,8 @@ Procedure verificare_parteneri
If Left(Lower(tcXMLParteneri), 5) = "<?xml"
Xmltocursor(tcXMLParteneri, 'crsXMLParteneriVerificare') && denumire, cod_fiscal, [atribut_fiscal], [ales], [data]
Else
Create Cursor crsXMLParteneriVerificare (cod_fiscal C(30), denumire C(100), atribut_fiscal C(2), ales L, dataact D)
*!* 22.08.2026 marius.mutu: id_part si data lipseau din cursor, iar Insert Into de mai jos esua tacut (ON ERROR) - lista ramanea goala
Create Cursor crsXMLParteneriVerificare (cod_fiscal C(30), denumire C(100), atribut_fiscal C(2), ales L, id_part N(16), data D)
lnNrParteneri = Getwordcount(tcXMLParteneri, "|")
For lnPartener = 1 To lnNrParteneri
lcItem = Getwordnum(tcXMLParteneri, m.lnPartener, "|")
@@ -4771,7 +4772,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, lcProvenienta
Local lnRaspuns, loPartener, lcProvenienta, lcPerioade
lcCodFiscal = Transform(m.tcCodFiscal)
lcDenumire = Transform(m.tcDenumire)
@@ -4790,6 +4791,24 @@ Function verifica_partener_show_info
'(sursa: CACHE ' + Dtoc(Nvl(loPartener.data_sursa, Date())) + Iif(Alltrim(Nvl(loPartener.sursa, '')) == 'CACHE_INDISP', ', ANAF indisponibil', '') + ')')
Endif
*!* 22.08.2026 marius.mutu: perioadele ANAF, doar cele completate (traseul mfinante.ro nu le are)
lcPerioade = ''
If Pemstatus(m.loPartener, 'data_inceput_scptva', 5)
If !Empty(Nvl(loPartener.data_inceput_scptva, {}))
lcPerioade = m.lcPerioade + 'Perioada TVA: ' + Dtoc(loPartener.data_inceput_scptva) + ' - ' + ;
Iif(Empty(Nvl(loPartener.data_sfarsit_scptva, {})), 'in vigoare', Dtoc(loPartener.data_sfarsit_scptva)) + ;
Iif(Empty(Nvl(loPartener.data_anul_imp_scptva, {})), '', ' (anulare din oficiu: ' + Dtoc(loPartener.data_anul_imp_scptva) + ')') + crlf
Endif
If !Empty(Nvl(loPartener.data_inceput_tvainc, {}))
lcPerioade = m.lcPerioade + 'Perioada TVA la incasare: ' + Dtoc(loPartener.data_inceput_tvainc) + ' - ' + ;
Iif(Empty(Nvl(loPartener.data_sfarsit_tvainc, {})), 'in vigoare', Dtoc(loPartener.data_sfarsit_tvainc)) + crlf
Endif
If !Empty(Nvl(loPartener.data_inactivare, {}))
lcPerioade = m.lcPerioade + 'Inactivare: ' + Dtoc(loPartener.data_inactivare) + ;
Iif(Empty(Nvl(loPartener.data_reactivare, {})), '', ' Reactivare: ' + Dtoc(loPartener.data_reactivare)) + crlf
Endif
Endif
lcText = 'VERIFICARE CIF: ' + m.lcCodFiscal + ' ' + m.lcDenumire + crlf + crlf + ;
Alltrim(loPartener.firma) + crlf + ;
Iif(!Empty(m.lcProvenienta), m.lcProvenienta + crlf, '') + ;
@@ -4799,7 +4818,8 @@ Function verifica_partener_show_info
'TVA Incasare: ' + Iif(m.llTvaIncasare, 'DA', 'NU') + crlf + ;
'Split TVA: ' + Iif(m.llSplitTVA, 'DA', 'NU') + crlf + ;
'Inactiv: ' + Iif(m.llInactiv, 'DA *** ATENTIE!', 'NU') + crlf + ;
'----------------------------------------------------' + crlf + ;
m.lcPerioade + ;
'----------------------------------------------------' + crlf + ;
'* Adresa: ' + Alltrim(loPartener.adresa) + crlf + ;
'* Judet: ' + loPartener.judet + crlf + ;
'* Nr. inregistrare la Registrul Comertului: ' + loPartener.regcom + crlf + ;

View File

@@ -635,6 +635,7 @@ Define Class VerificareCod As Custom
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, lcSqlIstoric, lcSursa, ldDataSursa
Local ldInceputScpTva, ldSfarsitScpTva, ldAnulImpScpTva, ldInceputTvaInc, ldSfarsitTvaInc, ldInactivare, ldReactivare
Local lcTipInterogare, llInterogareVies, llInterogareMfin
If Empty(tcTipInterogare) Or Type('tcTipInterogare') <> 'C'
@@ -691,11 +692,13 @@ Define Class VerificareCod As Custom
llInactiv = .F.
lcSursa = ''
ldDataSursa = {}
Store {} To ldInceputScpTva, ldSfarsitScpTva, ldAnulImpScpTva, ldInceputTvaInc, ldSfarsitTvaInc, ldInactivare, ldReactivare
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, sursa C(20), data_sursa D)
tvaincasare L, splittva L, inactiv L, sursa C(20), data_sursa D, ;
data_inceput_scptva D, data_sfarsit_scptva D, data_anul_imp_scptva D, data_inceput_tvainc D, data_sfarsit_tvainc D, data_inactivare D, data_reactivare D)
Cursortoxml("cVerificareCod", "lcXML", 1, 0, 0, "1")
Select cVerificareCod
@@ -738,6 +741,14 @@ Define Class VerificareCod As Custom
llInactiv = loMFIN.Inactiv
lcSursa = Nvl(loMFIN.sursa, 'ANAF')
ldDataSursa = Nvl(loMFIN.data_sursa, {})
*!* 22.08.2026 marius.mutu: perioadele vin doar de la ANAF; pe traseul mfinante.ro raman goale
ldInceputScpTva = loMFIN.data_inceput_scptva
ldSfarsitScpTva = loMFIN.data_sfarsit_scptva
ldAnulImpScpTva = loMFIN.data_anul_imp_scptva
ldInceputTvaInc = loMFIN.data_inceput_tvainc
ldSfarsitTvaInc = loMFIN.data_sfarsit_tvainc
ldInactivare = loMFIN.data_inactivare
ldReactivare = loMFIN.data_reactivare
Endif && llValid AND llInterogareMfin
If m.llValid And m.llRO And m.llInterogareMfin
@@ -789,8 +800,10 @@ 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, 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)
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, ;
data_inceput_scptva, data_sfarsit_scptva, data_anul_imp_scptva, data_inceput_tvainc, data_sfarsit_tvainc, data_inactivare, data_reactivare) ;
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, ;
m.ldInceputScpTva, m.ldSfarsitScpTva, m.ldAnulImpScpTva, m.ldInceputTvaInc, m.ldSfarsitTvaInc, m.ldInactivare, m.ldReactivare)
Select cVerificareCod
Go Top
@@ -889,6 +902,13 @@ Define Class VerificareCod As Custom
loMFIN.Inactiv = inactiv
loMFIN.sursa = Nvl(sursa, 'ANAF')
loMFIN.data_sursa = Nvl(data_sursa, {})
loMFIN.data_inceput_scptva = Nvl(data_inceput_ScpTVA, {})
loMFIN.data_sfarsit_scptva = Nvl(data_sfarsit_ScpTVA, {})
loMFIN.data_anul_imp_scptva = Nvl(data_anul_imp_ScpTVA, {})
loMFIN.data_inceput_tvainc = Nvl(dataInceputTvaInc, {})
loMFIN.data_sfarsit_tvainc = Nvl(dataSfarsitTvaInc, {})
loMFIN.data_inactivare = Nvl(dataInactivare, {})
loMFIN.data_reactivare = Nvl(dataReactivare, {})
Endif
Endif
@@ -1615,6 +1635,14 @@ Define Class VerificareCod As Custom
AddProperty(loMFIN, "Inactiv", .F.)
AddProperty(loMFIN, "sursa", '')
AddProperty(loMFIN, "data_sursa", {})
*!* 22.08.2026 marius.mutu: perioadele ANAF (scop TVA, TVA la incasare, inactivitate) duse pana in messagebox
AddProperty(loMFIN, "data_inceput_scptva", {})
AddProperty(loMFIN, "data_sfarsit_scptva", {})
AddProperty(loMFIN, "data_anul_imp_scptva", {})
AddProperty(loMFIN, "data_inceput_tvainc", {})
AddProperty(loMFIN, "data_sfarsit_tvainc", {})
AddProperty(loMFIN, "data_inactivare", {})
AddProperty(loMFIN, "data_reactivare", {})
Return loMFIN
Endfunc && GetEmptyMfinObj
Enddefine
@@ -1687,7 +1715,8 @@ Function ANAF_VerificaCuiSingle
loHTTP = ANAF_CreeazaCerereANAF(m.lnCuiCautat, m.ldData, .F.)
llRaspunsPrimit = .T.
lcJsonString = Alltrim(loHTTP.responseText)
*!* 22.08.2026 marius.mutu: raspunsul ANAF e UTF-8 - decodare din responseBody, altfel diacriticele ajung mojibake (Stare)
lcJsonString = Alltrim(AnafDecodeResponseText(loHTTP))
If !Empty(m.lcJsonString) And Left(m.lcJsonString, 1) = '{'
Use In (Select(m.lcAliasTemp))
@@ -1869,6 +1898,64 @@ Function ANAF_SondaOpreste
Return m.llOprita
Endfunc && ANAF_SondaOpreste
*!* 22.08.2026 marius.mutu: literele romanesti fara corespondent in codepage-ul local devin '?' la conversie, deci se inlocuiesc intai cu litera simpla
Function AnafTextLocal
Lparameters tcText
Local lcText
lcText = Nvl(m.tcText, '')
lcText = Strtran(m.lcText, Chr(196) + Chr(131), 'a')
lcText = Strtran(m.lcText, Chr(196) + Chr(130), 'A')
lcText = Strtran(m.lcText, Chr(200) + Chr(153), 's')
lcText = Strtran(m.lcText, Chr(200) + Chr(152), 'S')
lcText = Strtran(m.lcText, Chr(197) + Chr(159), 's')
lcText = Strtran(m.lcText, Chr(197) + Chr(158), 'S')
lcText = Strtran(m.lcText, Chr(200) + Chr(155), 't')
lcText = Strtran(m.lcText, Chr(200) + Chr(154), 'T')
lcText = Strtran(m.lcText, Chr(197) + Chr(163), 't')
lcText = Strtran(m.lcText, Chr(197) + Chr(162), 'T')
Return Strconv(Strconv(m.lcText, 12), 6)
Endfunc
*!* 22.08.2026 marius.mutu: citeste raspunsul ANAF din responseBody (bytes bruti) printr-un ADODB.Stream cu Charset='utf-8', ca sa pastreze toate diacriticele romanesti; cade pe AnafTextLocal(responseText) doar daca ADODB.Stream nu poate fi folosit
Function AnafDecodeResponseText
Lparameters toHTTP
Local lcText, loStream, loEx As Exception, llOk
If Type('gvANAF_FallbackTextLogat') = 'U'
Public gvANAF_FallbackTextLogat
gvANAF_FallbackTextLogat = .F.
Endif
lcText = ''
llOk = .F.
Try
loStream = Createobject('ADODB.Stream')
loStream.Type = 1
loStream.Open()
loStream.Write(toHTTP.responseBody)
loStream.Position = 0
loStream.Type = 2
loStream.Charset = 'utf-8'
lcText = loStream.ReadText()
loStream.Close()
llOk = .T.
Catch To loEx
llOk = .F.
Endtry
If !m.llOk
If !gvANAF_FallbackTextLogat
If Type('goLog') = 'O'
goLog.Log('AnafDecodeResponseText: ADODB.Stream indisponibil, revenire pe responseText', 'AnafDecodeResponseText')
Endif
gvANAF_FallbackTextLogat = .T.
Endif
lcText = AnafTextLocal(Alltrim(toHTTP.responseText))
Endif
Return m.lcText
Endfunc
*********************************************
*** Verificare coduri fiscale folosind serviciul web ANAF, cate 500 de coduri per interogare
*********************************************
@@ -2206,7 +2293,7 @@ Define Class VerificareANAF As Custom
loHTTP.Open('POST', lcServer, .F.) && !!! POST e blocat de furnizor
loHTTP.setRequestHeader("Content-Type", "application/json;")
loHTTP.Send(lcSend)
lcAlias = This.ProceseazaRaspunsHTTP(loHTTP.Status, loHTTP.responseText, m.tcAlias)
lcAlias = This.ProceseazaRaspunsHTTP(loHTTP.Status, AnafDecodeResponseText(loHTTP), m.tcAlias)
Catch To loEx
This.cMesajANAF = loEx.Message
Endtry
@@ -2234,6 +2321,7 @@ Define Class VerificareANAF As Custom
Local lcAlias, lcJsonString, loJsonObject, loEx As Exception, lcMesaj, llRaspunsInteles
lcAlias = Iif(!Empty(m.tcAlias) And Type('tcAlias') = "C", m.tcAlias, "crsANAF")
*!* 22.08.2026 marius.mutu: decodarea UTF-8 se face in apelant (AnafDecodeResponseText), inainte de a ajunge aici
lcJsonString = Alltrim(Nvl(m.tcResponseText, ''))
goLog.Log('tnStatus: ' + Transform(m.tnStatus) + ' lcJsonString: ' + m.lcJsonString, 'ANAF_SincronWebService_PlatitorTva')