anaf efactura generare token cu citire automata token din romfast.ro
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user