anaf efactura generare token cu citire automata token din romfast.ro

This commit is contained in:
2026-07-07 22:49:57 +03:00
parent 0acdff9647
commit 71bafec09b
7 changed files with 232 additions and 28 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -500,21 +500,200 @@ select a.*, cast(NULL as varchar2(1000)) as factura_detalii, 0 as modificat
Endproc && SaveToken
*!* 07.07.2026
*!* newToken - flux automat OAuth2: state + sesiune PHP + polling pick.php
*!* implementare unica in AnafeFacturaServer; ANAFeFactura deleaga
*!* kill switch ANAF_TOKEN_AUTOFLOW (1=automat, 0=vechi), garda headless
* Intoarce tokenul de acces la ANAF (eFactura) daca este salvat sau obtine un nou token
* Se apeleaza din formularul anaf_token.do_executa
* Se apeleaza din formularul anaf_token.do_executa (prin ANAFeFactura.newToken)
Function newToken
Local lcTokenURL
LOCAL lnAutoFlowVal, lcAutoFlowStr, lcTokenURL, lcState, lcStatePrefix
LOCAL lcBuf1, lcBuf2, lni, lnAscByte, lcHexChars
LOCAL lcBrowserUrl, lcPickUrl, lcExitCode
LOCAL loHTTP, lnStatus, lcResponse, loJson
LOCAL lnStartSec, lnElapsed, lnStep, lnKey
LOCAL loExHTTP, loExJson, loExSave
This.Log('Introduceti in calculator tokenul USB cu semnatura electronica' + LF + ;
'Se va deschide pagina ANAF de generare token. Introduceti PIN-ul pentru semnatura electronica.' + LF + ;
'Copiati codurile "Token" si "Refresh Token" afisate si completati-le in ' + m.gcGeneralIniFile)
* --- Garda headless: server/ROAEFACTURA (lServer=.T.) sau _SCREEN invizibil ---
* Pastreaza EXACT comportamentul vechi al AnafeFacturaServer.newToken
IF This.lServer OR !_SCREEN.Visible
This.Log('Introduceti in calculator tokenul USB cu semnatura electronica' + LF + ;
'Se va deschide pagina ANAF de generare token. Introduceti PIN-ul pentru semnatura electronica.' + LF + ;
'Copiati codurile "Token" si "Refresh Token" afisate si completati-le in ' + m.gcGeneralIniFile)
lcTokenURL = This.cTokenUrl
open_default_app(m.gcGeneralIniFile)
open_default_app(m.lcTokenURL)
RETURN
ENDIF
lcTokenURL = This.cTokenUrl
* --- Kill switch: default 1 la NULL/inexistent/Oracle indisponibil ---
lnAutoFlowVal = 1
TRY
lcAutoFlowStr = ALLTRIM(NVL(citeste_optiune("ANAF_TOKEN_AUTOFLOW"), ''))
IF !EMPTY(lcAutoFlowStr)
lnAutoFlowVal = INT(VAL(lcAutoFlowStr))
ENDIF
CATCH
lnAutoFlowVal = 1
ENDTRY
open_default_app(m.gcGeneralIniFile)
open_default_app(m.lcTokenURL)
lcTokenURL = ALLTRIM(NVL(This.cTokenUrl, ''))
IF EMPTY(lcTokenURL)
lcTokenURL = 'https://romfast.ro/oauth2/'
ENDIF
Endfunc
* --- Kill switch OFF (0) -> comportament vechi nemodificat ---
IF lnAutoFlowVal <> 1
AMESSAGEBOX('Introduceti in calculator tokenul USB cu semnatura electronica' + CHR(13) + CHR(10) + ;
'Se va deschide pagina ANAF de generare token. Introduceti PIN-ul pentru semnatura electronica.' + CHR(13) + CHR(10) + ;
'Copiati codurile "Token" si "Refresh Token" afisate si completati-le in ROA.', 0 + 64, _Screen.Caption)
open_default_app(m.lcTokenURL)
RETURN
ENDIF
* --- Modal initial OK/Anulare ---
IF aMESSAGEBOX('Se va genera un token nou eFactura.' + CHR(13) + ;
'1. Introduceti tokenul USB cu semnatura electronica in calculator.' + CHR(13) + ;
'2. Se va deschide pagina ANAF in browser: selectati certificatul dvs. si introduceti PIN-ul.' + CHR(13) + ;
'3. Reveniti in aplicatie - tokenul se preia automat.' + CHR(13) + CHR(13) + ;
'Continuati?', 1 + 64, _Screen.Caption) <> 1
RETURN
ENDIF
IF RIGHT(lcTokenURL, 1) <> '/'
lcTokenURL = lcTokenURL + '/'
ENDIF
* --- State anti-CSRF: 2 GUID-uri CoCreateGuid -> 64 hex (SYS(2015) e predictibil) ---
TRY
DECLARE INTEGER CoCreateGuid IN ole32 STRING @pguid
CATCH
* deja declarata in aceasta sesiune VFP
ENDTRY
lcBuf1 = REPLICATE(CHR(0), 16)
lcBuf2 = REPLICATE(CHR(0), 16)
CoCreateGuid(@lcBuf1)
CoCreateGuid(@lcBuf2)
lcBuf1 = lcBuf1 + lcBuf2 && 32 octeti aleatori = 256 biti entropie
lcHexChars = '0123456789abcdef'
lcState = ''
FOR lni = 1 TO 32
lnAscByte = ASC(SUBSTR(lcBuf1, lni, 1))
lcState = lcState + SUBSTR(lcHexChars, INT(lnAscByte/16)+1, 1) + SUBSTR(lcHexChars, MOD(lnAscByte,16)+1, 1)
ENDFOR
lcStatePrefix = LEFT(lcState, 8) && doar prefixul apare in log, niciodata tokenuri
lcBrowserUrl = lcTokenURL + '?state=' + lcState
lcPickUrl = lcTokenURL + 'pick.php'
This.Log('[' + lcStatePrefix + '] start flux automat token')
* --- Lansare browser; open_default_app (oexport.prg) intoarce .T./.F. (ShellExecute > 32) ---
IF !open_default_app(lcBrowserUrl)
AMESSAGEBOX('Nu s-a putut deschide browserul. Se continua cu fluxul manual: se va deschide pagina care afiseaza codurile pentru copiere.', 0 + 64, _Screen.Caption)
This.Log('[' + lcStatePrefix + '] esec lansare browser -> fallback manual')
open_default_app(lcTokenURL) && fara ?state -> pagina afiseaza codurile (retro-compat)
RETURN
ENDIF
* --- Polling pick.php la 2s: timeout 10 minute, Esc = anulare ---
lcExitCode = ''
lnStartSec = SECONDS()
DO WHILE .T.
lnElapsed = SECONDS() - lnStartSec
IF lnElapsed < 0
lnElapsed = lnElapsed + 86400 && trecere miezul noptii
ENDIF
IF lnElapsed >= 600
lcExitCode = 'timeout'
EXIT
ENDIF
WAIT WINDOW 'Asteptare autorizare ANAF... Continuati in fereastra browserului: selectati certificatul si introduceti PIN-ul. (Esc = anulare)' NOWAIT
lnStatus = 0
lcResponse = ''
TRY
loHTTP = CREATEOBJECT('WinHttp.WinHttpRequest.5.1')
loHTTP.SetTimeouts(5000, 5000, 5000, 5000)
loHTTP.Open('POST', lcPickUrl, .F.)
loHTTP.SetRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
loHTTP.Send('state=' + lcState)
lnStatus = loHTTP.Status
lcResponse = loHTTP.ResponseText
CATCH TO loExHTTP
* eroare retea tranzitorie -> continuam polling pana la timeout
ENDTRY
IF lnStatus = 200
loJson = NULL
TRY
loJson = nfjsonread(lcResponse)
CATCH TO loExJson
This.Log('[' + lcStatePrefix + '] eroare parsare JSON: ' + loExJson.Message)
ENDTRY
IF TYPE('loJson') = 'O' AND !ISNULL(loJson)
IF TYPE('loJson.error') <> 'U'
lcExitCode = 'anaf_error'
EXIT
ENDIF
IF TYPE('loJson.access_token') <> 'U' AND TYPE('loJson.refresh_token') <> 'U'
* Tokenuri primite - populare proprietati (fara valori de tokenuri in log)
This.cToken = loJson.access_token
This.cRefreshToken = loJson.refresh_token
This.dTokenGendate = DATE()
IF TYPE('loJson.expires_in') <> 'U'
This.dTokenExpdate = DATE() + INT(VAL(TRANSFORM(loJson.expires_in)) / 86400)
ELSE
This.dTokenExpdate = DATE() + 90
ENDIF
lcExitCode = 'success'
EXIT
ENDIF
* {"status":"pending"} sau alt continut -> continuam polling
ENDIF
ENDIF
* asteptare 2s cu verificare Esc la fiecare 0.5s
lnStep = 0
DO WHILE lnStep < 4
lnKey = INKEY(0.5)
IF lnKey = 27 && Esc
lcExitCode = 'esc'
EXIT
ENDIF
lnStep = lnStep + 1
ENDDO
IF lcExitCode = 'esc'
EXIT
ENDIF
ENDDO
WAIT CLEAR
This.Log('[' + lcStatePrefix + '] iesire: ' + lcExitCode)
DO CASE
CASE lcExitCode = 'success'
TRY
This.SaveToken()
AMESSAGEBOX('S-a generat token-ul eFactura, valabil pana la ' + DTOC(This.dTokenExpdate), 0 + 64, _Screen.Caption)
CATCH TO loExSave
* tokenul ramane in This.cToken; la reluarea operatiei va fi necesar PIN-ul din nou
AMESSAGEBOX('Tokenul a fost generat, dar salvarea in baza de date a esuat: ' + loExSave.Message + CHR(13) + ;
'Reluati operatia Token nou sau contactati suportul ROA.', 0 + 48, _Screen.Caption)
ENDTRY
CASE lcExitCode = 'esc'
AMESSAGEBOX('Ati anulat asteptarea. Daca ati introdus deja PIN-ul, autorizarea respectiva va fi ignorata; la reluare va trebui sa introduceti PIN-ul din nou.', 0 + 64, _Screen.Caption)
CASE lcExitCode = 'timeout'
AMESSAGEBOX('Nu s-a primit tokenul in 10 minute. Se deschide pagina pentru completare manuala; puteti si relua operatia Token nou.', 0 + 48, _Screen.Caption)
open_default_app(lcTokenURL)
CASE lcExitCode = 'anaf_error'
AMESSAGEBOX('Eroare la autorizarea ANAF: ' + TRANSFORM(NVL(loJson.error, '')) + '. Reluati operatia sau folositi completarea manuala (se deschide pagina care afiseaza codurile).', 0 + 48, _Screen.Caption)
open_default_app(lcTokenURL)
ENDCASE
Endfunc && newToken
* Actualizeaza data expirarii tokenului ANAF eFactura
* Se apeleaza din formularul anaf_token.do_executa
@@ -523,10 +702,11 @@ select a.*, cast(NULL as varchar2(1000)) as factura_detalii, 0 as modificat
* tcMesaj (OUT)
Local loHTTP As 'winHTTP.winHTTPrequest.5.1'
Local lcRefreshToken, lcResponse, lcURL, llSucces, loJson
llSucces = .F.
Local lcRefreshToken, lcResponse, lcURL, llSucces, loJson, loEx as Exception
llSucces = .T.
lcRefreshToken = Alltrim(This.cRefreshToken)
tcMesaj = ''
SET STEP ON
If Empty(m.lcRefreshToken)
tcMesaj = 'Completati Refresh Token'
This.Log(m.tcMesaj)
@@ -539,12 +719,21 @@ select a.*, cast(NULL as varchar2(1000)) as factura_detalii, 0 as modificat
loHTTP.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
loHTTP.Send([refresh_token=] + m.lcRefreshToken)
CATCH
loHTTP = Createobject('MSXML2.XMLHTTP.6.0')
loHTTP.Open('POST', lcURL, .F.)
loHTTP.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
loHTTP.Send([refresh_token=] + m.lcRefreshToken)
CATCH TO loEx
llSucces = .F.
ENDTRY
IF !m.llSucces OR TYPE('loHTTP') <> 'O'
TRY
loHTTP = Createobject('MSXML2.XMLHTTP.6.0')
loHTTP.Open('POST', lcURL, .F.)
loHTTP.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
loHTTP.Send([refresh_token=] + m.lcRefreshToken)
CATCH TO loEx
llSucces = .F.
AMESSAGEBOX(loEx.Message,0,_screen.Caption)
ENDTRY
ENDIF
llSucces = (TYPE('loHTTP') = 'O')
IF m.llSucces
@@ -578,7 +767,7 @@ select a.*, cast(NULL as varchar2(1000)) as factura_detalii, 0 as modificat
Endif
ELSE
tcMesaj = 'Nu s-a regenerat token-ul! Status = ' + Transform(loHTTP.Status) + CRLF + m.lcResponse
This.Log(m.tcMesaj, 0 + 48, _Screen.Caption)
This.Log(m.tcMesaj)
Endif
Endif
@@ -2154,7 +2343,7 @@ end;
ENDIF
IF m.llSucces
* Transformam raspunsul JSON <EFBFBD>ntr-un obiect FoxPro
* Transformam raspunsul JSON intr-un obiect FoxPro
TRY
loJson = nfjsonread(m.lcResponse)
CATCH TO loEx
@@ -2167,7 +2356,7 @@ end;
* Verificam daca exista mesaje disponibile
IF TYPE("loJson.mesaje") <> "U"
* Daca avem mesaje, le salvam <EFBFBD>ntr-un array
* Daca avem mesaje, le salvam intr-un array
*!* laMesaje = loJson.mesaje
*!* lnMesajeCount = ALEN(laMesaje, 1)
@@ -2697,7 +2886,10 @@ select id, id_efactura, nr, articol, descriere, detalii, cantitate, um, pret, pr
If m.tlShow Or Empty(m.lcToken) Or m.ldTokenExpDate <= Date()
loFrmToken = Createobject("anaf_token", This)
loFrmToken.Show(1)
If m.lcToken <> loServer.cToken
*!* 07.07.2026
*!* dupa fluxul automat (newToken) datele sunt deja setate corect din expires_in
*!* (dTokenGendate = azi); suprascrierea cu +90 ramane doar pentru completarea manuala
If m.lcToken <> loServer.cToken And loServer.dTokenGendate <> Date()
loServer.dTokenGendate = Date()
loServer.dTokenExpdate = Date() + 90
Endif
@@ -2719,15 +2911,23 @@ select id, id_efactura, nr, articol, descriere, detalii, cantitate, um, pret, pr
Endproc && SaveToken
*!* 07.07.2026
*!* newToken - deleaga la AnafeFacturaServer.newToken (implementare unica FR-7)
*!* pattern identic cu refreshToken: loServer = This.AnafeFacturaServer
* Intoarce tokenul de acces la ANAF (eFactura) daca este salvat sau obtine un nou token
* Se apeleaza din formularul anaf_token.do_executa
Function newToken
AMESSAGEBOX('Introduceti in calculator tokenul USB cu semnatura electronica' + Chr(13) + Chr(10) + ;
'Se va deschide pagina ANAF de generare token. Introduceti PIN-ul pentru semnatura electronica.' + Chr(13) + Chr(10) + ;
'Copiati codurile "Token" si "Refresh Token" afisate si completati-le in ROA.', 0 + 64, _Screen.Caption)
lcURL = [https://romfast.ro/oauth2/]
open_default_app(m.lcURL)
LOCAL loServer
loServer = This.AnafeFacturaServer
* Asigura cTokenUrl populat din optiunile firmei (citit de GetToken din citeste_optiune)
loServer.GetToken()
loServer.newToken()
* Propagare proprietati actualizate catre ANAFeFactura (consistent cu getToken)
This.token = loServer.cToken
This.refresh_token = loServer.cRefreshToken
This.token_gendate = loServer.dTokenGendate
This.token_expdate = loServer.dTokenExpdate
Endfunc
* Actualizeaza data expirarii tokenului ANAF eFactura

View File

@@ -299,9 +299,12 @@ Define Class oExportConfig As wwConfig
Endfunc && Report2File
************************************** INCEPUT : open_default_app
*!* 07.07.2026
*!* open_default_app - intoarce .T./.F. dupa rezultatul ShellExecute (>32 = succes)
*!* apelantii existenti care ignora rezultatul nu sunt afectati
Procedure OPEN_DEFAULT_APP
Parameters tcNumeFisier
Local lcActiune
Local lcActiune, lnResult
Declare Integer ShellExecute In shell32.Dll ;
Integer hndWin, ;
@@ -311,8 +314,9 @@ Define Class oExportConfig As wwConfig
String cDir, ;
Integer nShowWin
lcActiune = "open"
ShellExecute(0, lcActiune, tcNumeFisier, "", "", 1)
lnResult = ShellExecute(0, lcActiune, tcNumeFisier, "", "", 1)
Return (m.lnResult > 32)
Endproc && open_default_app
************************************** SFARSIT : open_default_app
************************************** INCEPUT : getExcelMask

Binary file not shown.

Binary file not shown.

Binary file not shown.