#DEFINE LF CHR(10)
#DEFINE CRLF CHR(13)+CHR(10)

#DEFINE	CT_SUCCES 1
#DEFINE	CT_INSUCCES -1


*!*	12.08.2024
*!*	ParseEFactura - discount factura, discount linie
 
*!*	21.08.2024
*!*	xml2PdfAnaf - tratare Invoice / CreditNote
 
*!*	03.12.2024
*!*	AnafeFactura.RefreshToken, SaveToken apeleaza AnafeFacturaServer.RefreshToken, SaveToken
*!*	AnafeFacturaServer.RefreshToken - automat daca data expirarii este mai mare sau egala, fara sa mai apara formularul de Actualizare
*!*	 astfel incat si pe server sa se apeleze automat daca expira tokenul

*!* 07.01.2025
*!* UpdateDbFactura - corectie double byte characters la mesaj_raspuns
*!* RefreshToken - tratare eroare cu Try Catch

*!* 26.03.2025
*!* SendEfactura - uploadb2c pentru persoane fizice len(codfiscal) = 13

*!*	20.05.2025
*!*	DescarcareRaspunsuri - se afiseaza eroare daca nu sunt drepturi in spv

*!* 13.03.2026
*!* Validarea si xml2pdfanaf se fac cu serviciul autentificat cu token efactura api.anaf.ro in loc de serviciul neautentificat https://webservicesp.anaf.ro/
*!* serviciul neautentificat nu mai raspundea

*!* 28.07.2026
*!* marius.mutu
*!* vizeFactura: potrivirea cu registrul se face dupa numarul facturii ca grup complet de cifre din xnumar_act (comparat cu nract prin apartenenta, ca sa poata folosi indexul), cu rezerva pe suma egala doar pentru facturile in RON, codul fiscal normalizat pe ambele parti; diferenta ramane goala cand factura nu e in registru sau e in valuta

*********************************
* Se apeleaza din ROACONT > Borderou eFactura
* Intoarce .T. daca descarcarea zip efactura si actualizarea efactura in baza de date s-au realizat cu succes
*********************************
PROCEDURE efactura_client	
	LPARAMETERS tnZile, tlFortareRaspunsuri, tlTest

	LOCAL lnExitCode, lcHost, lcPassword, lcUser, lnIsServer, lnFortareRaspunsuri, lnZile, llSucces
	Local loAnaf As 'AnafeFacturaServer'
	Local lcErrorMessage, llFortareRaspunsuri, llServer, loEx, llTest

	lcHost = ''
	lcUser = IIF(TYPE('gcS') = 'C', m.gcS, '')
	lcPassword = ''
	llServer = .F.
	lnZile = IIF(EMPTY(m.tnZile), 60, m.tnZile)
	llFortareRaspunsuri = m.tlFortareRaspunsuri
	llTest = m.tlTest
	llSucces = .F.
		
	TRY 
		loAnaf = Createobject('AnafeFacturaServer', m.llServer, m.lcHost, m.lcuser, m.lcPassword)
		loAnaf.ltest = m.llTest
		llSucces = loAnaf.Run(m.lnZile, m.llFortareRaspunsuri)
		
		IF loAnaf.lError
			goLog.Log(loAnaf.cErrorMessage)
		ENDIF 
	CATCH TO loEx
		lnExitCode = 1
		lcErrorMessage = TTOC(DATETIME(),1) + ' Eroare: ' + TRANSFORM(loEx.ErrorNo) + ' ' + loEx.Message + ' Continut: ' + loEx.LineContents +   + ' Linia: ' + TRANSFORM(loEx.LineNo) + ' Program: ' + loEx.Procedure
		WAIT WINDOW m.lcErrorMessage NOWAIT 
		AMESSAGEBOX(m.lcErrorMessage)
		This.Log(m.lcErrorMessage)
	ENDTRY 	

	RETURN m.llSucces
ENDPROC && efactura_client

Define Class AnafeFacturaServer As Custom
	dLastRunDate1 = {} && dataora inceput pentru ultima citire a raspunsurilor
	dLastRunDate2 = {} && dataora sfarsit pentru ultima citire a raspunsurilor	
	nLastRunDays = 0 && numarul de zile pentru citirea raspunsurilor 
	nLastRunSucces = 0 && succes la ultima citire a raspunsurilor
	
	cLogFile = ''
	
	cToken = ''
	cRefreshToken = ''
	dTokenGendate = {}
	dTokenExpdate = {}
	cTokenUrl = ''

	cCodFiscal = '' && cod fiscal contribuabil fara atribut fiscal
	lTest = .F. && .T. = transmite eFactura TEST

	cResponsesPath = '' && Citire raspunsuri. Calea unde se salveaza fisierele xml primite, semnatura MFIN, pdf generat de ANAF: z:\e-factura\<an>\<luna> <an>\<furnizor>\<id_descarcare
	nDaysResponses = 60

	cSendPath = '' && cale unde sunt fisierele xml de trimis
	cSendInvalidPath = '' && calea unde se muta fisierele invalide
	cSendOkPath = '' && calea unde se muta fisierele trimise

	cSaveFurnizoriPath = '' && cale template unde se copie xml, semnatura, generare pdf in ProcesCopiere
	cSaveClientiPath = ''
	cSaveFurnizoriFile = '' && nume fisier template pentru xml, semnatura, pdf
	cSaveClientiFile = '' && nume fisier template pentru xml, semnatura, pdf	
	
	nSaveFile = 1 && 1 = se salveaza arhivele zip in calea template, 0 nu se salveaza
	nSaveAnafPdfFile  = 1 && 1 = se salveaza arhivele zip in calea template, 0 nu se salveaza
	
	cSaveLogsPath = '' && directorul unde se salveaza fisierele cu raspunsuri de la ANAF descarcate (optional)

	cServerPath = '' && directorul de pe server EFACTURA_SERVER_PATH
	cNetworkPath = '' && directorul din retea accesibil de pe clienti, daca se ruleaza din ROACONT. EFACTURA_NETWORK_PATH

	cErrorMessage = ''
	lError = .F.
	
	cDatabaseFileName = 'anaf_efactura.dbf'
	cDatabaseFilePath = ''

	lServer = .T.
	cHost = ''
	cUser = ''
	cPassword = ''

	lConnected = .F. && daca programul este deja conectat la baza de date si nu este necesar sa se conecteze/deconecteze

	lZipDatabase = .T. && daca se salveaza zip efactura in baza de date
	
	lTokenAutoRefresh = .F. && daca se actualizeaza automat tokenul cu 10 zile inainte de expirare
		
	oAnafeFactura = null
		
	Procedure Init
		Lparameters tlServer, tcHost, tcUser, tcPassword

		Local lcTest, llSucces, lcUser
		This.cErrorMessage = ''

		lcUser = tcUser
		IF TYPE('tcUser') = 'C' AND !EMPTY(m.tcUser)
			lcUser = m.tcUser
		ELSE
			lcUser = IIF(TYPE('gcS') = 'C', m.gcS, '')
		ENDIF 	

		this.lServer = m.tlServer
		This.cHost = m.tcHost
		this.cUser = m.lcUser
		this.cPassword = m.tcPassword
			
		
		* Initializare baza date
		goConn.cHost = This.cHost
		goConn.cUser = this.cUser
		goConn.cPassword = this.cPassword

		This.lConnected = This.IsConnected()
		
		This.cLogFile = goLog.cLogFile

		llSucces = This.ReadSettingsFromDb()
		
	Endproc && Init
	
	PROCEDURE Run
		LPARAMETERS tnZile, tlFortareRaspunsuri
		
		Local llSucces, lnZile, llFortareRaspunsuri
		lnZile = m.tnZile
		This.nDaysResponses = m.lnZile
		llFortareRaspunsuri = m.tlFortareRaspunsuri

		This.PreRun()
				
		llSucces = This.InitDB(m.lnZile)

		IF m.llSucces
			llSucces = This.DescarcareRaspunsuri(m.lnZile, m.llFortareRaspunsuri)
			IF !m.llSucces AND !This.lServer
				AMESSAGEBOX(This.cErrorMessage,0+48, _SCREEN.Caption)
			ENDIF 
		ENDIF

		IF m.llSucces	
			llSucces = This.ProcesareRaspunsuri(m.llFortareRaspunsuri)

		
			IF m.llSucces
				llSucces = This.UpdateDb()
				IF !m.llSucces AND !This.lServer AND !EMPTY(This.cErrorMessage)
					AMESSAGEBOX(This.cErrorMessage,0+48, _SCREEN.Caption)
				ENDIF 		

			ELSE 
				IF !m.llSucces AND !This.lServer AND !EMPTY(This.cErrorMessage)
					AMESSAGEBOX(This.cErrorMessage,0+48, _SCREEN.Caption)
				ENDIF 		
			ENDIF 
		ENDIF 	
		
		This.PostRun(m.llSucces)	
		
		RETURN m.llSucces	
	ENDPROC && Run
	
	*****************************
	PROCEDURE PreRun
	
		Local llSucces, lnHandle

		This.dLastRunDate1 = DATETIME()
		This.dLastRunDate2 = {//::}
		This.nLastRunDays = This.nDaysResponses
		This.nLastRunSucces = 0
		
		lnHandle = This.ConnectROA()
		llSucces = (m.lnHandle > 0)
		IF m.llSucces
			scrie_optiune('EFACTURA_LASTRUN_DATE1', ttoc(This.dLastRunDate1), 'Efactura data inceput cand au fost verificate raspunsurile SPV')
			scrie_optiune('EFACTURA_LASTRUN_DATE2', ttoc(This.dLastRunDate2), 'Efactura data sfarsit cand au fost verificate raspunsurile SPV')		
			scrie_optiune('EFACTURA_LASTRUN_DAYS', ALLTRIM(STR(This.nLastRunDays)), 'Efactura cate zile de raspunsuri au fost verificate ultima data')
			scrie_optiune('EFACTURA_LASTRUN_SUCCES', ALLTRIM(STR(This.nLastRunSucces)), 'Efactura succes la ultima verificare de raspunsuri SPV')	
		ENDIF 	
	
	ENDPROC && PreRun

	*****************************
	PROCEDURE PostRun
		LPARAMETERS tlSucces
		Local llSucces, lnHandle

		This.nLastRunSucces = IIF(m.llSucces, 1, 0)
		This.dLastRunDate2 = DATETIME()
		
		lnHandle = This.ConnectROA()
		llSucces = (m.lnHandle > 0)
		IF m.llSucces
			scrie_optiune('EFACTURA_LASTRUN_SUCCES', ALLTRIM(STR(This.nLastRunSucces)), 'Efactura succes la ultima verificare de raspunsuri SPV')	
			scrie_optiune('EFACTURA_LASTRUN_DATE2', ttoc(This.dLastRunDate2), 'Efactura data sfarsit cand au fost verificate raspunsurile SPV')		
			scrie_optiune('EFACTURA_LASTRUN_SUCCES', IIF(m.tlSucces, "1", "0"), 'Efactura succes la ultima verificare de raspunsuri SPV')					
		ENDIF 	
	
	ENDPROC && PostRun
		
	*******************************
	* Verifica daca programul este conectat la baza de date
	*******************************
	PROCEDURE IsConnected
		LOCAL lcSql, llSucces
		LOCAL loEx as Exception
		Local lcErrorMessage

		
		llSucces = .F.		
		lcSql = "SELECT sysdate FROM dual"
		
		TRY 
			llSucces = goExecutor.oExecuta(m.lcSql)
		CATCH TO loEx
			lcErrorMessage = TTOC(DATETIME(),1) + ' Eroare: ' + TRANSFORM(loEx.ErrorNo) + ' ' + loEx.Message + ' Continut:' + loEx.LineContents +   + ' Linia: ' + TRANSFORM(loEx.LineNo) + ' Program: ' + loEx.Procedure
			This.cErrorMessage = m.lcErrorMessage
			This.Log(m.lcErrorMessage)
		ENDTRY 
			
		RETURN m.llSucces
		
	ENDPROC && IsConnected
	
	PROCEDURE ReadSettingsFromDb
	
		Local lcSql, llSucces, lcCodFiscal
		Local lcErrorMessage, lcFirma, lcLastRunDate1, lcLastRunDate2, lcPath, lnHandle, lnSucces
		Local lnZipDatabase
		*:Global gcFirma, gnAn, gnLuna

		llSucces = .F.
		
		TEXT TO lcSql TEXTMERGE NOSHOW 
select MAX(cod_fiscal) as cod_fiscal, MAX(firma) AS firma from syn_v_nom_firme where UPPER(schema) = '<<UPPER(ALLTRIM(This.cUser))>>' AND STERS = 0 AND (E_MAMA = 1 OR (E_MAMA = 0 AND ID_MAMA IS NULL))
		ENDTEXT 

		lnHandle = This.ConnectROA()
		llSucces = (m.lnHandle > 0)
		IF m.llSucces
			lnSucces = actualizeaza_optiuni()
			llSucces = (lnSucces = CT_SUCCES)

			IF m.llSucces
				lcCodFiscal = ''
				lcFirma = ''
				llSucces = goExecutor.oExecuta(m.lcSql, "cFirmaTemp")
				IF m.llSucces
					lcCodFiscal = ALLTRIM(NVL(cFirmaTemp.cod_fiscal, ''))
					lcFirma = ALLTRIM(NVL(cFirmaTemp.firma, ''))
					This.cCodFiscal = UPPER(ALLTRIM(GetNrFromString(NVL(m.lcCodFiscal,''))))
					IF TYPE('gcFirma') = 'C' AND EMPTY(m.gcFirma)
						gcFirma = m.lcFirma
					ENDIF 
				ENDIF 			
				USE IN (SELECT('cFirmaTemp'))				
			ENDIF 
			IF m.llSucces
				IF TYPE('gnAn') = 'N' AND EMPTY(m.gnAn)
					lcSql = "SELECT AN, LUNA FROM CALENDAR WHERE AN*12 + LUNA = (SELECT MAX(AN*12+LUNA) FROM CALENDAR)"
					llSucces = goExecutor.oExecuta(m.lcSql, 'cCalendarTemp')
					IF m.llSucces
						gnAn = cCalendarTemp.an
						gnLuna = cCalendarTemp.luna
					ENDIF  
					USE IN (SELECT('cCalendarTemp'))
				ENDIF 	
			ENDIF 			
			lnSucces = This.DisconnectROA()
			llSucces = (lnSucces = CT_SUCCES)
		ENDIF 

		IF m.llSucces	
	 		This.cResponsesPath = ADDBS(ALLTRIM(NVL(citeste_optiune("EFACTURA_RESPONSESPATH"), ''))) && RASPUNSURI  && <path>\<firma>\raspunsuri\
			This.cSendPath = ADDBS(ALLTRIM(NVL(citeste_optiune("EFACTURA_SENDPATH"),''))) && FACTURI DE TRIMIS 	 && <path>\<firma>\emise\	

			This.cSaveFurnizoriPath = ADDBS(ALLTRIM(NVL(citeste_optiune("EFACTURA_SAVE_FURNIZORI_PATH"), ''))) && <path>\<firma>\furnizori\<an>\<luna> <an>\<furnizor>\<id_descarcare>
			This.cSaveFurnizoriFile = ALLTRIM(citeste_optiune("EFACTURA_SAVE_FURNIZORI_FILE")) && <id_incarcare>_<datafact>_<furnizor>
			This.cSaveClientiPath = Addbs(ALLTRIM(NVL(citeste_optiune("EFACTURA_SAVE_CLIENTI_PATH"), ''))) && <path>\<firma>\clienti\<an>\<luna> <an>\<client>\<id_descarcare>
			This.cSaveClientiFile = ALLTRIM(citeste_optiune("EFACTURA_SAVE_CLIENTI_FILE")) && <id_incarcare>_<id_descarcare>_<datafact>_<client>
			This.nSaveFile = INT(VAL(ALLTRIM(citeste_optiune("EFACTURA_SAVE")))) && 1
			This.nSaveAnafPdfFile = INT(VAL(ALLTRIM(citeste_optiune("EFACTURA_SAVE_ANAF_PDF")))) && 1
														
			This.cServerPath = ADDBS(ALLTRIM(NVL(citeste_optiune("EFACTURA_SERVER_PATH"),''))) && C:\ROA-EFACTURA\
			This.cNetworkPath = ADDBS(ALLTRIM(NVL(citeste_optiune("EFACTURA_NETWORK_PATH"),''))) && W:\
			
			lcPath = IIF(This.lServer, this.cServerPath, this.cNetworkPath)
			This.cSaveFurnizoriPath = STRTRAN(STRTRAN(This.cSaveFurnizoriPath, '<path>', m.lcPath, 1, 1, 1), '\\', '\', 1, 10, 1)
			This.cSaveClientiPath = STRTRAN(STRTRAN(This.cSaveClientiPath, '<path>', m.lcPath, 1, 1, 1), '\\', '\', 1, 10, 1)

	 		This.cResponsesPath = ADDBS(ALLTRIM(NVL(citeste_optiune("EFACTURA_RESPONSESPATH"),''))) && RASPUNSURI  && <firma>\raspunsuri\
			This.cSendPath = ADDBS(ALLTRIM(NVL(citeste_optiune("EFACTURA_SENDPATH"),''))) && FACTURI DE TRIMIS 	 && <firma>\emise\	
	
			This.cResponsesPath = STRTRAN(STRTRAN(This.cResponsesPath, '<path>', m.lcPath, 1, 1, 1), '\\', '\', 1, 10, 1)
			This.cResponsesPath = STRTRAN(This.cResponsesPath,'<firma>', UPPER(This.cUser),1,1,1)
			This.cResponsesPath = This.cResponsesPath + IIF(this.lTest, 'test\', '')
			This.cSaveLogsPath = This.cResponsesPath + 'logs\'
			
			This.cSendPath = STRTRAN(STRTRAN(This.cSendPath, '<path>', m.lcPath, 1, 1, 1), '\\', '\', 1, 10, 1)
			This.cSendPath = STRTRAN(This.cSendPath,'<firma>', UPPER(This.cUser),1,1,1)	
			This.cSendPath = This.cSendPath + IIF(this.lTest, 'test\', '')
			This.cSendInvalidPath = This.cSendPath + 'invalid\'
			This.cSendOkPath = This.cSendPath + 'ok\'

			lnZipDatabase = INT(VAL(ALLTRIM(citeste_optiune("EFACTURA_ZIP_DATABASE")))) && 1
			This.lZipDatabase = (m.lnZipDatabase = 1)

	 		lcLastRunDate1 = ALLTRIM(NVL(citeste_optiune("EFACTURA_LASTRUN_DATE1"), ''))
			This.dLastRunDate1 = Iif(!Empty(m.lcLastRunDate1), CTOT(m.lcLastRunDate1), {//::})
	 		lcLastRunDate2 = ALLTRIM(NVL(citeste_optiune("EFACTURA_LASTRUN_DATE2"), ''))
			This.dLastRunDate2 = Iif(!Empty(m.lcLastRunDate2), CTOT(m.lcLastRunDate2), {//::})			
	 		This.nLastRunDays = INT(VAL(ALLTRIM(NVL(citeste_optiune("EFACTURA_LASTRUN_DAYS"), ''))))
	 		This.nLastRunSucces = INT(VAL(ALLTRIM(NVL(citeste_optiune("EFACTURA_LASTRUN_SUCCES"), ''))))

			************
			* Actualizeaza Token automat si citeste Token din baza de date
			* This.GetToken()
			This.RefreshTokenAuto() 
		ELSE 
			lcErrorMessage = 'ReadSettingsFromDb Eroare la initializarea setarilor'
			This.cErrorMessage = m.lcErrorMessage
			This.lError = .T.
		ENDIF 
		
		This.Log('This.nSaveFile ' + TRANSFORM(This.nSaveFile) + CHR(13) + CHR(10) + ;
			'This.nSaveAnafPdfFile ' + TRANSFORM(This.nSaveAnafPdfFile ) + CHR(13) + CHR(10) + ;
			'This.cServerPath ' + ALLTRIM(This.cServerPath) + CHR(13) + CHR(10) + ;
			'This.cNetworkPath ' + ALLTRIM(This.cNetworkPath) + CHR(13) + CHR(10) + ;
			'This.cSaveFurnizoriPath ' + ALLTRIM(This.cSaveFurnizoriPath ) + CHR(13) + CHR(10) + ;
			'This.cSaveClientiPath ' + ALLTRIM(This.cSaveClientiPath ) + CHR(13) + CHR(10) + ;
			'This.cResponsesPath ' + ALLTRIM(This.cResponsesPath ) + CHR(13) + CHR(10) + ;
			'This.cSaveLogsPath ' + ALLTRIM(This.cSaveLogsPath ))		
		RETURN m.llSucces

	ENDPROC && ReadSettingsFromDb
	*********************
	* 
	*********************
	PROCEDURE InitDB
		LPARAMETERS tnZile
		* tnZile: cate zile de raspunsuri se descarca, pentru a se verifica si cu baza de date cu tnZile de raspunsuri
		LOCAL llSucces, lnZile
		lnZile = IIF(EMPTY(m.tnZile), 60, m.tnZile) + 10 && adaug 10 zile pentru precautie
		
		lnHandle = This.ConnectROA()
		llSucces = (m.lnHandle > 0)
		IF m.llSucces
			pdData2 = DATE()+1
			pdData1 = DATE() - m.lnZile
			
			TEXT TO lcSql NOSHOW 
select a.*, cast(NULL as varchar2(1000)) as factura_detalii, 0 as modificat
	from anaf_efactura a	
	where a.data_raspuns between ?pdData1 and ?pdData2
			ENDTEXT 

			llSucces = goExecutor.oExecuta(m.lcSql,"anaf_efactura")
			IF m.llSucces
				SELECT anaf_efactura
				INDEX on id_incarcare TAG id_inc
				INDEX on id_descarcare TAG id_desc
			ENDIF 
		
			lnSucces = This.DisconnectROA()
		ENDIF && lnSucces	

		RETURN m.llSucces
	ENDPROC && InitDB
	
	PROCEDURE ConnectROA
		Local lnSucces

		IF This.lConnected
			* Nu ma conectez la baza de date daca sunt deja conectat (ex: Daca se apeleaza programul din ROACONT si sunt deja conectat la baza de date)
			lnSucces = CT_SUCCES
		ELSE 
			lnSucces = IIF(goConn.Connect() > 0, CT_SUCCES, CT_INSUCCES)
		ENDIF 	
		Return lnSucces
	ENDPROC 	

	PROCEDURE DisconnectROA
		Local lnSucces

		IF This.lConnected
			lnSucces = CT_SUCCES
		ELSE 		
			lnSucces = goConn.Disconnect()
		ENDIF 	
		RETURN m.lnSucces	
	ENDPROC && DisconnectROA
	
	Procedure Log
		Lparameters tcText, tcProgram

		IF TYPE('goLog') = 'O'
			goLog.Log(tcText, tcProgram)
		ELSE 	
			lcText = Ttoc(Datetime(),3) + ' ' + IIF(!EMPTY(m.tcProgram), m.tcProgram + ' ', '') + m.tcText + CRLF
			Strtofile(m.lcText, This.cLogFile, 1)
		ENDIF 	
	Endproc && Log


	*******************************************************************
	* Actualizare automata Token
	*******************************************************************
	FUNCTION RefreshTokenAuto

		This.GetToken()
	
		IF (This.lTokenAutoRefresh AND !EMPTY(NVL(This.cToken,'')) AND !EMPTY(NVL(This.cRefreshToken, ''))) AND (This.dTokenExpdate <= DATE())
			This.RefreshToken()
		ENDIF 

		This.GetToken()
	ENDFUNC 

	************************************************************************
	Function GetToken
		Local lcRefreshToken, lcToken, lcTokenExpDate, lcTokenGenDate, ldTokenExpDate, ldTokenGenDate
			
		lnTokenAutoRefresh = INT(VAL(ALLTRIM(citeste_optiune("ANAF_TOKEN_AUTO_REFRESH")))) && 1
		This.lTokenAutoRefresh = (m.lnTokenAutoRefresh = 1)

		* TokenJWT are dimensiunea mai mare. Il salvez in optiuni.varvalue2
		lcToken = Alltrim(Nvl(citeste_optiune('ANAF_TOKEN', .T.), ''))	
		lcRefreshToken = Alltrim(Nvl(citeste_optiune('ANAF_REFRESH_TOKEN', .T.), ''))
		
		lcTokenGenDate = Alltrim(Nvl(citeste_optiune('ANAF_TOKEN_GENDATE'), ''))
		ldTokenGenDate = Iif(!Empty(m.lcTokenGenDate), Ctod(m.lcTokenGenDate), {})
		lcTokenExpDate = Alltrim(Nvl(citeste_optiune('ANAF_TOKEN_EXPDATE'), ''))
		ldTokenExpDate = Iif(!Empty(m.lcTokenExpDate), Ctod(m.lcTokenExpDate), {})
		ldTokenExpDate = Iif(!Empty(m.ldTokenExpDate), m.ldTokenExpDate, m.ldTokenGenDate + 90)
		lcTokenURL = Alltrim(Nvl(citeste_optiune('ANAF_URL_TOKEN'), ''))

		This.cToken = m.lcToken
		This.cRefreshToken = m.lcRefreshToken
		This.dTokenGendate = m.ldTokenGenDate
		This.dTokenExpdate = m.ldTokenExpDate
		This.cTokenUrl  = m.lcTokenURL

		Do Case
			Case Empty(m.lcToken)
				This.Log('Token nu este configurat.')
			Case m.ldTokenExpDate <= Date()
				This.Log('Token expirat.')
		Endcase

		Return This.cToken
	Endfunc

***************************
* Salveaza tokenul in baza de date optiuni firma
***************************
	Procedure SaveToken
		scrie_optiune('ANAF_TOKEN', This.cToken, 'ANAF Token SPV eFactura', .T.)
		scrie_optiune('ANAF_REFRESH_TOKEN', This.cRefreshToken, 'ANAF Refresh Token SPV eFactura', .T.)
		scrie_optiune('ANAF_TOKEN_GENDATE', Dtoc(This.dTokenGendate), 'ANAF Token SPV eFactura data generare')
		scrie_optiune('ANAF_TOKEN_EXPDATE', Dtoc(This.dTokenExpdate), 'ANAF Token SPV eFactura data expirare')
	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 (prin ANAFeFactura.newToken)
	Function newToken
		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

		* --- 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

		* --- 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

		lcTokenURL = ALLTRIM(NVL(This.cTokenUrl, ''))
		IF EMPTY(lcTokenURL)
			lcTokenURL = 'https://romfast.ro/oauth2/'
		ENDIF

		* --- 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
	Function refreshToken
		LPARAMETERS tcMesaj
		* tcMesaj (OUT)

		Local loHTTP As 'winHTTP.winHTTPrequest.5.1'
		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)
		Else
			lcURL = This.cTokenUrl

			TRY 
				loHTTP = Createobject('winHTTP.winHTTPrequest.5.1')
				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 
				lcResponse = loHTTP.ResponseText
				llSucces = (loHTTP.Status = 200)
			ENDIF 	
			If !m.llSucces
				lcResponse = loHTTP.StatusText
			Endif

			If m.llSucces
				TRY 
					loJson = nfjsonread(m.lcResponse)
				CATCH TO loEx
					llSucces = .F.
					tcMesaj = 'Refresh token - eroare extragere raspuns json: ' + loEx.message + CRLF + m.lcResponse
					this.Log(m.tcMesaj)
				ENDTRY 	
				If Type('loJson.expires_in') <> 'U' And Type('loJson.access_token') <> 'U' And Type('loJson.refresh_token') <> 'U'
					This.dTokenExpdate = Date() + Int(Val(Transform(loJson.expires_in)) / 24 / 3600) && 90 zile
					This.dTokenGendate = Date()
					This.cToken = loJson.access_token
					This.cRefreshToken = loJson.refresh_token

					This.SaveToken()
					tcMesaj = 'S-a regenerat token-ul, cu valabilitate pana la ' + Dtoc(This.dTokenExpdate)	
					This.Log(m.tcMesaj)
				ELSE
					tcMesaj ='Nu s-a regenerat token-ul! Generati un token nou!' + LF + m.lcResponse 
					This.Log(m.tcMesaj)
				Endif
			ELSE
				tcMesaj = 'Nu s-a regenerat token-ul! Status = ' + Transform(loHTTP.Status) + CRLF + m.lcResponse
				This.Log(m.tcMesaj)
			Endif
		Endif

		Return m.llSucces
	Endfunc


	*********************
	* Trimite fisiere xml eFactura in SPV 
	*********************
	PROCEDURE VizeFacturaXml

		CREATE CURSOR cXmlFiles (ales N(1), filepath c(250), procesat N(1), stare c(100), mesaj c(250), extern N(1))

		loXmlFiles = CREATEOBJECT("anaf_efactura_xml", This)
		loXmlFiles.Show(1)
		
		USE IN (SELECT('cXmlFiles'))
	
	ENDPROC && VizeFacturaXml
	
	********************************
	* Genereaza xml efactura, valideaza xml si trimite la API ANAF
	* parseaza un director cu xml efactura si le trimite la API ANAF
	********************************
	Procedure TrimiteFacturaXML
		LPARAMETERS tcFile, tlValidare, tlValidareOnline, tlNuTrimiteEFacturaANAF, tlExtern
		
		Local loXmlEFactura As 'ExportEFactura'
		Local lcErrorMessage, lcExecutionStatus, lcFile, lcIndexIncarcare, lcMesaj, llSucces, llValid, loEx
		Local loXML, lcMesajValidare, llExtern, lcToken
		PRIVATE pcIdIncarcare, pcMesajTrimis, pnTrimis

		LOCAL loReturn
		
		lcFile = m.tcFile
		lcMesaj = ''
		lcMesajValidare = ''		

		lcToken = This.cToken

		loReturn = Createobject("empty")
		AddProperty(loReturn, "lSucces", .F.)
		AddProperty(loReturn, "cFile", '')
		AddProperty(loReturn, "cResponse", '')
		AddProperty(loReturn, "nStatus", 0)

		llExtern = m.tlExtern
		
		llValid = .T.	
		IF m.tlValidare
			llSilentios = .T.
			loXmlEFactura = CREATEOBJECT('ExportEFactura', m.llSilentios, m.lcToken)
			llValid = loXmlEFactura.ValidareEFactura(m.lcFile, @lcMesajValidare, m.tlValidareOnline)		
		ENDIF 
				
		IF m.llValid AND !m.tlNuTrimiteEFacturaANAF
			loReturn = This.SendEfactura(m.lcFile, m.llExtern)
			llSucces = loReturn.lSucces
			AddProperty(loReturn, "cIdIncarcare", '')		
			AddProperty(loReturn, "cMesaj", '')					
					
			If m.llSucces
				pcMesajTrimis = Iif(This.lTest, 'TEST ', '')
				loXML = Null
				Try
					loXML = nfxmlread(loReturn.cResponse)
				Catch To loEx
					lcErrorMessage = loEx.Message
				Endtry

				lcExecutionStatus = ''
				lcIndexIncarcare = ''
				lcErrorMessage = ''
				If Type('loxml.header._attr_.executionstatus') <> 'U'
					lcExecutionStatus = loXML.Header._attr_.executionstatus
				Endif
				If Type('loxml.header._attr_.index__incarcare') <> 'U'
					lcIndexIncarcare = loXML.Header._attr_.index__incarcare
				Endif
				If Type('loxml.header.errors._attr_.errorMessage') <> 'U'
					lcErrorMessage = loXML.Header.errors._attr_.ErrorMessage
				Endif

				Do Case
					Case lcExecutionStatus = "0"
						pcIdIncarcare = m.lcIndexIncarcare
						pnTrimis = 1
						pcMesajTrimis =  m.pcMesajTrimis + 'Transmis cu succes. Index incarcare = ' + m.pcIdIncarcare
						loReturn.cIdIncarcare = m.pcIdIncarcare
						loReturn.lSucces = .T.	
						
					Case !Empty(m.lcErrorMessage)
						pcIdIncarcare = ''
						pnTrimis = 1
						pcMesajTrimis =  m.pcMesajTrimis + Iif(This.lTest, 'TEST ', '') + 'Eroare. ' + m.lcErrorMessage

					Case [VALID] $ Upper(loReturn.cResponse)
						pcIdIncarcare = ''
						pnTrimis = 0
						pcMesajTrimis =  m.pcMesajTrimis + loReturn.cResponse

					Otherwise
						pcMesajTrimis = m.pcMesajTrimis + Iif(This.lTest, 'TEST ', '') + 'Eroare. ' + m.lcErrorMessage
						pcIdIncarcare = ''
						pnTrimis = 1
				Endcase

				loReturn.cMesaj = m.pcMesajTrimis + ' ' + m.lcMesajValidare
			Else
				pcMesajTrimis = ' Eroare transmitere - Http Status: ' + Transform(loReturn.nStatus) + ' Http Response: ' + Alltrim(Transform(loReturn.cResponse)) + ' ' + loReturn.cResponse
				loReturn.cResponse = pcMesajTrimis
				loReturn.cMesaj = m.pcMesajTrimis + ' ' + m.lcMesajValidare
				This.Log(loReturn.cResponse)
			ENDIF
		ELSE 
			AddProperty(loReturn, "cIdIncarcare", '')		
			AddProperty(loReturn, "cMesaj", '')	
					
			pcMesajTrimis = '. Nu s-a trimis fisierul la ANAF.'
			loReturn.cResponse = m.pcMesajTrimis
			
			IF m.llValid 
				loReturn.cMesaj = 'Nu s-a trimis fisierul. ' + m.lcMesajValidare
				loReturn.lSucces = .T.	
				llSucces = .T.
			ELSE 
				loReturn.cMesaj = 'Eroare validare. Nu s-a trimis fisierul: ' + m.lcMesajValidare
				loReturn.lSucces = .F.	
				llSucces = .F.	
			ENDIF 	
		ENDIF 				
		
		RETURN loReturn
		
	Endproc && TrimiteFacturaXML

* Genereaza xml eFactura, valideaza xml si trimite la ANAF
	Function SendEfactura
		Lparameters tcFile, tlExtern, tlMesaj
		* tcFile: calea catre fisierul xml efactura / sau xml mesaj
		* tlExtern: daca se apeleaza cu parametrul Extern=DA (pentru clientii externi)
		* tlMesaj: daca mesajul este o factura sau un mesaj catre furnizor

		Local loEx As Exception
		Local loHTTP As 'winHTTP.winHTTPrequest.5.1'
		Local loReturn As "empty"
		Local lcCodFiscal, lcExtern, lcFile, lcSend, lcServer, lcToken, llOk, llTest, llB2C
		LOCAL lcCustomer, lcPartyLegal, lcCodFiscalClient

		loReturn = Createobject("empty")
		AddProperty(loReturn, "lSucces", .F.)
		AddProperty(loReturn, "cFile", '')
		AddProperty(loReturn, "cResponse", '')
		AddProperty(loReturn, "nStatus", 0)

		lcToken = This.cToken
		lcCodFiscal = ALLTRIM(This.cCodFiscal)
		llTest = This.lTest
		llOk = .F.
		lcFile = ''

		lcFile = Iif(Type('tcFile') = 'C' and !Empty(m.tcFile), m.tcFile, '')
		loReturn.cFile = m.lcFile
		lcExtern = Iif(m.tlExtern, '&extern=DA', '')
		This.Log('SendEFactura: ' + m.lcFile)
		If File(m.lcFile)
			lcSend = Filetostr(m.lcFile)

			* Verific daca clientul este persoana fizica si folosesc upload2bc in loc de upload
			lcCustomer = STREXTRACT(lcSend, '<cac:AccountingCustomerParty>', '</cac:AccountingCustomerParty>',1,1)
			lcPartyLegal = STREXTRACT(lcCustomer, '<cac:PartyLegalEntity>', '</cac:PartyLegalEntity>',1,1)
			lcCodFiscalClient = ALLTRIM(STREXTRACT(m.lcPartyLegal, '<cbc:CompanyID>','</cbc:CompanyID>',1,1))	
			llB2C = (LEN(m.lcCodFiscalClient) = 13) && persoane fizice	
	
			TRY 
				IF !m.tlMesaj
					lcServer = [https://api.anaf.ro/] + Iif(m.llTest, [test], [prod]) + [/FCTEL/rest/upload] + IIF(m.llB2C,'b2c','') + [?standard=UBL&cif=] + m.lcCodFiscal + m.lcExtern
				ELSE
					lcServer = [https://api.anaf.ro/] + Iif(m.llTest, [test], [prod]) + [/FCTEL/rest/upload] + IIF(m.llB2C,'b2c','') + [?standard=RASP&cif=] + m.lcCodFiscal
				ENDIF 	
				
				loHTTP = Createobject('winHTTP.winHTTPrequest.5.1')
				loHTTP.Open('POST', lcServer, .F.)
				loHTTP.setRequestHeader("Content-Type", "application/xml;")
				loHTTP.setRequestHeader('Authorization', 'Bearer ' + m.lcToken) && 9b1f44af738c16aa10c78347b9a064857f034b03a20704a03c131b99f019cee5
				poLog.Log(m.lcServer)

				loHTTP.Send(m.lcSend)

				loReturn.nStatus = loHTTP.Status
				loReturn.cResponse = loHTTP.ResponseText
				loReturn.lSucces = (loHTTP.Status = 200)

			CATCH TO loEx
				loReturn.lSucces = .F.
				loReturn.cResponse = '<errorMessage="' + loEx.message + '">'
			ENDTRY 	
		Else
			loReturn.cResponse = '<errorMessage="Nu exista fisierul' + m.lcFile + '">'
			loReturn.lSucces = .F.
		ENDIF
		
		This.Log('SendEFactura: ' + Transform(loReturn.nStatus) + ' ' + Transform(loReturn.lSucces) + ' ' + loReturn.cResponse)
		Return loReturn
	Endfunc

	* Genereaza xml mesaj catre furnizor si trimite la ANAF
	Function SendMesaj
		Lparameters tnIdIncarcare, tcMesaj

		LOCAL lnIdIncarcare, lcMesaj, llMesaj, loReturn, lcFile
		lcFile = ADDBS(SYS(2023)) + FORCEEXT(SYS(2015), 'xml')
		llMesaj = .T.
		lcMesaj = Alltrim(XmlSpecialCharacters(RemoveCharacters(m.tcMesaj, .T.)))
		lnIdIncarcare = ALLTRIM(NVL(m.tnIdIncarcare,''))
		
TEXT TO lcText TEXTMERGE NOSHOW 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<header xmlns="mfp:anaf:dgti:spv:reqMesaj:v1" index_incarcare="<<m.lnIdIncarcare>>" message="<<m.lcMesaj>>"/>
ENDTEXT 
	STRTOFILE(m.lcText, m.lcFile)
	
		loReturn = This.SendEFactura(m.lcFile,,m.llMesaj)
		IF FILE(m.lcFile)
			DELETE FILE (m.lcFile)
		ENDIF 
		RETURN loReturn
	ENDFUNC
	
	*************************
	* Dezarhiveaza o arhiva si intoarce .T./.F.
	*************************
	Procedure UnzipFile
		Lparameters tcZipFile, tcDir, tcErrorMessage
		* tcZipFile: arhiva zip cu detaliile raspunsului unei eFactura
		* tcDir: IN/OUT directorul cu fisierele dezarhivate
		* tcErrorMessage: OUT mesaj de eroare

		Local laZipTemp[1, 3], lcDir, lcFileName, llSucces, llSilent
		tcErrorMessage = ''
		llSilent = .T.

		IF TYPE('tcDir') <> 'C' OR EMPTY(NVL(m.tcDir, ''))
			tcDir = ADDBS(JUSTPATH(m.tcZipFile))
		ENDIF 	

		This.Log('UnzipFile ' + m.tcZipFile)
		llSucces = MyUnzip(m.tcZipFile, @tcDir, @tcErrorMessage, m.llSilent)

		Return m.llSucces
	ENDPROC && UnzipFile	
		
	*********************************
	* Proces ProcesCopiere: copiez arhiva zip intr-o structura de directoare, dezarhivez, transform xml in pdf
	*********************************
	PROCEDURE ProcesareRaspunsuri
		LPARAMETERS tlFortareRaspunsuri
		
		Local lcDir, lcDir2, lcErrorMessage, lcFile, lcFile2, lcFile2Semnatura, lcFilePdf, lcFileSemnatura
		Local lcIdDescarcare, lcIdIncarcare, lcTipRaspuns, lcZipFile, llSucces, loEx, loFactura, llFortareRaspunsuri
		
		llFortareRaspunsuri = m.tlFortareRaspunsuri
		
		This.Log('Procesare Raspunsuri')

		* procesez server si nu este descarcat sau client (borderou eFactura ROACONT) si nu este procesat (completat detalii)
		SELECT id_incarcare, id_descarcare, tip_mesaj_raspuns, filepath, procesat ;
			FROM anaf_efactura WITH (BUFFERING = .T.) ;
			WHERE ((This.lServer AND (procesat_server = 0 OR procesat = 0)) OR (!This.lServer AND (procesat = 0 OR modificat = 1))) AND ;
			!EMPTY(NVL(filepath,'')) ;
			ORDER BY id_incarcare ;
			INTO CURSOR cRaspunsuriTemp
		
		This.Log('Procesare Raspunsuri ' + ALLTRIM(STR(RECCOUNT('cRaspunsuriTemp'))) + ' fisiere de procesat')

		llSucces = .T.
		SELECT cRaspunsuriTemp
		SCAN
			lcIdIncarcare = ALLTRIM(id_incarcare)
			lcIdDescarcare = ALLTRIM(id_descarcare)
			lcZipFile = ALLTRIM(filepath)
			lcTipRaspuns = UPPER(ALLTRIM(tip_mesaj_raspuns))
			
			lcText = 'ProcesareRaspunsuri ' + ALLTRIM(STR(RECNO())) + '/' + ALLTRIM(STR(RECCOUNT()))
			WAIT WINDOW m.lcText NOWAIT 
			This.Log(m.lcText)
			
			IF FILE(m.lcZipFile)
				lcDir = ''		
				lcErrorMessage = ''

				llSucces = This.UnzipFile(m.lcZipFile, @lcDir, @lcErrorMessage)

				IF !m.llSucces 
					lcErrorMessage = 'ProcesareRaspunsuri Eroare dezarhivare detalii factura id_incarcare = ' + Alltrim(m.lcIdIncarcare) + '. ' + m.lcErrorMessage
					This.cErrorMessage = m.lcErrorMessage
					This.lError = .T.
					WAIT WINDOW m.lcErrorMessage NOWAIT 
					This.Log(m.lcErrorMessage)
				ELSE 	
					TRY
						lcFile = Addbs(m.lcDir) + m.lcIdIncarcare + '.xml'
						lcFileSemnatura = Addbs(m.lcDir) + 'semnatura_' + m.lcIdIncarcare + '.xml'

						* Completez xml dezarhivat in anaf_efactura
						lcDetalii = FILETOSTR(m.lcFile)
						
						llSucces = This.cUpdateDetalii(m.lcIdIncarcare, m.lcDetalii)

						IF !m.llSucces 
							lcErrorMessage = 'ProcesareRaspunsuri Eroare actualizare detalii id_incarcare ' + m.lcIdIncarcare
							This.cErrorMessage = m.lcErrorMessage
							This.lError = .T.
							WAIT WINDOW m.lcErrorMessage NOWAIT 
							This.Log(m.lcErrorMessage)							
						ENDIF 
									
						* Parsez doar FATURA PRIMITA/FACTURA TRIMISA
						IF Inlist(m.lcTipRaspuns, 'FACTURA PRIMITA', 'FACTURA TRIMISA') AND FILE(m.lcFile)
							loFactura = ParseEFactura(m.lcFile)
					
							ADDPROPERTY(loFactura, 'cIdIncarcare', m.lcIdIncarcare)
							ADDPROPERTY(loFactura, 'cIdDescarcare', m.lcIdDescarcare)							
							ADDPROPERTY(loFactura, 'tip_mesaj_raspuns', m.lcTipRaspuns)

							llSucces = This.cUpdateFactura(loFactura)

							* Pe server, copiez arhiva zip, generez pdf in structura directoare custom
							IF (This.nSaveFile = 1) AND ((This.lServer AND !EMPTY(NVL(This.cServerPath,''))) OR (!This.lServer AND !EMPTY(NVL(This.cNetworkPath,''))))
								lcFile2 = This.GetFacturaSavePath(loFactura, 'zip')
								lcDir2 = ADDBS(JUSTPATH(m.lcFile2))
								lcFilePdf = m.lcDir2 + Juststem(m.lcFile2) + '.pdf'
								If !File(m.lcFile2)
									llSucces = This.SaveFile(m.lcZipFile, .F., m.lcDir2, JUSTFNAME(m.lcFile2))
								ENDIF 
								IF (this.nSaveAnafPdfFile = 1) AND !FILE(m.lcFilePdf)	
									lcFilePdf = This.xml2PdfAnaf(m.lcFile, m.lcFilePdf)
								ENDIF 	

								This.cUpdateProcesatServer(m.lcIdIncarcare)
							ELSE 	
								* Marchez procesat server si daca nu trece prin procesul de procesare, pentru ca altfel il procesez din nou si urmatoarea data (dezarhivare, copiere)
								This.cUpdateProcesatServer(m.lcIdIncarcare)
							ENDIF 	 && This.nSaveFile = 1
						ENDIF && lcTipRaspuns	

						DELETE FILE(m.lcFile)
						DELETE FILE(m.lcFileSemnatura)						

					Catch To loEx
						llSucces = .F.						
						
						lcErrorMessage = 'ProcesareRaspunsuri Eroare la salvarea datelor extrase din xml eFactura. ' + 'Eroare: ' + TRANSFORM(loEx.ErrorNo) + ' ' + loEx.Message + ' Continut:' + loEx.LineContents +   + ' Linia: ' + TRANSFORM(loEx.LineNo) + ' Program: ' + loEx.Procedure
						This.cErrorMessage = m.lcErrorMessage
						This.lError = .T.
						WAIT WINDOW m.lcErrorMessage NOWAIT 
						This.Log(m.lcErrorMessage)
					ENDTRY
				ENDIF 
			ENDIF 					
		ENDSCAN && cRaspunsuriTemp
		
		USE IN (SELECT('cRaspunsuriTemp'))
		
		RETURN m.llSucces	
	ENDPROC && ProcesareRaspunsuri
	*********************************
	*!* 24.07.2026 marius.mutu - import manual arhiva zip eFactura descarcata din SPV
	*********************************
	PROCEDURE ImportZipLocal
		LPARAMETERS tcZipFile
		* tcZipFile: (optional) arhiva zip descarcata din SPV. Daca lipseste, se alege cu Getfile

		Local laFiles[1], lcCodFiscalClient, lcCodFiscalFurnizor, lcDir, lcErrorMessage, lcFilePath
		Local lcId, lcSemnatura, lcTip, lcXmlFile, lcZipFile, llSucces, lnFile, lnFiles, loFactura

		lcZipFile = IIF(TYPE('tcZipFile') = 'C' AND !EMPTY(NVL(m.tcZipFile, '')), ALLTRIM(m.tcZipFile), GETFILE('zip', 'Arhiva zip eFactura', 'Import'))
		IF EMPTY(m.lcZipFile) OR !FILE(m.lcZipFile)
			RETURN .F.
		ENDIF

		lcDir = ADDBS(SYS(2023)) + SYS(2015) + '\'
		lcErrorMessage = ''
		llSucces = This.UnzipFile(m.lcZipFile, @lcDir, @lcErrorMessage)

		IF !m.llSucces
			AMESSAGEBOX('Eroare la dezarhivarea ' + m.lcZipFile + CHR(13) + CHR(10) + m.lcErrorMessage, 0+48, _SCREEN.Caption)
			RETURN .F.
		ENDIF

		* xml-ul facturii este fisierul xml care nu este semnatura MFinante
		lcXmlFile = ''
		lnFiles = ADIR(laFiles, ADDBS(m.lcDir) + '*.xml')
		FOR lnFile = 1 TO m.lnFiles
			IF !('SEMNATURA' $ UPPER(laFiles[m.lnFile, 1]))
				lcXmlFile = ADDBS(m.lcDir) + ALLTRIM(laFiles[m.lnFile, 1])
				EXIT
			ENDIF
		ENDFOR

		IF EMPTY(m.lcXmlFile)
			AMESSAGEBOX('Arhiva nu contine fisierul xml al facturii!', 0+48, _SCREEN.Caption)
			RETURN .F.
		ENDIF

		lcId = ALLTRIM(JUSTSTEM(m.lcXmlFile))
		loFactura = ParseEFactura(m.lcXmlFile)

		IF TYPE('loFactura') <> 'O' OR loFactura.Eroare
			AMESSAGEBOX('Eroare la citirea facturii din ' + m.lcXmlFile, 0+48, _SCREEN.Caption)
			RETURN .F.
		ENDIF

		lcCodFiscalFurnizor = UPPER(ALLTRIM(GetNrFromString(NVL(loFactura.CodFiscalFurnizor, ''))))
		lcCodFiscalClient = UPPER(ALLTRIM(GetNrFromString(NVL(loFactura.CodFiscalClient, ''))))

		DO CASE
			CASE !EMPTY(m.lcCodFiscalClient) AND m.lcCodFiscalClient == ALLTRIM(This.cCodFiscal)
				lcTip = 'FACTURA PRIMITA'
			CASE !EMPTY(m.lcCodFiscalFurnizor) AND m.lcCodFiscalFurnizor == ALLTRIM(This.cCodFiscal)
				lcTip = 'FACTURA TRIMISA'
			OTHERWISE
				AMESSAGEBOX('Factura nu apartine firmei curente (cod fiscal ' + ALLTRIM(This.cCodFiscal) + ')!' + CHR(13) + CHR(10) + ;
					'Emitent: ' + m.lcCodFiscalFurnizor + '  Beneficiar: ' + m.lcCodFiscalClient, 0+48, _SCREEN.Caption)
				RETURN .F.
		ENDCASE

		* Salvez arhiva in directorul local de raspunsuri, ca la descarcarea din SPV
		lcFilePath = GetPdfPath('EFACTURA', IIF(m.lcTip == 'FACTURA PRIMITA', 'PRIMITE', 'TRIMISE')) + m.lcId + '_' + m.lcId + '.zip'
		IF !FILE(m.lcFilePath)
			This.SaveFile(m.lcZipFile, .F., JUSTPATH(m.lcFilePath), JUSTFNAME(m.lcFilePath))
		ENDIF

		* Cursor temporar cu structura din InitDB, cu factura importata
		llSucces = goExecutor.oExecuta("select a.*, cast(NULL as varchar2(1000)) as factura_detalii, 0 as modificat from anaf_efactura a where 1 = 0", "canaf_efactura_temp")

		IF !m.llSucces
			AMESSAGEBOX('Eroare la citirea structurii anaf_efactura!', 0+48, _SCREEN.Caption)
			RETURN .F.
		ENDIF

		INSERT INTO canaf_efactura_temp (id_incarcare, id_descarcare, data_raspuns, mesaj_raspuns, tip_mesaj_raspuns, ;
				cod_fiscal_emitent, cod_fiscal_beneficiar, factura_emisa, test, descarcat, filepath, detalii, modificat) ;
			VALUES (m.lcId, m.lcId, DATETIME(), 'Import manual ' + JUSTFNAME(m.lcZipFile), m.lcTip, ;
				m.lcCodFiscalFurnizor, m.lcCodFiscalClient, IIF(m.lcTip == 'FACTURA PRIMITA', 0, 1), IIF(This.lTest, 1, 0), ;
				0, m.lcFilePath, FILETOSTR(m.lcXmlFile), 1)

		TABLEUPDATE(1, .F., 'canaf_efactura_temp')

		ADDPROPERTY(loFactura, 'cIdIncarcare', m.lcId)
		This.cUpdateFactura(loFactura, 'canaf_efactura_temp')

		llSucces = This.UpdateDb('canaf_efactura_temp')

		USE IN (SELECT('canaf_efactura_temp'))

		lcSemnatura = ADDBS(m.lcDir) + 'semnatura_' + m.lcId + '.xml'
		DELETE FILE (m.lcXmlFile)
		IF FILE(m.lcSemnatura)
			DELETE FILE (m.lcSemnatura)
		ENDIF

		IF m.llSucces
			AMESSAGEBOX('Factura ' + ALLTRIM(loFactura.NumarAct) + ' din ' + DTOC(loFactura.DataAct) + ' a fost importata in borderoul eFactura!', 0+64, _SCREEN.Caption)
		ENDIF

		RETURN m.llSucces
	ENDPROC && ImportZipLocal

	
	*********************************
	* RASPUNSURI FACTURI
	* Trebuie sa descarc ERORI FACTURI TRIMISE si FACTURI PRIMITE si sa citesc detalii (mesaj eroare, numar, data factura, detalii factura furnizor)
	* Citesc lista de raspunsuri ANAF
	* Descarc detaliile fiecarui raspuns neprocesat
	* Salvez arhiva zip detalii in directorul zilei curente
	*********************************
	Procedure DescarcareRaspunsuri
		Lparameters tnZile, tlFortareRaspunsuri
* tnZile : Cate zile de raspunsuri de la ANAF
* tlFortareRaspunsuri: .T. = se proceseaza si mesajele + detaliile deja salvate si procesate, default .F.

		Local lcFile2, lcSelect, llSucces, lnMesaj, lnMesaje, lnRecno, lnZile, loAnafMesaj, loEx, loJson
		Local loReturn, loMesaj, lnFortareRaspunsuri, loEx As Exception

		llFortareRaspunsuri = Iif(Type('tlFortareRaspunsuri') = 'L', m.tlFortareRaspunsuri, .F.)

		lcSelect = Select()
		llSucces = .F.

		*************************************************
		Local loHTTP As 'winHTTP.winHTTPrequest.5.1'
		Local loReturn As "empty"
		Local lcServer, llTest, lcToken, lcCodFiscal, lnZile, lcText

		llTest = This.lTest
		lcToken = This.cToken
		lcCodFiscal = This.cCodfiscal
		lnZile = Iif(!Empty(m.tnZile), Min(m.tnZile, 60), 60)

		ltEndTime =  GetUtcTime(DATETIME()-60) && 60 de secunde in urma, ca sa fiu sigur? ca ceasul calculatorului nu este inainte fata de timpul serverului ANAF. Poate fi si cu mai mult de 1 minut
		ltStartTime = ltEndTime - m.lnZile*24*60*60

		lcStartTime = ALLTRIM(STR(Datetime2UnixTime(m.ltStartTime))) + '000'
		lcEndTime = ALLTRIM(STR(Datetime2UnixTime(m.ltEndTime))) + '000'

		loHTTP = Createobject('winHTTP.winHTTPrequest.5.1')

		lnPagina = 1
		lnNumarTotalPagini = 99999

		DO WHILE m.lnPagina <= m.lnNumarTotalPagini
			TEXT TO lcServer TEXTMERGE NOSHOW 
https://api.anaf.ro/<<Iif(m.llTest, [test], [prod])>>/FCTEL/rest/listaMesajePaginatieFactura?startTime=<<lcStartTime>>&endTime=<<lcEndTime>>&cif=<<lcCodFiscal>>&pagina=<<lnPagina>>
			ENDTEXT 
			
			lcText = 'Descarcare Raspunsuri ultimele ' + TRANSFORM(m.lnZile) + ' zile : ' + TTOC(m.ltStartTime,3) + '-' + TTOC(m.ltEndTime,3)
			WAIT WINDOW m.lcText NOWAIT 
			This.Log(m.lcText + ' ' + m.lcServer)

			loHTTP.Open('GET', lcServer, .F.)
			loHTTP.setRequestHeader("Content-Type", "application/xml;")
			loHTTP.setRequestHeader('Authorization', 'Bearer ' + m.lcToken)
			loHTTP.Send()

			llSucces = (loHttp.Status = 200)
			IF !m.llSucces 
				lcErrorMessage = This.cUser + ' ' + 'DescarcareRaspunsuri Eroare la citirea raspunsurilor! Solutii: 1. Reincercati operatia cu o perioada mai mica. 2. Actualizati/Regenerati token-ul de acces daca este expirat.' + LF + loHTTP.ResponseText
				This.cErrorMessage = m.lcErrorMessage
				This.lError = .T.
				This.Log(m.lcErrorMessage)
				EXIT 
			ENDIF 
			
			llSucces = This.SaveFile(loHttp.ResponseText, .T.,This.cSaveLogsPath,'response_json_' + TTOC(Datetime(),1) + '.txt')
		
			TRY 
				loJson = nfjsonread(loHTTP.ResponseText)
			CATCH TO loEx
				llSucces = .F.
				lcErrorMessage = This.cUser + ' ' + 'DescarcareRaspunsuri ' + LF + ' Eroare: ' + TRANSFORM(loEx.ErrorNo) + ' ' + loEx.Message + ' Continut:' + loEx.LineContents +   + ' Linia: ' + TRANSFORM(loEx.LineNo) + ' Program: ' + loEx.Procedure
				This.cErrorMessage = m.lcErrorMessage
				This.lError = .T.
				This.Log(m.lcErrorMessage)
			ENDTRY 	
			
			IF TYPE('loJson') <> 'O'
				llSucces = .F.
				lcErrorMessage = This.cUser + ' ' + 'DescarcareRaspunsuri ' + LF + ' Eroare: ' + TRANSFORM(loEx.ErrorNo) + ' ' + loEx.Message + ' Continut:' + loEx.LineContents +   + ' Linia: ' + TRANSFORM(loEx.LineNo) + ' Program: ' + loEx.Procedure
				This.cErrorMessage = m.lcErrorMessage
				This.lError = .T.
				This.Log(m.lcErrorMessage)
				EXIT 
			ENDIF 
			
			If Type('loJson.numar_total_pagini') = 'N'
				lnNumarTotalPagini = loJson.numar_total_pagini			
			ENDIF 	
			
			If Type('loJson.eroare') = 'C' And !Empty(loJson.eroare)
				llSucces = .F.
				lcErrorMessage = This.cUser + LF + loJson.eroare
				This.cErrorMessage = m.lcErrorMessage + ;
					IIF(ATC('Nu exista mesaje in intervalul selectat', loJson.eroare) > 0,  '', ;
					LF + 'Posibile cauze/solutii: Token expirat (regenerati tokenul), semnatura electronica expirata (reinnoiti semnatura in SPV)' + ;
					LF + ;
					LF + 'Apasati pe butonul Chatbot (stanga) pentru alte solutii!')
				This.lError = .T.
				This.Log(m.lcErrorMessage)
				EXIT 
			ENDIF
			
			If Type('loJson.mesaje') = 'U'
				llSucces = .F.
				lcErrorMessage = This.cUser + ' ' + 'DescarcareRaspunsuri Eroare: Nu exista informatia [mesaje] in raspuns.' + LF + loHttp.ResponseText
				This.cErrorMessage = m.lcErrorMessage
				This.lError = .T.
				This.Log(m.lcErrorMessage)
				EXIT 
			ENDIF

			lnMesaje = Alen(loJson.mesaje)
			For lnMesaj = 1 To m.lnMesaje
				lcText = This.cUser + ' ' + 'DescarcareRaspunsuri Raspuns ' + Alltrim(Str(m.lnMesaj)) + '/' + Alltrim(Str(m.lnMesaje))
				WAIT WINDOW m.lcText NOWAIT 
				This.Log(m.lcText)

				loMesaj = loJson.mesaje[m.lnMesaj]
				AddProperty(loMesaj, 'recno', m.lnMesaj)
				AddProperty(loMesaj, 'recc', m.lnMesaje)

				lcIdIncarcare = IIF(Type('loMesaj.id_solicitare') = 'C' And !Empty(Nvl(loMesaj.id_solicitare, '')), loMesaj.id_solicitare, '')
				IF !EMPTY(m.lcIdIncarcare)
					* Nu procesez mesajele deja descarcate, decat daca fortez procesarea tuturor mesajelor
					IF m.llFortareRaspunsuri OR (This.lServer AND !This.cIsDescarcat(m.lcIdIncarcare)) OR (!This.lServer AND !This.cIsProcesat(m.lcIdIncarcare))
						loAnafMesaj = This.ProceseazaMesaj(loMesaj)
						llSucces = !loAnafMesaj.lEroare
						IF loAnafMesaj.lEroare
							This.lError = .T.
							This.cErrorMessage = loAnafMesaj.cEroare
						ENDIF 	
					ENDIF
				ELSE 
					llSucces = .F.
					lcErrorMessage = This.cUser + ' ' + 'DescarcareRaspunsuri Eroare: EMPTY(loMesaj.id_solicitare) Mesaj ' + Alltrim(Str(m.lnMesaj)) + '/' + Alltrim(Str(m.lnMesaje))
					This.cErrorMessage = m.lcErrorMessage
					This.lError = .T.
					This.Log(m.lcErrorMessage)
					EXIT 					
				ENDIF && empty	
			Endfor && lnMesaj
			
			lnPagina = m.lnPagina + 1
		ENDDO && .T.		
	
		Select (m.lcSelect)
		Return m.llSucces
	Endproc && DescarcareRaspunsuri

*****************************
* Dezarhiveaza mesajul, parseaza xml efactura trimisa/primita si salveaza pe disk si in baza de date
* Intoarce un obiect AnafMesaj (cEroare, lEroare)
****************************
	Procedure ProceseazaMesaj
		Lparameters toMesaj

		Local loDate As "empty"
		Local lcDirectory, lcFile, lcTip, lcTipRaspuns, llSucces, lnAn, lnLuna, lnMin, lnOra, lnSec, lnZi
		Local loAnafMesaj, loDetalii, lcFilePath

		loAnafMesaj = This.NewMesaj()

		With toMesaj
			loAnafMesaj.cIdIncarcare = .id_solicitare

			lnAn = Val(Substr(.data_creare, 1, 4))
			lnLuna = Val(Substr(.data_creare, 5, 2))
			lnZi = Val(Substr(.data_creare, 7, 2))
			lnOra = Val(Substr(.data_creare, 9, 2))
			lnMin = Val(Substr(.data_creare, 11, 2))
			lnSec = Val(Substr(.data_creare, 13, 2))
			loAnafMesaj.dDataRaspuns = Datetime(m.lnAn, m.lnLuna, m.lnZi, m.lnOra, m.lnMin, m.lnSec)

			loAnafMesaj.cMesajRaspuns = .detalii
			loAnafMesaj.cTipMesajRaspuns = .tip
			loAnafMesaj.cIdDescarcare = .Id
			loAnafMesaj.cCodFiscalEmitent = Strextract(.detalii, [cif_emitent=], [ ],1,1+2)
			loAnafMesaj.cCodFiscalBeneficiar = Strextract(.detalii, [cif_beneficiar=], [ ],1,1+2)
			loAnafMesaj.nTest = Iif(This.lTest, 1, 0) && server TEST ANAF
			loAnafMesaj.nFacturaEmisa = IIF(UPPER(ALLTRIM(.tip)) = 'FACTURA PRIMITA', 0, 1)

			lcTipRaspuns = Alltrim(Upper(loAnafMesaj.cTipMesajRaspuns))


			* Adaug mesajul in cRaspunsuri
			This.cAddMesaj(loAnafMesaj)


			lcTip = Iif('ERORI'$m.lcTipRaspuns, 'ERORI', Iif('PRIMIT'$m.lcTipRaspuns, 'PRIMITE', Iif('TRIMIS'$m.lcTipRaspuns, 'TRIMISE', IIF('MESAJ CUMPARATOR TRANSMIS'$m.lcTipRaspuns, 'MESAJE', 'ALTELE'))))
			lcFile = loAnafMesaj.cIdIncarcare + '_' + loAnafMesaj.cIdDescarcare + '.zip' && C:\EFACTURA\PRIMITE\20240112\1234_1234\

			IF this.lServer
				lcDirectory = This.cResponsesPath + m.lcTip + '\' + Dtos(Date()) + '\'
			ELSE
				lcDirectory = GetPdfPath('EFACTURA', m.lcTip)
			ENDIF 	

			lcFilePath = m.lcDirectory + m.lcFile
			
			* Daca nu exista fisierul zip descarcat de alt program
			IF !FILE(m.lcFilePath)
				* Descarca detalii raspuns
				loDetalii = This.DownloadDetaliiEFactura(loAnafMesaj.cIdDescarcare, ' Descarcare detalii factura ID: ' + loAnafMesaj.cIdDescarcare)
				llSucces = loDetalii.lSucces

				If !m.llSucces
					loAnafMesaj.cEroare = 'Eroare descarcare detalii factura id_descarcare = ' + Alltrim(loAnafMesaj.cIdDescarcare) + ;
						'. Cod eroare: ' + Alltrim(Transform(loDetalii.nStatus))  + ' ' + loDetalii.cErrorMessage
					loAnafMesaj.lEroare = .T.
				Else
					If 'eroare' $ Lower(loDetalii.cResponse)
						loAnafMesaj.cEroare = 'Eroare descarcare detalii raspuns id_descarcare = ' + Alltrim(loAnafMesaj.cIdDescarcare) + '. ' + loDetalii.cResponse
						loAnafMesaj.lEroare = .T.
					Endif && 'eroare' $ Lower(loDetalii.cResponse)
				Endif && m.llSucces  loDetalii.lSucces

				IF loAnafMesaj.lEroare
					This.Log('Proceseaza Mesaj  ' + loAnafMesaj.cEroare)
				ELSE
					llSucces = This.SaveFile(loDetalii.cResponse, .T., m.lcDirectory, m.lcFile)			
					This.Log('Proceseaza Mesaj salvare fisier: ' + Transform(m.llSucces) + ' ' + m.lcFilePath)
				ENDIF && lEroare		
				
			ENDIF && !file	
		ENDWITH && toMesaj
		
		* Salvez arhiva pe disk
		IF FILE(m.lcFilePath)
			This.Log('Proceseaza Mesaj. Exista fisierul: ' + m.lcFilePath)
			loAnafMesaj.lEroare = .F.
			llSucces = .T.
			* Actualizez cRaspunsuri.descarcat, filepath
			lnDescarcatServer = IIF(this.lServer, 1, 0) && marchez descarcat doar daca am descarcat pe server
			This.cUpdateDescarcat(loAnafMesaj.cIdIncarcare, m.lnDescarcatServer, m.lcFilePath)
		ENDIF 
		
		Return loAnafMesaj
	Endproc && ProceseazaMesaj

* Salveaza fisiere/variabile pe disk
	Procedure SaveFile
		Lparameters tcFile, tlVariable, tcDirectory, tcFileName
* tcFile: calea catre fisierul sursa
* tlVariable: .T. daca tcFile este o variabila cu continutul fisierului
* tcFileName: numele fisierului destinatie
		Local lcFile2, llSucces, loEx As Exception

		llSucces = .T.
		lcFileName2 = Iif(!Empty(m.tcFileName), m.tcFileName, Justfname(m.tcFile))
		lcFile2 = Addbs(m.tcDirectory) + m.lcFileName2
		If !Empty(m.tcDirectory) And !Directory(m.tcDirectory)
			Try
				Md (m.tcDirectory)
			Catch To loEx
				llSucces = .F.
				This.Log('SaveFile ' + 'Eroare: ' + TRANSFORM(loEx.ErrorNo) + ' ' + loEx.Message + ' Continut:' + loEx.LineContents +   + ' Linia: ' + TRANSFORM(loEx.LineNo) + ' Program: ' + loEx.Procedure)
			Endtry
		Endif
		If !Empty(m.tcDirectory) And Directory(m.tcDirectory)
			Try
				If m.tlVariable
					Strtofile(m.tcFile, m.lcFile2)
				Else
					Copy File (m.tcFile) To (m.lcFile2)
				ENDIF
				This.Log('SaveFile ' + m.lcFile2)
				llSucces = .T.
			Catch To loEx
				llSucces = .F.
				This.Log('SaveFile ' + 'Eroare: ' + TRANSFORM(loEx.ErrorNo) + ' ' + loEx.Message + ' Continut:' + loEx.LineContents +   + ' Linia: ' + TRANSFORM(loEx.LineNo) + ' Program: ' + loEx.Procedure)
			Endtry
		Endif
		Return m.llSucces
	Endproc && SaveFile

	************
	* Intoarce calea de salvare xml intr-un director comun, definit in baza de date OPTIUNI
	************
	Procedure GetFacturaSavePath
		Lparameters toFactura, tcExt
		* tcExt: optional, default xml
		
		Local loReturn As "empty"
		Local lcAn, lcDataAct, lcFile2, lcFile2Semnatura, lcFilePdf, lcFileSemnatura, lcFurnizor
		Local lcIdDescarcare, lcIdIncarcare, lcLuna, lcLuna2, lcLuna3, lcNumarAct, lcSaveFile, lcSavePath
		Local llSucces, lcExt, lcFirma

		llSucces = .F.
		lcExt = IIF(!EMPTY(m.tcExt), m.tcExt, 'xml')

		lcTip = ALLTRIM(UPPER(toFactura.tip_mesaj_raspuns)) && FACTURI TRIMISE / FACTURI PRIMITE
		llFurnizor = 'PRIMIT'$m.lcTip
		
		IF m.llFurnizor
			lcPartener = WindowsSpecialCharacters(toFactura.Furnizor)
			lcSavePath = This.cSaveFurnizoriPath
			lcSaveFile = This.cSaveFurnizoriFile
		ELSE 	
			lcPartener = WindowsSpecialCharacters(toFactura.Client)
			lcSavePath = This.cSaveClientiPath	
			lcSaveFile = This.cSaveClientiFile					
		ENDIF 
		lcFirma = This.cUser
		lcPartener = Alltrim(Left(Strtran(m.lcPartener, '.', '',1,100,1), 50))
		
		lcAn = Alltrim(Str(Year(toFactura.dataact)))
		lcLuna = c_luna(Month(toFactura.dataact))
		lcLuna3 = cluna3(Month(toFactura.dataact))
		lcLuna2 = Padl(Month(toFactura.dataact), 2, '0')
		lcDataAct = Dtos(toFactura.dataact)
		lcIdIncarcare = toFactura.cIdIncarcare
		lcIdDescarcare = toFactura.cIdDescarcare
		lcNumarAct = Alltrim(WindowsSpecialCharacters(toFactura.numaract))

		lcSavePath = Strtran(m.lcSavePath, '<an>', m.lcAn, 1, 100, 1)
		lcSavePath = Strtran(m.lcSavePath, '<aaaa>', m.lcAn, 1, 100, 1)
		lcSavePath = Strtran(m.lcSavePath, '<id_incarcare>', m.lcIdIncarcare, 1, 100, 1)
		lcSavePath = Strtran(m.lcSavePath, '<id_descarcare>', m.lcIdDescarcare, 1, 100, 1)
		lcSavePath = Strtran(m.lcSavePath, '<luna>', m.lcLuna, 1, 100, 1)
		lcSavePath = Strtran(m.lcSavePath, '<lll>', m.lcLuna3, 1, 100, 1)
		lcSavePath = Strtran(m.lcSavePath, '<ll>', m.lcLuna2, 1, 100, 1)
		lcSavePath = Strtran(m.lcSavePath, '<yyyymmdd>', m.lcDataAct, 1, 100, 1)
		lcSavePath = Strtran(m.lcSavePath, '<datafact>', m.lcDataAct, 1, 100, 1)
		lcSavePath = Strtran(m.lcSavePath, '<furnizor>', m.lcPartener, 1, 100, 1)
		lcSavePath = Strtran(m.lcSavePath, '<client>', m.lcPartener, 1, 100, 1)		
		lcSavePath = Strtran(m.lcSavePath, '<firma>', m.lcFirma, 1, 100, 1)		
				
		lcSavePath = Addbs(m.lcSavePath)

		
		If Empty(m.lcSaveFile)
			lcFile2 = m.lcSavePath + m.lcIdIncarcare + '_' + m.lcIdDescarcare + '_' + m.lcDataAct + '_' + m.lcNumarAct + '.' + m.lcExt
		Else
			lcFile2 = m.lcSavePath + Strtran(m.lcSaveFile, '<id_incarcare>', m.lcIdIncarcare, 1, 100, 1)
			lcFile2 = Strtran(m.lcFile2, '<id_descarcare>', m.lcIdDescarcare, 1, 100, 1)					
			lcFile2 = Strtran(m.lcFile2, '<datafact>', m.lcDataAct, 1, 100, 1)
			lcFile2 = Strtran(m.lcFile2, '<furnizor>', m.lcPartener, 1, 100, 1)
			lcFile2 = Strtran(m.lcFile2, '<client>', m.lcPartener, 1, 100, 1)			
			If EMPTY(Justext(Lower(m.lcFile2)))
				lcFile2 = m.lcFile2 + '.' + m.lcExt
			Endif
		ENDIF

		RETURN m.lcFile2
		
	Endproc && GetFacturaSavePath


************************************
* Intoarce un obiect tip ANAF_EFACTURA, doar informatiile din mesajul ANAF, pentru salvarea in baza de date
************************************
	Function NewMesaj
		Local loMesaj
		loMesaj= Createobject("empty")
		AddProperty(loMesaj, 'nId', Null)
		AddProperty(loMesaj, 'cIdIncarcare', Null)
		AddProperty(loMesaj, 'cMesajRaspuns', Null)
		AddProperty(loMesaj, 'dDataRaspuns', Null)
		AddProperty(loMesaj, 'cMesajRaspuns', Null)
		AddProperty(loMesaj, 'cTipMesajRaspuns', Null)
		AddProperty(loMesaj, 'cIdDescarcare', Null)
		AddProperty(loMesaj, 'cCodFiscalEmitent', Null)
		AddProperty(loMesaj, 'cCodFiscalBeneficiar', Null)
		AddProperty(loMesaj, 'cDetalii', Null)
		AddProperty(loMesaj, 'nFacturaEmisa', Null)
		AddProperty(loMesaj, 'nTest', 0)
		AddProperty(loMesaj, 'lEroare', .F.)
		AddProperty(loMesaj, 'cEroare', '')

		Return loMesaj
	Endfunc && NewMesaj


* Citeste raspunsuri eFactura de la ANAF
	Function ReadResponseEFactura
		Lparameters tnZile

		Local loHTTP As 'winHTTP.winHTTPrequest.5.1'
		Local loReturn As "empty"
		Local lcServer, llTest, lcToken, lcCodFiscal, lnZile
		llTest = This.lTest
		lcToken = This.cToken
		lcCodFiscal = This.cCodFiscal
		lnZile = Iif(!Empty(m.tnZile), Min(m.tnZile, 60), 60)

		This.Log('ReadResponseEfactura: Citire raspunsuri ANAF ultimele ' + Alltrim(Str(m.lnZile)) + '...')

		Try
			lcServer = [https://api.anaf.ro/] + Iif(m.llTest, [test], [prod]) + [/FCTEL/rest/listaMesajeFactura?zile=] + Alltrim(Str(m.lnZile)) + [&cif=] + m.lcCodFiscal && 1879855
			This.Log(m.lcServer)
			loHTTP = Createobject('winHTTP.winHTTPrequest.5.1')
			loHTTP.Open('GET', lcServer, .F.)
			loHTTP.setRequestHeader("Content-Type", "application/xml;")
			loHTTP.setRequestHeader('Authorization', 'Bearer ' + m.lcToken)

			loHTTP.Send()
		Catch To loEx
			This.Log('ReadResponseEfactura ' + loEx.Message)
		Endtry

		loReturn = Createobject("empty")
		AddProperty(loReturn, "lSucces", (loHTTP.Status = 200))
		AddProperty(loReturn, "cResponse", loHTTP.ResponseText)
		AddProperty(loReturn, "nStatus", loHTTP.Status)
		If loHTTP.Status <> 200
			loReturn.cResponse = loHTTP.StatusText && 403 Forbidden
		Endif
		This.Log('ReadResponseEfactura ' + Transform(loHTTP.Status))

		Return loReturn

	Endfunc

******************
* Citeste detalii factura eFactura de la ANAF
* Intoarce un obiect cu cResponse (continutul arhivei zip)
*****************
	Function DownloadDetaliiEFactura
		Lparameters tcIdDescarcare, tcWaitWindowText
* tcIdDescarcare: Id descarcare ANAF
* tcWaitWindowText: optional, text pentru wait window:

		Local loHTTP As 'winHTTP.winHTTPrequest.5.1'
		Local loReturn As "empty", loEx As Exception
		Local lcServer, llTest, lcToken, lcCodFiscal, lcIdDescarcare, lcErrorMessage, lcWaitWindowText
		llTest = This.lTest
		lcToken = This.cToken
		lcIdDescarcare = m.tcIdDescarcare
		lcErrorMessage = ''
		lcWaitWindowText = Iif(!Empty(m.tcWaitWindowText), m.tcWaitWindowText, 'Descarcare detalii factura ID: ' + m.tcIdDescarcare)

		WAIT WINDOW m.lcWaitWindowText NOWAIT 
		
		Try
			lcServer = [https://api.anaf.ro/] + Iif(m.llTest, [test], [prod]) + [/FCTEL/rest/descarcare?id=] + m.lcIdDescarcare
			This.Log('DownloadDetaliieFactura ' + m.lcServer)
			loHTTP = Createobject('winHTTP.winHTTPrequest.5.1')
			loHTTP.Open('GET', lcServer, .F.)
			loHTTP.setRequestHeader("Content-Type", "application/xml;")
			loHTTP.setRequestHeader('Authorization', 'Bearer ' + m.lcToken)

			loHTTP.Send()
		Catch To loEx
			This.Log('DownloadDetaliieFactura ' + loEx.Message)
		Endtry

		loReturn = Createobject("empty")
		AddProperty(loReturn, "lSucces", (loHTTP.Status = 200))
		If 'eroare' $ Lower(loHTTP.ResponseText)
			lcResponse = loHTTP.ResponseText
			lcErrorMessage = m.lcResponse
		Else
			lcResponse = loHTTP.ResponseBody
		Endif
		AddProperty(loReturn, "cResponse", m.lcResponse) && arhiva zip sau json cu text eroare {'eroare' : 'Factura cu id 1112 nu exista'}
		AddProperty(loReturn, "nStatus", loHTTP.Status)
		AddProperty(loReturn, "cErrorMessage", m.lcErrorMessage)

		This.Log('DownloadDetaliieFactura ' + Transform(loHTTP.Status) + ' ' + m.lcErrorMessage)
		Return loReturn

	Endfunc


*****************
* Adauga/actualizeaza datele si detaliile facturii in baza de date ANAF_EFACTURA
* Foloseste obiect returnat din ParseEFactura
* Intoarce SUCCES = .T.
*****************
	Procedure cUpdateFactura
		Parameters toFactura, tcCursor

		*toFactura: obiect din ParseEFactura
		* tcCursor: optional, anaf_efactura sau un cursor asemanator, temporar
		
		LOCAL llSucces, lcSql, lcCursor
		lcCursor = IIF(EMPTY(m.tcCursor), 'anaf_efactura', m.tcCursor)
		
	    UPDATE (m.lcCursor) ;
	       set xnumar_act         = toFactura.NumarAct, ;
	           xdata_act          = toFactura.DataAct, ;
	           xdata_scad         = toFactura.DataScad, ;
	           xdescriere         = toFactura.Detalii, ;
	           xdetalii_plata     = Left(toFactura.Detaliiplata, 500), ;
	           xtotal_fara_tva    = toFactura.TotalFaraTva, ;
	           xtotal_tva         = toFactura.TotalTva, ;
	           xtotal_tva_ron	  = toFactura.TotalTvaRON, ;
	           xtotal_cu_tva      = toFactura.TotalCuTva, ;
	           xdiscount_fara_tva = toFactura.DiscountFaraTVA, ;
	           xtaxe_fara_tva     = toFactura.TaxeFaraTVA, ;
	           xvaloare_fara_tva  = toFactura.ValoareFaraTVA, ;
	           xtotal_de_plata    = toFactura.TotaldePlata, ;
	           xnume_valuta       = toFactura.Valuta, ;
	           xfurnizor          = toFactura.Furnizor, ;
	           xclient            = toFactura.Client, ;
	           factura_detalii    = toFactura.FacturaDetalii, ;
	           creditnote		  = toFactura.CreditNote, ;
	           cod_fiscal_emitent = IIF(EMPTY(NVL(cod_fiscal_emitent,'')), UPPER(ALLTRIM(GetNrFromString(NVL(toFactura.CodFiscalFurnizor,'')))), cod_fiscal_emitent), ;
	           cod_fiscal_beneficiar = IIF(EMPTY(NVL(cod_fiscal_beneficiar,'')), UPPER(ALLTRIM(GetNrFromString(NVL(toFactura.CodFiscalClient,'')))), cod_fiscal_beneficiar), ;
	           modificat = 1 ;
	     where id_incarcare = toFactura.cIdIncarcare		   
	     llSucces = .T.  
	     
	     TABLEUPDATE(1,.F., m.lcCursor)

		RETURN m.llSucces
	Endproc && cUpdateFactura

*****************
* Adauga/actualizeaza un raspuns FACTURA PRIMITA/TRIMISA/EROARE in ANAF_EFACTURA
* Mesajul intoarce ANAF_EFACTURA.ID
* Intoarce SUCCES = .T.
*****************
	Procedure UpdateRaspuns
		Parameters toMesaj
		Private pnId
		pnId = 0

		TEXT TO lcSql NOSHOW
BEGIN
	pack_anaf.UpdateRaspuns(?.cIdIncarcare,
                             ?.dDataRaspuns,
                             ?.cMesajRaspuns,
                             ?.cTipMesajRaspuns,
                             ?.cIdDescarcare,
                             ?.cCodFiscalEmitent,
                             ?.cCodFiscalBeneficiar,
                             ?.cDetalii,
                             ?.nTest,
                             ?@pnId);
end;
		ENDTEXT
		With toMesaj
			llSucces = goExecutor.oExecuta(m.lcSql)
		Endwith
		If m.llSucces
			toMesaj.nId = m.pnId
		Endif

		Return m.llSucces
	Endproc && UpdateRaspuns

*****************
* Actualizeaza un ANAF_EFACTURA.DETALII, DETALII_ZIP (arhiva xml efactura) dupa ce se descarca arhiva cu detaliile unui raspuns
* Intoarce SUCCES = .T.
*****************
	Procedure UpdateRaspunsDetalii
		Parameters pcIdDescarcare, pcDetalii, pcDetaliiZip

		Local lcSql, llSucces
* Fac update direct pe tabela in loc de pack_anaf.UpdateRaspunsDetalii, pentru ca da cateaodata eroare (BUG oracle)
		llSucces = goExecutor.oExecuta('update anaf_efactura set detalii = ?pcDetalii, detalii_zip = ?pcDetaliiZip where id_descarcare = ?pcIdDescarcare')

		If .F. && am facut direct update pe tabela
			lcSql = [BEGIN pack_anaf.UpdateRaspunsDetalii(?pcIdDescarcare, ?pcDetalii, ?pcDetaliiZip); end;]
			llSucces = goExecutor.oExecuta(m.lcSql)
			If !m.llSucces
* Da eroare cateodata, asa ca reincerc update direct pe tabela
				If AMESSAGEBOX('Doriti sa reincercati actualizarea detaliilor?',4+32,_Screen.Caption) = 6
					llSucces = goExecutor.oExecuta('update anaf_efactura set detalii = ?pcDetalii, detalii_zip = ?pcDetaliiZip where id_descarcare = ?pcIdDescarcare')
				Endif
			Endif
		Endif

		Return m.llSucces
	Endproc && UpdateRaspunsDetalii

*****************
* Marcheaza ANAF_EFACTURA.PROCESAT = 1 ca sa nu se mai descarce arhiva cu detaliile raspunsului, daca mesajul a fost procesat
*****************
	Procedure UpdateProcesat
		Parameters tcIdDescarcare, tnProcesat
* tnIdEfactura: ANAF_EFACTURA.ID_DESCARCARE
* tnProcesat: OPTIONAL, DEFAULT (1)

		Local lcSql, llSucces
		Private pnProcesat
		pnProcesat = Iif(!Empty(m.tnProcesat) And Type('tnProcesat') = 'N' And Inlist(m.tnProcesat,0,1), m.tnProcesat, 1)

		lcSql = [BEGIN pack_anaf.UpdateProcesat(?tcIdDescarcare, ?pnProcesat); END;]

		llSucces = goExecutor.oExecuta(m.lcSql)
		Return m.llSucces
	Endproc && UpdateProcesat

	*****************
	* Intoarce .T. daca un IdDescarcare a fost descarcat
	*****************
	Function cIsDescarcat
		Parameters tcIdIncarcare
		Local llDescarcat
		
		IF SEEK(m.tcIdIncarcare, 'anaf_efactura', 'id_inc')
	 		llDescarcat = (anaf_efactura.descarcat = 1)
	 	ENDIF 
	 		
		RETURN m.llDescarcat
	Endfunc && cIsDescarcat

	*****************
	* Intoarce .T. daca un IdIncarcare a fost procesat
	*****************
	Function cIsProcesat
		Parameters tcIdIncarcare
		Local llProcesat
		
		IF SEEK(m.tcIdIncarcare, 'anaf_efactura', 'id_inc')
	 		llProcesat = (anaf_efactura.procesat = 1)
	 	ENDIF 
	 		
		RETURN m.llProcesat
	Endfunc && cIsProcesat
	
	*****************
	* Completeaza raspunsuri.descarcat, filepath, dupa salvarea arhivei raspuns
	*****************
	PROCEDURE cAddMesaj
		PARAMETERS toMesaj

		LOCAL lcSql, llSucces
		

		TEXT TO lcSql NOSHOW 
merge into anaf_efactura a using dual b ON (a.id_incarcare = ?tcIdIncarcare)
when not matched then
	INSERT (id_incarcare, id_descarcare) VALUES (?tcIdIncarcare, ?tcIdDescarcare)
		ENDTEXT 	
*!*			llSucces = goExecutor.oExecuta(m.lcSql)

*!*			IF m.llSucces
			WITH toMesaj
			IF !SEEK(.cIdIncarcare,'anaf_efactura', 'id_inc')
				INSERT INTO anaf_efactura (id_incarcare, id_descarcare,tip_mesaj_raspuns,mesaj_raspuns,data_raspuns,cod_fiscal_emitent,cod_fiscal_beneficiar,factura_emisa,test) ;
					VALUES (.cIdIncarcare, .cIdDescarcare, .cTipMesajRaspuns,.cMesajRaspuns,.dDataRaspuns,.cCodFiscalEmitent,.cCodFiscalBeneficiar,.nFacturaEmisa,.nTest)           				
				
				TABLEUPDATE(1,.F.,'ANAF_EFACTURA')						
			ENDIF 	
			ENDWITH 				
			llSucces = .T.
*!*			ENDIF 	
		RETURN m.llSucces	
	ENDPROC && AddMesaj
	
	*****************
	* Completeaza raspunsuri.descarcat, filepath, dupa salvarea arhivei raspuns
	*****************
	PROCEDURE cUpdateDescarcat
		PARAMETERS tcIdIncarcare, tnDescarcat, tcFilePath
			
		TEXT TO lcSql noshow
UPDATE anaf_efactura SET descarcat = ?tnDescarcat, filepath = ?tcFilePath WHERE id_incarcare = ?tcIdIncarcare		
		ENDTEXT 
		
*!*			llSucces = goExecutor.oExecuta(m.lcSql)
*!*			IF m.llSucces
		UPDATE anaf_efactura SET descarcat = m.tnDescarcat, filepath = m.tcFilePath, modificat = 1 WHERE id_incarcare = m.tcIdIncarcare
		
		TABLEUPDATE(1,.F.,'ANAF_EFACTURA')		
		llSucces = .T.
*!*			ENDIF 	
		RETURN m.llSucces
	ENDPROC 

	*****************
	* Completeaza raspunsuri.descarcat, filepath, dupa salvarea arhivei raspuns
	*****************
	PROCEDURE cUpdateProcesat
		PARAMETERS tcIdIncarcare

		UPDATE anaf_efactura SET procesat = 1, modificat = 1 WHERE id_incarcare = m.tcIdIncarcare
		
		TABLEUPDATE(1,.F.,'ANAF_EFACTURA')
		
		llSucces = .T.

		RETURN m.llSucces
	ENDPROC 

	*****************
	* Completeaza anaf_efactura.procesat_server = 1, dupa procesarea arhivei pe servers sau in directorul din retea
	*****************
	PROCEDURE cUpdateProcesatServer
		PARAMETERS tcIdIncarcare

		UPDATE anaf_efactura SET procesat_server = 1, modificat = 1 WHERE id_incarcare = m.tcIdIncarcare
		
		TABLEUPDATE(1,.F.,'ANAF_EFACTURA')
		llSucces = .T.

		RETURN m.llSucces
	ENDPROC 
		
	*****************
	* Completeaza anaf_efactura.detalii (continutul fisierului xml din raspuns)
	*****************
	PROCEDURE cUpdateDetalii
		PARAMETERS tcIdIncarcare, tcDetalii

		UPDATE anaf_efactura SET detalii = m.tcDetalii, modificat = 1 WHERE id_incarcare = m.tcIdIncarcare
		
		TABLEUPDATE(1,.F.,'ANAF_EFACTURA')
		llSucces = .T.

		RETURN m.llSucces
	ENDPROC 


	*****************
	* actualizeaza anaf_efactura
	*****************
	PROCEDURE UpdateDb
		LPARAMETERS tcCursor
		
		LOCAL lcSql, llSucces, lnSucces, lcSelect, lcCursor
	
		lcSelect = SELECT()
		lcCursor = IIF(EMPTY(m.tcCursor), 'anaf_efactura', m.tcCursor)	

		llSucces = .T.		
           
		lnSucces = This.ConnectROA()

		IF m.lnSucces = CT_SUCCES
			* Actualizez datele doar pentru facturile care nu au fost procesate (fie de catre server, fie de catre clienti)
			SELECT * FROM (m.lcCursor) WITH (BUFFERING = .T.) WHERE modificat = 1 OR procesat = 0 INTO CURSOR crsUpdateTemp
		
			SELECT crsUpdateTemp
			SCAN
				SCATTER NAME loRec MEMO 
				lcText = 'Actualizare baza de date ' + ALLTRIM(STR(RECNO())) + '/' + ALLTRIM(STR(RECCOUNT()))
				WAIT WINDOW m.lcText NOWAIT 
				This.Log(m.lcText)
				llSucces = This.UpdateDbFactura(loRec)

				IF !m.llSucces
					lcErrorMessage = This.cErrorMessage
					IF LEN(m.lcErrorMessage) > 200
						IF This.lServer
							WAIT WINDOW LEFT(m.lcErrorMessage,200) NOWAIT 
						ELSE 
							AMESSAGEBOX(m.lcErrorMessage,0+48,_Screen.Caption)	
						ENDIF 
					ELSE
						WAIT WINDOW m.lcErrorMessage NOWAIT 
					ENDIF 	

					This.Log(m.lcErrorMessage)
					IF !This.lServer
						* daca imi da eroare la o factura, incerc sa le actualizez pe celelalte
						IF AMESSAGEBOX('Continuati actualizarea celorlalte facturi in baza de date?',4+32,_screen.Caption) <> 6
							EXIT
						ENDIF 	
					ENDIF 	
				ENDIF 
			ENDSCAN 
			
			USE IN (SELECT('crsUpdateTemp'))
		ENDIF && lnSucces
		
		lnSucces = This.DisConnectROA() 	
		
		SELECT (m.lcSelect)
		RETURN m.llSucces	

	ENDPROC && UpdateDb
	

	*****************
	* actualizeaza o linie de factura in anaf_efactura
	*****************
	PROCEDURE UpdateDbFactura
		LPARAMETERS toFactura
		* toFactura : obiect din anaf_efactura
		
		Local lcSql, llSucces, lcText
		Local lcFacturaDetalii, lnIdEfactura, llZipDatabase
		PRIVATE pcDetalii, pcDetaliiZip, pnId, pcDetaliiPlata

		lcText = StripNonAscii(NVL(toFactura.xdetalii_plata,''), '')
		lcText = RemoveCharactersDB(m.lcText, .T.)
		lcText = LEFT(ALLTRIM(m.lcText), 495)
		toFactura.xdetalii_plata = m.lcText && LEFT(ALLTRIM(StripNonAscii(NVL(toFactura.xdetalii_plata,''), '')), 495)

		lcText = StripNonAscii(NVL(toFactura.xdescriere,''), '')
		lcText = RemoveCharactersDB(m.lcText, .T.)
		lcText = LEFT(ALLTRIM(m.lcText), 3995)
		toFactura.xdescriere = m.lcText && LEFT(ALLTRIM(StripNonAscii(NVL(toFactura.xdescriere, ''), '')), 3995)
		
		lcText = StripNonAscii(NVL(toFactura.mesaj_raspuns,''), '')
		lcText = RemoveCharactersDB(m.lcText, .T.)
		lcText = LEFT(ALLTRIM(m.lcText), 250)
		toFactura.mesaj_raspuns = m.lcText

		llZipDatabase = This.lZipDatabase && daca se salveaza zip efactura in baza de date
		pnId = 0
		* Nu mai actualizez anaf_detalii in pack_anaf.UpdateFactura, pentru ca da eroare cateodata (cand sunt prea multe linii?)
		* Actualizez separat liniile
		pcDetalii = toFactura.Detalii
		pcDetaliiZip = ''

		IF m.llZipDatabase AND TYPE('toFactura.filepath') = 'C' AND !EMPTY(NVL(toFactura.filepath,'')) AND FILE(NVL(toFactura.filepath,''))
			pcDetaliiZip = FILETOSTR(ALLTRIM(NVL(toFactura.filepath,'')))
		ENDIF 			
		lcFacturaDetalii = NVL(toFactura.factura_detalii, '')
		toFactura.xnumar_act = RIGHT(ALLTRIM(toFactura.xnumar_act), 30)
		toFactura.procesat = 1 && sa se actualizeze anaf_efactura.procesat
		llSucces = .F.
		
		TEXT TO lcSql NOSHOW 
begin
  pack_anaf.AdaugaRaspunsFactura(v_id_incarcare => ?TRIM(.id_incarcare),
                                 v_data_raspuns => ?.data_raspuns,
                                 v_mesaj_raspuns => ?TRIM(.mesaj_raspuns),
                                 v_tip_mesaj_raspuns => ?TRIM(.tip_mesaj_raspuns),
                                 v_id_descarcare => ?TRIM(.id_descarcare),
                                 v_cod_fiscal_emitent => ?TRIM(.cod_fiscal_emitent),
                                 v_cod_fiscal_beneficiar => ?TRIM(.cod_fiscal_beneficiar),
                                 v_detalii => ?.detalii,
                                 v_test => ?.test,
                                 v_numar_act => ?TRIM(.xnumar_act),
                                 v_data_act => ?.xdata_act,
                                 v_data_scad => ?.xdata_scad,
                                 v_furnizor => ?TRIM(.xfurnizor),
                                 v_client => ?TRIM(.xclient),
                                 v_descriere => ?TRIM(LEFT(.xdescriere,3995)),
                                 v_detalii_plata => ?.xdetalii_plata,
                                 v_total_fara_tva => ?.xtotal_fara_tva,
                                 v_total_tva => ?.xtotal_tva,
		                         v_total_tva_ron => ?.xtotal_tva_ron,
                                 v_total_cu_tva => ?.xtotal_cu_tva,
                                 v_discount_fara_tva => ?.xdiscount_fara_tva,
                                 v_taxe_fara_tva => ?.xtaxe_fara_tva,
                                 v_valoare_fara_tva => ?.xvaloare_fara_tva,
                                 v_total_de_plata => ?.xtotal_de_plata,
                                 v_nume_valuta => ?TRIM(.xnume_valuta),
                                 v_descarcat => ?.descarcat,
                                 v_filepath => ?.filepath,
                                 v_procesat_server => ?.procesat_server,                                 
                                 v_procesat => ?.procesat,                                 
                                 v_xmldetalii => ?.factura_detalii,
                                 v_creditnote => ?.creditnote,
                                 V_ID_EFACTURA => ?@pnId);
end;
		ENDTEXT 	

           
		* Daca len(FacturaDetalii) > 5000, da eroare si trebuie sa actualizez separat
		IF LEN(m.lcFacturaDetalii) < 5000 AND LEN(m.pcDetalii) < 5000
			WITH toFactura								
				lnSucces = goExecutor.oExecute(m.lcSql)	
				llSucces = (m.lnSucces = CT_SUCCES)				
			ENDWITH 	

			IF !m.llSucces
				SET STEP ON 
				This.lError = .T.
				This.cErrorMessage = goExecutor.cEroare
			ENDIF 			

			IF m.llSucces AND m.llZipDatabase AND !EMPTY(m.pcDetaliiZip)
				* Fac update direct pe tabela in loc de pack_anaf.UpdateRaspunsDetalii, pentru ca da cateodata eroare (BUG oracle)
				lcSql = 'update anaf_efactura set detalii_zip = ?pcDetaliiZip where id = ?pnId'
				lnSucces = goExecutor.oExecute(m.lcSql)
				llSucces = (m.lnSucces = CT_SUCCES)				
				IF !m.llSucces
					
					This.lError = .T.
					This.cErrorMessage = goExecutor.cEroare
				ENDIF 
			ENDIF 			
		ENDIF && len

		*********************************************
		* Daca da eroare, mai incerc o data fara transmiterea detalii factura = lista articole.
		* Articolele le salvez separat
		IF !m.llSucces
			* ORA-01460
			toFactura.factura_detalii = ''			
			toFactura.detalii = ''

			WITH toFactura								
				lnSucces = goExecutor.oExecute(m.lcSql)	
				llSucces = (m.lnSucces = CT_SUCCES)
			ENDWITH 
			
			IF !m.llSucces
				SET STEP ON 			
				This.lError = .T.
				This.cErrorMessage = goExecutor.cEroare
			ELSE 	
				* Adaug fiecare linie in anaf_efactura_detalii pentru ca cateodata se blocheaza Oracle BUG, daca este > 4.000 caractere
				llSucces = This.UpdateFacturaDetalii(m.pnId, m.lcFacturaDetalii)	
			ENDIF 		
		
			IF m.llSucces
				* Fac update direct pe tabela in loc de pack_anaf.UpdateRaspunsDetalii, pentru ca da cateodata eroare (BUG oracle)
				lcSql = 'update anaf_efactura set detalii = ?pcDetalii' + IIF(m.llZipDatabase and !EMPTY(m.pcDetaliiZip), ', detalii_zip = ?pcDetaliiZip', '') + ' where id = ?pnId'
				lnSucces = goExecutor.oExecute(m.lcSql)
				llSucces = (m.lnSucces = CT_SUCCES)
								
				IF !m.llSucces
					SET STEP ON 
					This.lError = .T.
					This.cErrorMessage = goExecutor.cEroare
				ENDIF 				
			ENDIF 				
		ENDIF 

		IF !m.llSucces
			lcErrorMessage = 'UpdateDb Eroare la actualizarea datelor facturii pe server anaf_efactura.id = ' + TRANSFORM(m.pnId) + ' numar = ' + TRANSFORM(toFactura.xnumar_act) + CHR(13) + CHR(10) + ;
				This.cErrorMessage
			This.cErrorMessage = m.lcErrorMessage
			This.lError = .T.
			This.Log(m.lcErrorMessage)
		ENDIF 
			
		RETURN m.llSucces	

	ENDPROC && UpdateDb
	
	*************************
	*** Adaug linii una cate una, din cauza ca uneori are eroare la UpdateFactura cu toate detaliile, cand sunt prea multe linii poate?
	*************************
	Procedure UpdateFacturaDetalii
		Parameters tnIdEfactura, tcFacturaDetalii
		* tnIdEfactura: Id efactura
		* tcFacturaDetalii: xml detalii factura

		Local lcSql, llSucces, lnCount, lnRec, lnRecs
		Private poRec

		llSucces = .T.
		lnCount = 0

		* Verific daca exista deja introduse linii factura. Nu mai introduc
		lcSql = "select count(*) from ANAF_EFACTURA_DETALII WHERE ID_EFACTURA = ?tnIdEfactura"
		llSucces = goExecutor.oSelecteaza2Value(m.lcSql, @lnCount)
		If Nvl(m.lnCount,0) > 0
			Return m.llSucces
		Endif

		TEXT TO lcSql NOSHOW
	INSERT INTO ANAF_EFACTURA_DETALII (ID_EFACTURA, NR, ARTICOL, DESCRIERE, DETALII, UM, CANTITATE, PRET, PROCTVA, TIPTVA, VALOAREFARATVA, DISCOUNTFARATVA) 
	VALUES (?tnIdEfactura, ?.NR, ?.ARTICOL, ?.DESCRIERE, ?.DETALII, ?.UM, ?.CANT, ?.PRET, ?.PROCTVA, ?.TIPTVA, ?.VALOAREFARATVA, ?.DISCOUNTFARATVA)
		ENDTEXT


		TRY 
			lnRecs = Xmltocursor(tcFacturaDetalii, "cFacturaDetaliiTemp")
		
			Select cFacturaDetaliiTemp
			Scan
				Scatter Name poRec Memo
				Wait Window 'eFactura ID ' + Alltrim(Str(m.tnIdEfactura)) + ' Salvare articol ' + Alltrim(Str(Recno())) + '/' + Alltrim(Str(m.lnRecs)) + ' ...' Nowait

				With poRec				
					.descriere = RemoveCharactersDB(.descriere, .T.)
					.descriere = LEFT(ALLTRIM(.descriere), 300)					
					.articol = RemoveCharactersDB(.articol, .T.)
					.articol = LEFT(ALLTRIM(.articol), 300)						
					
					lnSucces = goExecutor.oExecute(m.lcSql)
					llSucces = (m.lnSucces = CT_SUCCES)
					If !m.llSucces
						This.cErrorMessage = goExecutor.cEroare
						This.lError = .T.				
						Exit
					Endif
				Endwith
			Endscan

			Use In (Select('cFacturaDetaliITemp'))
		CATCH TO loEx
			This.Log('tcFacturaDetalii ' + tcFacturaDetalii)
		ENDTRY 		

		Return m.llSucces

	Endproc && UpdateFacturaDetalii

****************
* Genereaza pdf din xml eFactura pe serverul ANAF
****************
	Procedure xml2PdfAnaf
		Lparameters tcFile, tcFisierPdf, tlVariable
* tcXml: xml eFactura
* tcFisierPdf : (optional) calea catre fisierul Pdf generat. Altfel, se intreaba utilizatorul
* tlVariable: .T. daca tcFile este o variabila cu continutul xml efactura

		Local loHTTP As 'winHTTP.winHTTPrequest.5.1'
		Local loReturn As "empty"
		Local lcMesaj, lcSend, lcServer, lcStare, llValid, lnBytes, lnMesaj, lnMesaje, loJson, loMessage, lcTip, lcToken
		
		loReturn = Createobject("empty")
		AddProperty(loReturn, "lSucces", .F.)
		AddProperty(loReturn, "cFile", '')
		AddProperty(loReturn, "cResponse", '')
		AddProperty(loReturn, "cResponseBody", '')
		AddProperty(loReturn, "nStatus", 0)
		AddProperty(loReturn, "cFilePdf", '')
		If !Empty(m.tcFisierPdf)
			loReturn.cFilePdf = m.tcFisierPdf
		Endif

		lcSend = ''
		If m.tlVariable
			lcSend = m.tcFile
		Else
			If File(m.tcFile)
				lcSend = Filetostr(m.tcFile)
			Endif
		ENDIF
		lcTip = 'FACT1'
		IF 'CreditNote'$m.lcSend
			lcTip = 'FCN'
		ENDIF 
		lcToken = This.cToken
		
*!*			lcServer = [https://webservicesp.anaf.ro/prod/FCTEL/rest/transformare/] + m.lcTip + [/DA] && serviciu neautentificat
		lcServer = [https://api.anaf.ro/prod/FCTEL/rest/transformare/] + m.lcTip + [/DA] && serviciu autentificat
		
		loHTTP = Createobject('winHTTP.winHTTPrequest.5.1')
		loHTTP.Open('POST', lcServer, .F.)
		loHTTP.setRequestHeader("Content-Type", "text/plain")
		loHTTP.setRequestHeader('Authorization', 'Bearer ' + m.lcToken) && 9b1f44af738c16aa10c78347b9a064857f034b03a20704a03c131b99f019cee5		
	
		Try
			This.Log(m.lcServer)
		Catch
		Endtry



* Elimin caracterele Chr(13), Chr(10)
* Da eroare la serviciul ANAF
		lcSend = Strtran(m.lcSend, [&#x0D;], [])

* Sterg xsi:schemaLocation pentru ca poate da request rejected
* xsi:schemaLocation="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2 ../../UBL-2.1(1)/xsd/maindoc/UBL-Invoice-2.1.xsd"
		lcXsi = Strextract(lcSend, [xsi:schemaLocation="], [.xsd"], 1, 1)
		lcSend = Strtran(m.lcSend, m.lcXsi, '', 1, 1, 1)
		loHTTP.Send(m.lcSend)

		loReturn.nStatus = loHTTP.Status
		loReturn.cResponse = loHTTP.ResponseText
		loReturn.cResponseBody = loHTTP.ResponseBody
		loReturn.lSucces = (loHTTP.Status = 200)
		lcMesaj = ''

		If loReturn.lSucces
			Do Case
				Case ["stare"] $ Lower(loReturn.cResponse)
* Daca nu este valid xml
					loJson = nfjsonread(loReturn.cResponse)
					If Type('loJson.stare') = 'C' And !Empty(loJson.stare)
						lcStare = Alltrim(Lower(loJson.stare))
						llValid = (m.lcStare == 'ok')
						If !m.llValid
							If Type('loJson.messages_vfpsafe_') = 'U'
								lcMesaj = 'Fisierul nu s-a validat. Nu exista informatia [messages] in raspuns. ' + Chr(13) + Chr(10) + loReturn.cResponse
							Else
								lnMesaje = Alen(loJson.messages_vfpsafe_)
								lcMesaj = ''
								For lnMesaj = 1 To m.lnMesaje
									loMessage = loJson.messages_vfpsafe_[m.lnMesaj]
									If Type('loMessage.message') = 'C'
										lcMesaj = lcMesaj + loMessage.Message + Chr(13) + Chr(10)
									Endif
								Endfor
							Endif && messages
						Endif && llValid
					Endif
					If !Empty(m.lcMesaj)
						lcErrorMessage = 'XML2PDFANAF ' + m.lcMesaj
						This.cErrorMessage = m.lcErrorMessage
						This.lError = .T.
						This.Log(m.lcErrorMessage)
					Endif
				Case 'request rejected' $ Lower(loReturn.cResponse)
					lcErrorMessage = 'XML2PDFANAF Fisierul nu s-a validat.' + CRLF + loReturn.cResponse
					This.cErrorMessage = m.lcErrorMessage
					This.lError = .T.
					This.Log(m.lcErrorMessage)

				Otherwise
* Daca este valid xml
					If Empty(loReturn.cFilePdf)
						loReturn.cFilePdf = Putfile('Fisier pdf', 'efactura.pdf', 'pdf')
					Endif

					Try
						Delete File loReturn.cFilePdf
					Endtry
					lnBytes = Strtofile(loReturn.cResponseBody, loReturn.cFilePdf)
					This.Log('XML2PDFANAF ' + loReturn.cFilePdf)

			Endcase
		Endif && loReturn.lSucces

		Return loReturn.cFilePdf
	Endproc && Xml2PdfAnaf

	*********************
	* Trimite fisiere xml eFactura in SPV 
	*********************
	PROCEDURE VizSPV
		
* [{"id":"100000000","detalii":"recipisa pentru CIF 8000000000, tip D112, numar_inregistrare INTERNT-130000000-2017/20-12-2017, perioada raportare 11.2017","cif":"8000000000","data_creare":"20.12.2017 12:00:00","id_solicitare":null,"tip":"RECIPISA"}],"cnp":"1111111111118","cui":"8000000000,8000000001,8000000002","serial":"xxxxxxxxxxxxxxxxxxx"} 
		
*!*			CREATE CURSOR cMesajeSPV (ales N(1), id V(32), detalii V(250) null, cif V(20) null, data_creare T null, id_solicitare V(32) null, tip V(50) null, atasament W null, descarcat N(1), citit N(1), arhivat N(1))
*!*			lcSql = [select id, cif, data_creare, detalii, id_solicitare, tip, '' as atasament, citit, arhivat, descarcat from anaf_spv ] + ;
*!*				IIF(!EMPTY(m.tnArhivat) and m.tnArhivat = 1, "", "where arhivat=0")
*!*			llSucces = goExecutor.oExecuta(m.lcSql, 'cMesajeSPVTemp')
		
*!*			SELECT cMesajeSPV
*!*			APPEND FROM DBF('cMesajeSPVTemp')
*!*			INDEX on ID TAG Id DESCENDING  
*!*			USE IN (SELECT('cMesajeSPVTemp'))

		Local loFrmSPV As "anaf_spv"
		Local lcFiltru, lcFiltruOriginal, lcGroup, lcOrder, lcSchema, lcSelect, llAfisare, llModParam
		PRIVATE poMesaje

		lcSelect=[select 0 as ales, id, detalii, cif, data_creare, id_solicitare, tip, '' as atasament, citit, arhivat, descarcat from anaf_spv]
		lcFiltru=[arhivat=0]
		lcSchema=[ales N(1), id V(32), detalii V(250) null, cif V(20) null, data_creare T null, id_solicitare V(32) null, tip V(50) null, atasament W null, citit N(1), arhivat N(1), descarcat N(1)]
		lcOrder=[data_creare desc]
		llAfisare=.F.
		lcGroup = []
		llModParam = .T.
		lcFiltruOriginal = []
		poMesaje = null 
		gencursor('poMesaje','cMesajeSPV', m.lcSelect, m.lcFiltru, m.lcSchema, m.lcOrder, m.llAfisare, m.lcGroup, m.llModParam, m.lcFiltruOriginal)
		poMesaje.ca_baza1.afisare()
		
		SELECT cMesajeSPV
		loFrmSPV = CREATEOBJECT("anaf_spv", This)
		loFrmSPV.Show(1)

		USE IN (SELECT('cMesajeSPV '))
	ENDPROC && VizSPV
	
	*****************
	* Citeste lista de mesaje din SPV si salveaza in baza de date
	*****************
	PROCEDURE GetSPV
	
		Local loHTTP As "MSXML2.XMLHTTP"
		Local lcCIF, lcDetaliiMesaj, lcErrorMessage, lcIdMesaj, lcIdSolicitare, lcMesaj, lcResponse, lcTip
		Local llSucces, loEx, loJson, loMesaj, ltDataCreare
		LOCAL lcCodFiscal, lcURL, lnZile, lcZile, loEx as Exception

		DECLARE INTEGER InternetSetOption IN "wininet.dll" ;
	    INTEGER hInternet, INTEGER dwOption, STRING lpBuffer, INTEGER dwBufferLength

		#DEFINE INTERNET_OPTION_END_BROWSER_SESSION 42

		* Clear SSL cache by ending the browser session
		=InternetSetOption(0, INTERNET_OPTION_END_BROWSER_SESSION, 0, 0)

		lnZile = 1000
		lcZile = ALLTRIM(STR(m.lnZile))
		lcCodFiscal = ALLTRIM(NVL(This.cCodFiscal, ''))
		lcURL = "https://webserviced.anaf.ro/SPVWS2/rest/listaMesaje?zile=" + m.lcZile + "&cif=" + m.lcCodFiscal
		
		llSucces = .F.
		TRY 
			loHTTP = Createobject("MSXML2.XMLHTTP")
			loHTTP.Open("GET", lcURL , .F.)
			loHTTP.setRequestHeader("content-type", "text/plain")
			loHTTP.Send()
			llSucces = .T.
		CATCH TO loEx
			This.cErrorMessage = loEx.message
			This.lError = .T.				
		ENDTRY 
	    llSucces = .T.
		lcMesaj = ''
		* Verificam statusul raspunsului
		IF TYPE('loHttp') = 'O' AND loHttp.Status <> 200
		    * Daca cererea HTTP a esuat
		    lcMesaj = "Eroare la conectarea la server: " + TRANSFORM(loHttp.Status)
			This.cErrorMessage = m.lcMesaj
			This.lError = .T.			    
			llSucces = .F.
		ENDIF
		
	    * Preluam raspunsul JSON
		IF m.llSucces
		    lcResponse = loHttp.ResponseText
			IF ATC('<head>', m.lcResponse) > 0
				llSucces = .F.
				DO CASE 
					CASE ATC('utilizator neautorizat', m.lcResponse) > 0
						lcMesaj = 'Utilizator neautorizat. Posibile cauze: parola eronata sau certificat fara drepturi.'
					CASE ATC('certificatul nu a fost prezentat', m.lcResponse) > 0
						lcMesaj = 'Certificatul nu a fost prezentat.'
						
					OTHERWISE 
						lcMesaj = 'Eroare certificat'
				ENDCASE 
				This.cErrorMessage = m.lcMesaj
				This.lError = .T.				
			ENDIF 
		ENDIF 	
						
		IF m.llSucces	
		    * Transformam raspunsul JSON intr-un obiect FoxPro
			TRY 
				loJson = nfjsonread(m.lcResponse)
			CATCH TO loEx
				llSucces = .F.
				lcErrorMessage = 'GetSPV ' + LF + ' Eroare: ' + TRANSFORM(loEx.ErrorNo) + ' ' + loEx.Message + ' Continut:' + loEx.LineContents +   + ' Linia: ' + TRANSFORM(loEx.LineNo) + ' Program: ' + loEx.Procedure
				This.cErrorMessage = m.lcErrorMessage
				This.lError = .T.
				This.Log(m.lcErrorMessage)
			ENDTRY 

		    * Verificam daca exista mesaje disponibile
		    IF TYPE("loJson.mesaje") <> "U"
		        * Daca avem mesaje, le salvam intr-un array
*!*			        laMesaje = loJson.mesaje
*!*			        lnMesajeCount = ALEN(laMesaje, 1)

		        * Iteram prin lista de mesaje si descarcam fiecare mesaj
		        lnMesaje = 0
		        FOR EACH loMesaj IN loJson.mesaje 
		        	lnMesaje = lnMesaje + 1
		        	*i = 1 TO lnMesajeCount
*!*			            lcIdMesaj = laMesaje[i].id
*!*			            lcDetaliiMesaj = laMesaje[i].detalii
		            lcIdMesaj = loMesaj.id
		            lcDetaliiMesaj = loMesaj.detalii		            
					lcTip = loMesaj.tip
					lcCIF = loMesaj.cif
					ltDataCreare = CTOT(loMesaj.data_creare)
					lcIdSolicitare = loMesaj.id_solicitare
		        	WAIT WINDOW 'Mesaj: ' + ALLTRIM(STR(m.lnMesaje)) + ' ' + m.lcTip NOWAIT 
		        	
					llSucces = This.UpdateDbSPV(m.loMesaj)
*!*						IF !SEEK(m.lcIdMesaj, 'cMesajeSPV', 'id')
*!*												
*!*							INSERT INTO cMesajeSPV (id, detalii, tip, cif, data_creare, id_solicitare) VALUES (m.lcIdMesaj, m.lcDetaliiMesaj, m.lcTip, m.lcCIF, m.ltDataCreare, m.lcIdSolicitare)
*!*							SELECT cMesajeSPV
*!*							IF SEEK(m.lcIdMesaj)
*!*								SCATTER NAME loMesaj MEMO 
*!*								llSucces = This.UpdateDbSPV(m.loMesaj)
*!*							ENDIF 	
*!*						ENDIF                   
		        ENDFOR
*!*			        GO TOP IN cMesajeSPV
	        	WAIT WINDOW ALLTRIM(STR(m.lnMesaje)) + ' mesaje verificate/adaugate'  NOWAIT 
		    ELSE
		        * Daca nu exista mesaje
		        lcMesaj = "Nu exista mesaje disponibile in ultimele " + lcZile + " zile."
		    ENDIF
		ENDIF && llSucces   
		
		IF !This.lServer AND !EMPTY(This.cErrorMessage)
			AMESSAGEBOX(This.cErrorMessage, 0+48, _screen.Caption)
		ENDIF 
			
		RETURN m.llSucces

	ENDPROC && GetSPV
	
	***************************
	* Salveaza un mesaj SPV in baza de date anaf_spv
	***************************
	PROCEDURE UpdateDbSPV
		LPARAMETERS toMesaj
		
		Local lcSql, llSucces
		PRIVATE pcCIF, pcDetalii, pcId, pcIdSolicitare, pcTip, ptDataCreare

		TEXT TO lcSql NOSHOW 
		merge into anaf_spv a using dual b ON (a.id = ?pcId)
			when not matched then
			INSERT (id, detalii, tip, cif, data_creare, id_solicitare) VALUES (?pcId, ?pcDetalii, ?pcTip, ?pcCIF, ?ptDataCreare, ?pcIdSolicitare)
		ENDTEXT 
		WITH toMesaj
			pcId = ALLTRIM(.id)
			pcDetalii = ALLTRIM(.detalii)
			pcTip = ALLTRIM(.tip)
			pcCIF = ALLTRIM(.cif)
			ptDataCreare = CTOT(.data_creare)
			pcIdSolicitare = ALLTRIM(.id_solicitare)
		ENDWITH 
		
		llSucces = goExecutor.oExecuta(m.lcSql)
		IF !m.llSucces
			goLog.Log(NVL(pcId, '') + ' ' + NVL(pcTip, '') + ' ' + NVL(pcCIF, '') + ' ' + TRANSFORM(NVL(ptDataCreare, {})) + ' ' + NVL(pcIdSolicitare, '') + ' ' + NVL(pcDetalii, ''))
			SET STEP ON 
		ENDIF 
		RETURN m.llSucces
	ENDPROC && UpdateDbSPV
	
	***************************
	* Salveaza atasamentul pentru un mesaj SPV in baza de date anaf_spv
	***************************	
	PROCEDURE UpdateDbSPVFile
		PARAMETERS tcIdMesaj, tcContinut, tcFileName
		* tcIdMesaj: Id mesaj SPV
		* tcContinut: continutul pdf/zip mesaj
		
		Local lcSql, llSucces

		lcSql = [UPDATE anaf_spv SET atasament = ?tcContinut, filename = ?tcFileName, descarcat = 1 WHERE id = ?tcIdMesaj]
		
		llSucces = goExecutor.oExecuta(m.lcSql)	
		IF !m.llSucces
			goLog.Log(TRANSFORM(NVL(tcContinut, '')) + ' ' + TRANSFORM(NVL(tcIdMesaj, '')) + ' ' + TRANSFORM(m.tcFileName))
			SET STEP ON 
		ENDIF		
		RETURN m.llSucces
	ENDPROC && UpdateDbSPVFile
	
	****************
	* Actualizeaza anaf_spv.citit, descarcat, arhivat
	****************
	PROCEDURE UpdateSPV	
		LPARAMETERS tcIdMesaj, tcAtribut, tnValoare
		
		lcSql = [update anaf_spv set ] + m.tcAtribut + [ = ] + ALLTRIM(STR(m.tnValoare)) + [ where id = ] + ALLTRIM(m.tcIdMesaj)
		llSucces = goExecutor.oExecuta(m.lcSql)	
		RETURN m.llSucces
	ENDPROC 
	 
	*****************
	* Descarca atasamentul pdf al unui mesaj din SPV si il salveaza pe disc
	*****************
	PROCEDURE DescarcaDetaliiSPV
		LPARAMETERS tcIdMesaj
		* tnIdMesaj (optional): Id mesaj, altfel se descarca mesajele cMesajeSPV.ales = 1
		* ttDataCreare, tcTip (optional): pentru numele fisierului
		
		Local loHTTP As "MSXML2.XMLHTTP"
		Local lcDirectory, lcIdMesaj, lcPdfData, lcPdfFileName, lcRecc, lcUrlDescarcare
		Local lcData, lcDataCreare, lcExtensie, lcFileName, lcFiltru, lcTip, llSucces, lcIdMesaj
		
		lcIdMesaj = IIF(!EMPTY(m.tcIdMesaj), ALLTRIM(m.tcIdMesaj), '')


*!*			******************
*!*			DECLARE INTEGER InternetSetOption IN "wininet.dll" ;
*!*		    INTEGER hInternet, INTEGER dwOption, STRING lpBuffer, INTEGER dwBufferLength

*!*			#DEFINE INTERNET_OPTION_END_BROWSER_SESSION 42
*!*			* Clear SSL cache by ending the browser session
*!*			=InternetSetOption(0, INTERNET_OPTION_END_BROWSER_SESSION, 0, 0)
*!*			******************
		IF this.lServer
			lcDirectory = This.cResponsesPath + 'SPV' + '\' + Dtos(Date()) + '\'
		ELSE
			lcDirectory = GetPdfPath('SPV')
		ENDIF 
		
		lcFiltru = 'descarcat = 0'
		DO CASE 
			CASE !EMPTY(m.lcIdMesaj)
				lcFiltru = 'id = lcIdMesaj'
			OTHERWISE 
				SELECT * FROM cMesajeSPV WHERE ales = 1 INTO CURSOR cMesajeSelectateTemp
				IF _tally > 0
					lcFiltru = 'ales = 1'
				ENDIF 
				USE IN (SELECT('cMesajeSelectateTemp'))
		ENDCASE 		
		
		SELECT * FROM cMesajeSPV WHERE &lcFiltru INTO CURSOR cMesajeTemp NOFILTER 
		
		lcRecc = TRANSFORM(RECCOUNT('cMesajeTemp'))

		llSucces = .F.
		TRY 
			loHTTP = Createobject("MSXML2.XMLHTTP")
			llSucces = .T.
		CATCH TO loEx
			This.cErrorMessage = loEx.message
			This.lError = .T.		
			IF !This.lServer
				AMESSAGEBOX('Eroare ' + This.cErrorMessage,0+48, _Screen.Caption)
			ENDIF
		ENDTRY 
		
		IF m.llSucces AND TYPE('loHttp') = 'O'
			This.lError = .F.
		    SELECT cMesajeTemp
		    SCAN 
		    	lcIdMesaj = ALLTRIM(id)
		    	lcDataCreare = TTOC(data_creare,1)
		    	lcTip = ALLTRIM(tip)
		    	lcDetalii = ALLTRIM(detalii)
				llSucces = .T.	    	
		
		    	WAIT WINDOW TRANSFORM(RECNO()) + '/' + m.lcRecc NOWAIT 
		    	
			    * Construim URL-ul pentru descarcarea mesajului
			    lcUrlDescarcare = "https://webserviced.anaf.ro/SPVWS2/rest/descarcare?id=" + m.lcIdMesaj
			    
			    * Facem cererea pentru descarcarea mesajului PDF
			    
			    llSucces = .F.
			    TRY 
				    loHttp.Open("GET", m.lcUrlDescarcare, .F.)
				    loHttp.Send()
				    llSucces = .T.
				CATCH TO loEx
					This.cErrorMessage = loEx.message
					This.lError = .T.				
					IF !This.lServer
						AMESSAGEBOX('Eroare ' + This.cErrorMessage,0+48, _Screen.Caption)
					ENDIF 	
				ENDTRY  

			    * Verificam statusul descarcarii
			    IF m.llSucces AND loHttp.Status = 200
			    
				    * Verific daca raspunsul contine un mesaj de eroare in html
				    lcResponse = loHttp.ResponseText
					DO CASE 
					CASE ATC('<head>', m.lcResponse) > 0
						llSucces = .F.
						DO CASE 
							CASE ATC('utilizator neautorizat', m.lcResponse) > 0
								lcMesaj = 'Utilizator neautorizat. Posibile cauze: parola eronata sau certificat fara drepturi.'
							CASE ATC('certificatul nu a fost prezentat', m.lcResponse) > 0
								lcMesaj = 'Certificatul nu a fost prezentat.'
								
							OTHERWISE 
								lcMesaj = 'Eroare certificat'
						ENDCASE 
						This.cErrorMessage = m.lcMesaj
						This.lError = .T.
						WAIT WINDOW "Eroare la descarcarea mesajului " + m.lcIdMesaj + ' : ' + m.lcMesaj NOWAIT 
						IF !This.lServer
							AMESSAGEBOX("Eroare la descarcarea mesajului " + m.lcIdMesaj + ' : ' + m.lcMesaj + '!',0+48,_Screen.Caption)
							EXIT 
						ENDIF
					CASE LEFT(m.lcResponse, 1) = "{"
*!*							{"titlu":"Descarcare mesaj","eroare":"A aparut o eroare tehnica. Cod: 2000"}	 	
						lcMesaj = GetRegExp(m.lcResponse, '(?<="eroare":")[^"]+', 1)
						This.cErrorMessage = m.lcMesaj
						This.lError = .T.
						WAIT WINDOW "Eroare la descarcarea mesajului " + m.lcIdMesaj + ' : ' + m.lcMesaj NOWAIT 
						IF !This.lServer
							AMESSAGEBOX("Eroare la descarcarea mesajului " + m.lcIdMesaj + ' : ' + m.lcMesaj + '!',0+48,_Screen.Caption)
							EXIT 
						ENDIF
				    OTHERWISE 
				        * Obtinem continutul PDF/ZIP
				        lcResponse  = loHttp.ResponseBody			        				
					ENDCASE 


			        * Salvam fisierul PDF/zip pe disc
			        *detalii: recipisa pentru CIF 1879855, tip D300, numar_inregistrare INTERNT-767970463-2024/16-08-2024, perioada raportare 7.2024
			        lcTipD =  GetRegExp(m.lcDetalii, ", tip ([^,]+)", 1) && obtin Tip declaratie ",tip D300,"
			        lcTipD = ALLTRIM(STRTRAN(m.lcTipD, ", tip", "",1,1,1))
			        lcTipD = IIF(!EMPTY(m.lcTipD), '_' + ALLTRIM(m.lcTipD), '')

			        lcPerioadaR = GetRegExp(m.lcDetalii, "perioada raportare (\d+\.\d+)", 1) && perioada raportare "7.2024"
			        lcPerioadaR = ALLTRIM(STRTRAN(m.lcPerioadaR, "perioada raportare", "",1,1,1))
			        lcPerioadaR = IIF(!EMPTY(m.lcPerioadaR), '_' + ALLTRIM(m.lcPerioadaR), '')
			        
			        lcExtensie = IIF(This.lError, 'html', IIF(LOWER(LEFT(loHttp.responseText, 4)) = '%pdf', 'pdf', 'zip'))
			        lcFileName = m.lcDirectory + "mesaj_spv_" + m.lcIdMesaj + "_" + m.lcDataCreare + "_" + m.lcTip + m.lcTipD + m.lcPerioadaR + "." + m.lcExtensie
			        	
			        STRTOFILE(m.lcResponse, m.lcFileName, 0)
			        IF m.llSucces
				        * Salvez atasamentul in baza de date
				        llSucces = This.UpdateDbSPVFile(m.lcIdMesaj, m.lcResponse, JUSTFNAME(m.lcFileName))
				    ENDIF     
			        IF m.llSucces
			        	UPDATE cMesajeSPV SET descarcat = 1 WHERE id = m.lcIdMesaj
			        ENDIF 
			        * Afisam un mesaj de succes
			        WAIT WINDOW "Mesajul " + m.lcIdMesaj + " descarcat cu succes: " + m.lcFileName NOWAIT
			    ELSE
			        * Daca apare o eroare la descarcare, afisam mesajul de eroare
			        WAIT WINDOW "Eroare la descarcarea mesajului " + m.lcIdMesaj NOWAIT
			    ENDIF
			ENDSCAN && cMesajeTemp  
		ENDIF && llSucces	
		
		USE IN (SELECT('cMesajeTemp'))

		IF !This.lServer	
			open_default_app(m.lcDirectory)
		ENDIF 	
	
	ENDPROC && DescarcaDetaliiSPV
	
	*************
	* Deschide directorul cu atasamente SPV si atasamentul dorit, dupa id mesaj
	*************
	PROCEDURE DeschideAtasamentSPV
		LPARAMETERS tcIdMesaj

		PRIVATE pcIdMesaj
		Local laFiles[1], lcDirectory, lcFile, lcFileSkeleton, lcFiltru, lcFiltruOriginal, lcFisier, lcId
		Local lcOrder, lcSchema, lcSelect, lcgroup, llAfiseaza, llModParam, lnFile, lnFiles

		pcIdMesaj = tcIdMesaj
		
		IF this.lServer
			lcDirectory = This.cResponsesPath + 'SPV' + '\' + Dtos(Date()) + '\'
		ELSE
			lcDirectory = GetPdfPath('SPV')
		ENDIF 
		lcDirectory = ADDBS(m.lcDirectory)
		
		lcFileSkeleton = m.lcDirectory + '*' + ALLTRIM(m.tcIdMesaj) + '*.*'
		lnFiles = ADIR(laFiles, m.lcFileSkeleton)
		IF m.lnFiles > 0
			open_default_app(m.lcDirectory)

			FOR lnFile = 1 TO m.lnFiles
				lcFile = m.lcDirectory + laFiles[m.lnFile,1]
				IF FILE(m.lcFile)
					open_default_app(m.lcFile)
				ENDIF 
			ENDFOR 
		ELSE
			* daca nu sunt fisiere pe disk, descarc din baza de date
			PRIVATE poDetaliiZip
			poDetaliiZip = null
				
			lcSchema = [id V(36), fisier W, filename V(100)]
			lcSelect = [select id, atasament, filename from anaf_spv where id = ?pcIdMesaj]
			lcOrder = []
			lcgroup = []
			lcFiltru = []
			lcFiltruOriginal = []
			llModParam = .T.
			llAfiseaza = .F.

			gencursor('poDetaliiZip','cRegFisierTemp', lcSelect, lcFiltru, lcSchema, lcOrder, llAfiseaza,  lcgroup, llModParam, lcFiltruOriginal)
			poDetaliiZip.ca_baza1.afisare()
			If Used('cRegFisierTemp')
				lcId= ALLTRIM(NVL(id, ''))
				lcFisier = fisier
				lcFileName = IIF(!EMPTY(NVL(filename, '')), ALLTRIM(NVL(filename, '')), m.pcIdMesaj + '.pdf')
				Use In (Select('cRegFisierTemp'))

				lcFile = PUTFILE('Fisier', m.lcFileName, JUSTEXT(m.lcFileName))
				IF !EMPTY(m.lcFile)
					Strtofile(lcFisier, m.lcFile)
					open_default_app(JUSTPATH(m.lcFile))
					open_default_app(m.lcFile)					
				ENDIF 	
			Endif		
		ENDIF 			
		
	ENDPROC && DeschideAtasamentSPV
	
Enddefine && ANAFeFacturaServer

Procedure viz_borderou_efactura
	LOCAL loAnafeFactura 
	If !m.glEfactura
		AMESSAGEBOX('Trebuie activata functionalitatea eFactura!', 0 + 48, _Screen.Caption)
		Return
	Endif
*	gcAcces = [1;2;3;4;5;6]
	loAnafeFactura = Createobject("ANAFeFactura")
	loAnafeFactura.vizeFactura()
ENDPROC

*****************************
PROCEDURE viz_efactura_xml
	LOCAL loAnafeFactura 

	loAnafeFactura = CREATEOBJECT("AnafeFacturaServer")
	loAnafeFactura.vizeFacturaXml()
ENDPROC && viz_efactura_xml

*****************************
PROCEDURE viz_spv

	LOCAL loAnafeFactura 
	loAnafeFactura = CREATEOBJECT("AnafeFacturaServer")
	loAnafeFactura.VizSPV()
ENDPROC && viz_spv

Define Class ANAFeFactura As Custom

	AnafeFacturaServer = null
	
	token = ''
	refresh_token = ''
	token_gendate = {}
	token_expdate = {}
	codfiscal = '' && cod fiscal contribuabil fara atribut fiscal
	lTest = .F. && .T. = transmite eFactura TEST
	cResponsesPath = ''
		
	Procedure Init
		this.AnafeFacturaServer = Createobject('AnafeFacturaServer')
		
		This.codfiscal = IIF(TYPE('goFirma') = 'O', gofirma.codfiscalfro, '')         
		This.cResponsesPath = GetPdfPath('EFACTURA') && ADDBS(m.gcEFACTURA_RESPONSESPATH) && RASPUNSURI daca se descarca automat cu ROAEFACTURA
		
	Endproc && Init

	Procedure vizeFactura
		Local lcToken
		Local loFrmBorderou As "frm_borderou_efactura"
		Local lcFiltru, lcFiltruOriginal, lcOrder, lcSchema, lcSelect, lcgroup, llAfiseaza, llModParam, lcData1, lnInregistrariAfisare 
		Local lcSqlCount, llSucces
		Private poFacturiEmise, poFacturiPrimite, poFacturiTrimise, poFacturiDetalii, pnRecCnt
		poFacturiEmise = Null
		poFacturiPrimite = Null
		poFacturiTrimise = Null
		poFacturiDetalii = Null

		lcToken = This.getToken()
		If Empty(m.lcToken)
			AMESSAGEBOX('Nu s-a obtinut token-ul eFactura!', 0 + 48, _Screen.Caption)
		Endif

		* La facturi primite/trimise aduc 0 inregistrari. 
		* Afisez inregistrarile la prima activare a paginilor Trimise/Primite din Borderou
		* Nu aduc coloana ANAF_EFACTURA.DETALII (xml efactura) pentru ca este prea mult trafic de date si merge greu pentru multe inregistrari. Aduc detalii doar pentru cate o factura
		
		* FACTURI PRIMITE
		lcData1 = '01' + PADL(INT(m.gnLuna),2,'0') + ALLTRIM(STR(m.gnAn))
		Text To lcSchema Noshow
ales N(1), id N(20), id_fact N(20), data_act D, data_scad D, numar_act C(30), xfurnizor C(200), xclient C(200), id_incarcare C(36), id_descarcare c(36) null, tip_mesaj_raspuns C(50) null,mesaj_raspuns C(250) null, data_raspuns D null, trimis N(1) null, data_trimis T null, cod_fiscal_emitent C(30) null, cod_fiscal_beneficiar C(30) null, detalii M null, total_fara_tva N(16,4), total_tva N(16,4), total_tva_ron N(16,4), total_cu_tva N(16,4), discount_fara_tva N(16,4), taxe_fara_tva N(16,4), valoare_fara_tva N(16,4), total_de_plata N(16,4), nume_valuta C(5), test N(1) null, jtotctva N(16,4) null, descriere M null, detalii_plata M null, diferenta N(16,4) null, procesat N(1), tip_persoana N(1) null, descarcat N(1) null, filepath c(250) null, procesat_server N(1) null, creditnote N(1)
		Endtext
		Text To lcSelect Noshow
SELECT 0 as ales, id, id_fact, data_act, data_scad, numar_act, xfurnizor, xclient, id_incarcare, id_descarcare, tip_mesaj_raspuns, mesaj_raspuns, data_raspuns, NVL(trimis,0) as trimis, data_trimis, cod_fiscal_emitent, cod_fiscal_beneficiar, '' as detalii, total_fara_tva, total_tva, total_tva_ron, total_cu_tva, discount_fara_tva, taxe_fara_tva, valoare_fara_tva, total_de_plata, nume_valuta, test, jtotctva, descriere, detalii_plata, case when jtotctva is null then null when NVL(nume_valuta,'RON') <> 'RON' then null else decode(creditnote,0,1,-1) * NVL(total_cu_tva, 0.00)-(NVL(jtotctva, 0.00)-NVL(jtva_ti, 0.00)) end as diferenta, procesat, tip_persoana, descarcat, filepath, procesat_server, creditnote FROM anaf_vefactura_primit
		Endtext
		lcOrder = [data_act,numar_act,data_raspuns]
		lcgroup = []
		* Aduc inregistrarile cand se activeaza prima data pagina cu facturi primite
		lcFiltru = [1=2] && [(extract(year from data_act) = ?gnAn and extract(month from data_act) = ?gnLuna) or (data_act is null and data_raspuns >= to_date('] + m.lcData1 + [','ddmmyyyy'))]	
		lcFiltruOriginal = []
		llModParam = .T.
		llAfiseaza = .F.

		gencursor('poFacturiPrimite', 'crsFacturiPrimite', lcSelect, lcFiltru, lcSchema, lcOrder, llAfiseaza,  lcgroup, llModParam, lcFiltruOriginal)
		poFacturiPrimite.ca_baza1.afisare()
		Select crsFacturiPrimite
		Go Top

		* FACTURI TRIMISE
		Text To lcSchema Noshow
ales N(1), id N(20), id_fact N(20), data_act D, data_scad D, numar_act C(30), xfurnizor C(200), xclient C(200), id_incarcare C(36), id_descarcare c(36) null, mesaj_trimis C(250) null, tip_mesaj_raspuns C(50) null,mesaj_raspuns C(250) null, data_raspuns D null, trimis N(1) null, data_trimis T null, cod_fiscal_emitent C(30) null, cod_fiscal_beneficiar C(30) null, detalii M null, total_fara_tva N(16,4), total_tva N(16,4), total_tva_ron N(16,4), total_cu_tva N(16,4), discount_fara_tva N(16,4), taxe_fara_tva N(16,4), valoare_fara_tva N(16,4), total_de_plata N(16,4), nume_valuta C(5), test N(1) null, jtotctva N(16,4) null, descriere M null, detalii_plata M null, diferenta N(16,4) null, procesat N(1), tip_persoana N(1) null, descarcat N(1) null, filepath c(250) null, procesat_server N(1) null, creditnote N(1)
		Endtext
		Text To lcSelect Noshow
SELECT 0 as ales, id, id_fact, data_act, data_scad, numar_act, xfurnizor, xclient, id_incarcare, id_descarcare, mesaj_trimis, tip_mesaj_raspuns, mesaj_raspuns, data_raspuns, NVL(trimis,0) as trimis, data_trimis, cod_fiscal_emitent, cod_fiscal_beneficiar, '' as detalii, total_fara_tva, total_tva, total_tva_ron, total_cu_tva, discount_fara_tva, taxe_fara_tva, valoare_fara_tva, total_de_plata, nume_valuta, test, jtotctva, descriere, detalii_plata, case when jtotctva is null then null when NVL(nume_valuta,'RON') <> 'RON' then null else decode(creditnote,0,1,-1) * NVL(total_cu_tva, 0.00)-NVL(jtotctva, 0.00) end as diferenta, procesat, tip_persoana, descarcat, filepath, procesat_server, creditnote FROM anaf_vefactura_trimis
		Endtext
		lcOrder = [data_act,numar_act,data_trimis,data_raspuns]
		lcgroup = []
		* Aduc inregistrarile cand se activeaza prima data pagina cu facturi trimise
		lcFiltru = [1=2] && [(extract(year from data_act) = ?gnAn and extract(month from data_act) = ?gnLuna) or (data_act is null and data_raspuns >= to_date('] + m.lcData1 + [','ddmmyyyy'))]	
		lcFiltruOriginal = []
		llModParam = .T.
		llAfiseaza = .F.

		gencursor('poFacturiTrimise', 'crsFacturiTrimise', lcSelect, lcFiltru, lcSchema, lcOrder, llAfiseaza,  lcgroup, llModParam, lcFiltruOriginal)
		poFacturiTrimise.ca_baza1.afisare()
		Select crsFacturiTrimise
		Go Top

		*!* diferenta ramane goala cand factura nu e in Registrul de Vanzari, ca la facturile primite/trimise
		* FACTURI EMISE
		Text To lcSchema Noshow
ales N(1), id N(20), id_fact N(20), id_vanzare N(10), data_act D, numar_act N(14), in_valuta N(1) null, curs N(10,4) null, valval N(16,2), tvaval N(16,2),totval N(16,2), total_fara_tva N(16,2), total_tva N(16,2), total_cu_tva N(16,2), nume_valuta C(5) null, client C(100), id_client N(10), cod_fiscal C(30), tip_persoana N(1) null, trimis N(1) null, data_trimis T null, stare C(100) null, id_incarcare C(36) null, mesaj_trimis C(250) null, id_descarcare c(36) null, tip_mesaj_raspuns C(50) null,mesaj_raspuns C(250) null, data_raspuns D null, cod_fiscal_emitent C(30) null, cod_fiscal_beneficiar C(30) null, detalii M null, xfurnizor C(200), xclient C(200), xdata_act D, xnumar_act C(30), xtotal_fara_tva N(16,4), xtotal_tva N(16,4), xtotal_tva_ron N(16,4), xtotal_cu_tva N(16,4), xdiscount_fara_tva N(16,4), xtaxe_fara_tva N(16,4), xvaloare_fara_tva N(16,4), xtotal_de_plata N(16,4), xnume_valuta C(5), test N(1) null, id_util N(10), utilizator C(100), jtotctva N(16,4) null, diferenta N(16,4) null, procesat  N(1), procesat_server N(1), creditnote N(1)
		Endtext
		Text To lcSelect Noshow
SELECT 0 as ales, id, id_fact, id_vanzare, data_act, numar_act, in_valuta, curs, valval, tvaval, totval, total_fara_tva, total_tva,total_cu_tva, nume_valuta, client, id_client, cod_fiscal, NVL(tip_persoana,1) as tip_persoana, NVL(trimis,0) as trimis, data_trimis, stare, id_incarcare, mesaj_trimis, id_descarcare, tip_mesaj_raspuns, mesaj_raspuns, data_raspuns, cod_fiscal_emitent, cod_fiscal_beneficiar, '' as detalii, xfurnizor, xclient, xdata_act, xnumar_act, xtotal_fara_tva, xtotal_tva, xtotal_tva_ron, xtotal_cu_tva, xdiscount_fara_tva, xtaxe_fara_tva, xvaloare_fara_tva, xtotal_de_plata, xnume_valuta, test, id_util, utilizator, jtotctva, case when jtotctva is null then null else decode(creditnote,0,1,-1) * ROUND(NVL(xtotal_cu_tva , 0.00) * decode(in_valuta,1,curs,1), 2)-NVL(jtotctva, 0.00) end as diferenta, procesat, procesat_server,creditnote FROM anaf_vefactura_emis
		Endtext
		lcOrder = [data_act,numar_act]
		lcgroup = []
		lcFiltru = [(extract(year from data_act)=?gnAn and extract(month from data_act)=?gnLuna) OR (trimis = 1 and tip_mesaj_raspuns is null and extract(year from data_act) >=2023)]	
		lcFiltruOriginal = []
		llModParam = .T.
		llAfiseaza = .F.
		
		* Afisez toate facturile emise, ca sa le pot vizualiza pe cele netrimise sau trimise cu starea lor (trimis, eroare etc.)
		gencursor('poFacturiEmise', 'crsFacturiEmise', lcSelect, lcFiltru, lcSchema, lcOrder, llAfiseaza,  lcgroup, llModParam, lcFiltruOriginal)
		poFacturiEmise.ca_baza1.afisare()


* DETALII FACTURI PRIMITE/TRIMISE/EMISE
		Text To lcSchema Noshow
id  N(20), id_efactura N(20), nr N(5), articol V(250), descriere V(250), detalii M, cantitate N(18,6), um V(20), pret N(20,6), proctva N(7,2), valoarefaratva N(20,6), discountfaratva N(20,6)
		Endtext
		Text To lcSelect Noshow
select id, id_efactura, nr, articol, descriere, detalii, cantitate, um, pret, proctva, valoarefaratva, discountfaratva from anaf_vefactura_detalii
		Endtext
		lcOrder = [nr]
		lcgroup = []
		lcFiltru = [1=2] && IIF(!EMPTY(NVL(crsFacturiPrimite.id,0)), [id_efactura=] + ALLTRIM(STR(crsFacturiPrimite.id)), [1=2])
		lcFiltruOriginal = []
		llModParam = .T.
		llAfiseaza = .F.

		gencursor('poFacturiDetalii', 'crsDetaliiFacturi', lcSelect, lcFiltru, lcSchema, lcOrder, llAfiseaza,  lcgroup, llModParam, lcFiltruOriginal)
		poFacturiDetalii.ca_baza1.afisare()


		Select crsFacturiEmise
		loFrmBorderou = Createobject("anaf_efactura", This)
		* Do Form anaf_efactura Name loFrmBorderou Linked With this Noshow

		loFrmBorderou.Show(1)

		Use In (Select('crsFacturiEmise'))
		Use In (Select('crsFacturiTrimise'))		
		Use In (Select('crsFacturiPrimite'))
		Use In (Select('crsDetaliiFacturi'))
	Endproc && vizeFactura

	Function getToken
		Lparameters tlShow
* tlShow: .T. arata formularul chiar daca este generat Token si nu este expirat 90 zile
		Private poToken

		Local loFrmToken As "anaf_token"
		Local lcToken, lcRefreshToken, lcTokenGenDate, ldTokenGenDate, loServer
 
		loServer = This.AnafeFacturaServer 

		* TokenJWT are dimensiunea mai mare. Il salvez in optiuni.varvalue2
		IF .F.
			lcToken = Alltrim(Nvl(citeste_optiune('ANAF_TOKEN', .T.), ''))	
			lcRefreshToken = Alltrim(Nvl(citeste_optiune('ANAF_REFRESH_TOKEN', .T.), ''))
			
			lcTokenGenDate = Alltrim(Nvl(citeste_optiune('ANAF_TOKEN_GENDATE'), ''))
			ldTokenGenDate = Iif(!Empty(m.lcTokenGenDate), Ctod(m.lcTokenGenDate), {})
			lcTokenExpDate = Alltrim(Nvl(citeste_optiune('ANAF_TOKEN_EXPDATE'), ''))
			ldTokenExpDate = Iif(!Empty(m.lcTokenExpDate), Ctod(m.lcTokenExpDate), {})
			ldTokenExpDate = Iif(!Empty(m.ldTokenExpDate), m.ldTokenExpDate, m.ldTokenGenDate + 90)
		ELSE 
			lcToken = loServer.cToken
			lcRefreshToken = loServer.cRefreshToken
			ldTokenGenDate = loServer.dTokenGendate
			ldTokenExpDate = loServer.dTokenExpdate
		ENDIF 

		This.token = m.lcToken
		This.refresh_token = m.lcRefreshToken
		This.token_gendate = m.ldTokenGenDate
		This.token_expdate = m.ldTokenExpDate

		If m.tlShow Or Empty(m.lcToken) Or m.ldTokenExpDate <= Date()
			loFrmToken = Createobject("anaf_token", This)
			loFrmToken.Show(1)
			*!* 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
		
			This.SaveToken()
		Endif

		Return loServer.cToken
	Endfunc

***************************
* Salveaza tokenul in baza de date optiuni firma 
***************************
	Procedure SaveToken
		LOCAL loServer
 
		loServer = This.AnafeFacturaServer 
		loServer.SaveToken()
	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
		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
* Se apeleaza din formularul anaf_token.do_executa
	Function refreshToken
		LOCAL loServer, lcMesaj, llSucces
		llSucces = .F.

		loServer = This.AnafeFacturaServer 
		lcMesaj = ''
		llSucces = loServer.RefreshToken(@lcMesaj)
		
		AMESSAGEBOX(m.lcMesaj, 0 + 48, _Screen.Caption)

		Return m.llSucces
	Endfunc

********************************
* Bifeaza Trimis o factura trimisa manual la ANAF
********************************
	Procedure BifeazaTrimisManual
		Lparameters tnIdFact, tnTrimis
		Private pnIdFact, pnTrimis
		pnIdFact = m.tnIdFact
		pnTrimis = m.tnTrimis
		pnTest = IIF(This.lTest, 1, 0) && server TEST ANAF
		lcSql = 'begin pack_anaf.BifeazaEFactTrimisManual(?pnIdFact, ?pnTrimis, ?pnTest, ?gnIdUtil); end;'
		llSucces = goExecutor.oExecuta(m.lcSql)
		Return m.llSucces
	Endproc && BifeazaTrimisManual


	********************************
	* Suprascrie Id Incarcare manual, in caz ca pe factura este un Id Incarcare al trimiterilor ulterioare care au primit raspuns Eroare factura duplicata
	* Este posibil si ca la prima incarcare anaf.ro sa dea timeout si sa nu intoarca Id Incarcare si sa se trimita din nou factura. Se primeste id incarcare, dar mesajul de descarcare este EROARE factura duplicata.
	********************************
	Procedure SuprascrieIdIncarcare
		Lparameters tnIdFact, tcIdIncarcare
		Private pnIdFact, pcIdIncarcare
		pnIdFact = m.tnIdFact
		pcIdIncarcare = m.tcIdIncarcare
		pnTest = IIF(This.lTest, 1, 0) && server TEST ANAF
		lcSql = 'begin pack_anaf.SuprascrieIdIncarcare(?pnIdFact, ?pcIdIncarcare, ?pnTest, ?gnIdUtil); end;'
		llSucces = goExecutor.oExecuta(m.lcSql)
		Return m.llSucces
	Endproc && SuprascrieIdIncarcare


********************************
* Genereaza xml efactura, valideaza xml si trimite la API ANAF
********************************
	Procedure TrimiteFacturi
		Lparameters tlNuTrimiteEFacturaANAF

		Local lcTip, llSucces, lnValoare, lnRecno, loEx as Exception
		Local lcFilter, lcSql, lnIdVanzare
		Local lcRecc, lcRecno, ldDataFact, lnNumarFact, loReturn, lnTrimis
		Local lcMesaj
		Local lcErrorMessage, lcExecutionStatus, lcIndexIncarcare, loXML
		Private pnIdFact, pnValoare, pcMesajTrimis, pnTrimis, pcIdIncarcare, pnTest

		llSucces = .F.
		pnIdFact = crsFacturiEmise.id_fact
		pnTest = IIF(This.lTest, 1, 0) && server TEST ANAF
		lnRecno = Recno('crsFacturiEmise')
		lcFilter = "id_fact = " + Alltrim(Str(m.pnIdFact))

		Select crsFacturiEmise
		Locate For ales = 1
		If !Found()
			Locate For id_fact = m.pnIdFact
		Else
			lcFilter = "ales = 1"
		Endif

		If Empty(m.pnIdFact)
			Return m.llSucces
		Endif

		lcSql = 'begin pack_anaf.BifeazaEFactTrimis(?pnIdFact, ?pnTrimis, ?pcMesajTrimis, ?pcIdIncarcare, ?pnTest, ?gnIdUtil); end;'

		Select crsFacturiEmise
		lcRecc = Alltrim(Str(Reccount()))
		Scan For &lcFilter
			pnIdFact = id_fact
			lnIdVanzare = id_vanzare
			lnNumarFact = crsFacturiEmise.numar_act
			ldDataFact = crsFacturiEmise.data_act
			pnTrimis = Nvl(trimis, 0)
			lnTrimis = Nvl(trimis, 0)
			pcIdIncarcare = Nvl(id_incarcare, '')

			lcRecno = Alltrim(Str(Recno()))

			Wait Window 'Factura ' + Alltrim(Str(m.lnNumarFact)) + ' / ' + Dtoc(m.ldDataFact) + ' ' + m.lcRecno + '/' + m.lcRecc Nowait

			loReturn = This.TrimiteEfactura(m.lnIdVanzare, m.tlNuTrimiteEFacturaANAF)
			llSucces = loReturn.lSucces

			If m.llSucces
				pcMesajTrimis = Iif(This.lTest, 'TEST ', '')
				loXML = NULL
				IF !m.tlNuTrimiteEFacturaANAF
					TRY 
						loXML = nfxmlread(loReturn.cResponse)
					CATCH TO loEx
						lcErrorMessage = loEx.Message
					ENDTRY 	
				ENDIF 	
				lcExecutionStatus = ''
				lcIndexIncarcare = ''
				lcErrorMessage = ''
				IF TYPE('loxml.header._attr_.executionstatus') <> 'U'
					lcExecutionStatus = loxml.header._attr_.executionstatus
				ENDIF 	
				IF TYPE('loxml.header._attr_.index__incarcare') <> 'U'
					lcIndexIncarcare = loxml.header._attr_.index__incarcare
				ENDIF 
				IF TYPE('loxml.header.errors._attr_.errorMessage') <> 'U'
					lcErrorMessage = loxml.header.errors._attr_.errorMessage
				ENDIF 					
				
				Do Case
					Case lcExecutionStatus = "0"
						pcIdIncarcare = m.lcIndexIncarcare
						pnTrimis = 1
						pcMesajTrimis =  m.pcMesajTrimis + 'Transmis cu succes. Index incarcare = ' + m.pcIdIncarcare

					Case !EMPTY(m.lcErrorMessage)
						pcIdIncarcare = ''
						pnTrimis = 1
						pcMesajTrimis =  m.pcMesajTrimis + Iif(This.lTest, 'TEST ', '') + 'Eroare. ' + m.lcErrorMessage 
						
					Case [VALID] $ Upper(loReturn.cResponse)
						pcIdIncarcare = ''
						pnTrimis = 0
						pcMesajTrimis =  m.pcMesajTrimis + loReturn.cResponse
					Otherwise
						pcMesajTrimis = m.pcMesajTrimis + Iif(This.lTest, 'TEST ', '') + 'Eroare. ' + m.lcErrorMessage 
						pcIdIncarcare = ''
						pnTrimis = 1
				Endcase

				* Completez doar cu raspunsul de la trimiterea la ANAF, nu si de la validare
				If !m.tlNuTrimiteEFacturaANAF
					pcMesajTrimis = LEFT(m.pcMesajTrimis,250)
					llSucces = goExecutor.oExecuta(m.lcSql)
				Endif

				If [VALID] $ Upper(loReturn.cResponse) And m.lnTrimis = 0
					Replace trimis With m.pnTrimis, id_incarcare With m.pcIdIncarcare, data_trimis With Datetime(), mesaj_trimis With m.pcMesajTrimis, ales With 0, ;
						id_descarcare WITH '', data_raspuns WITH null, tip_mesaj_raspuns WITH '', mesaj_raspuns WITH null ;
						In crsFacturiEmise
				Else
					Replace trimis With m.pnTrimis, id_incarcare With m.pcIdIncarcare, data_trimis With Datetime(), mesaj_trimis With m.pcMesajTrimis, ales With 0, ;
						id_descarcare WITH '', data_raspuns WITH null, tip_mesaj_raspuns WITH '', mesaj_raspuns WITH null ;
						In crsFacturiEmise
				Endif
			ELSE

				lcMesaj = 'Eroare transmitere factura ' + Alltrim(Str(m.lnNumarFact)) + ' / ' + Dtoc(m.ldDataFact) + Chr(13) + Chr(10) + ;
					'Fisier xml: ' + Alltrim(Transform(loReturn.cFile)) + Chr(13) + Chr(10) + ;
					'ANAF Http Status: ' + Transform(loReturn.nStatus) + Chr(13) + Chr(10) + ;
					IIF(loReturn.nStatus = 403, 'Acces interzis. Token-ul a expirat si trebuie regenerat.' + Chr(13) + Chr(10), '') + ;
					'ANAF Http Response: ' + Alltrim(Transform(loReturn.cResponse))
				poLog.Log(m.lcMesaj)

				If AMESSAGEBOX(m.lcMesaj + Chr(10) + ;
						  'Doriti sa continuati?', 4 + 32, _Screen.Caption) <> 6
					Exit
				Endif
			Endif
		Endscan

		Select crsFacturiEmise
		Try
			If m.lnRecno > 0
				Goto m.lnRecno
			Else
				Go Top
			Endif
		Catch
			Go Top
		Endtry
	Endproc && TrimiteFacturi

	* Genereaza xml eFactura, valideaza xml si trimite la ANAF
	FUNCTION TrimiteEfactura
		Lparameters tnIdVanzare, tlNuTrimiteEFacturaANAF
		PRIVATE pcTokenEfactura	
		LOCAL loReturn

		loReturn = Createobject("empty")
		AddProperty(loReturn, "lSucces", .F.)
		AddProperty(loReturn, "cFile", '')
		AddProperty(loReturn, "cResponse", '')
		AddProperty(loReturn, "nStatus", 0)
		
		* Genereaza xml eFactura
		llSilent = .T.
		llJustPDF = .F.
		lcTipDocument = 'FACTURA'
		llEFactura = .T.
		llOk = .F.
		lcFile = ''
		lcMesaj = ''
		
		pcTokenEfactura = This.Token && variabila privata pentru getxmlefactura > ValidareEFacturaAnaf
		
		loDate = listeaza_formular(m.tnIdVanzare, m.llSilent, m.llJustPDF, m.lcTipDocument, m.llEFactura)
		loInfo = loDate.oInfoEFactura
		If Type('loInfo.cFile') = 'C'
			lcFile = Iif(Type('loInfo.cFile') = 'C', loInfo.cFile, '')
			llOk = loInfo.lOk
			lcMesaj = loInfo.cMesaj
		Endif

		loReturn.cFile = m.lcFile

		lcCodTara = 'RO'
		IF TYPE('loDate.oClient.cod_tara') <> 'U'
			lcCodTara = ALLTRIM(NVL(loDate.oClient.cod_tara, ''))
			IF EMPTY(m.lcCodTara)
				lcCodTara = 'RO'
			ENDIF 
		ENDIF 	

		llAtributFiscalRO = .F.
		IF TYPE('loDate.oClient.cod_fiscal') <> 'U'
			llAtributFiscalRO = 'RO'$UPPER(ALLTRIM(NVL(loDate.oClient.cod_fiscal, '')))
		ENDIF 			

		llExtern = (m.lcCodTara <> 'RO' AND !m.llAtributFiscalRO) && sa aiba sediul fiscal extern si sa nu fie inregistrat TVA in Romania
		lcExtern = IIF(m.llExtern, '&extern=DA', '')

		If m.llOk And !Empty(m.lcFile) And Type('lcFile') = 'C' And File(m.lcFile)
			If !m.tlNuTrimiteEFacturaANAF
				loReturn = This.AnafeFacturaServer.SendEfactura(m.lcFile, m.llExtern)
			Else
				loReturn.cResponse = Iif(!Empty(m.lcMesaj), m.lcMesaj + Chr(13) + Chr(10), '') + 'VALID. Nu s-a trimis fisierul la ANAF.'
				loReturn.lSucces = .T.
			Endif
		Else
			loReturn.cResponse = m.lcMesaj + Chr(13) + Chr(10) + '<errorMessage="Nu s-a trimis fisierul la ANAF">'
			loReturn.lSucces = .F.
		Endif					
		
		RETURN m.loReturn
		
	ENDFUNC && TrimiteEfactura


	****************
	* Parseaza un xml efactura si actualizeaza ANAF_EFACTURA
	****************
	PROCEDURE Detalii2UpdateFactura
		LPARAMETERS tnId, tcDetalii

		LOCAL llVariable
		llVariable = .T.

		TRY
			loFactura = ParseEFactura(m.tcDetalii, m.llVariable)
			loFactura.nId = m.tnId
		
			lcSql = [select a.*, 1 as modificat, to_clob(null) as factura_detalii from anaf_efactura a where id = ] + ALLTRIM(STR(m.tnId))
			llSucces = goExecutor.oExecuta(m.lcSql, 'cAnafEfacturaTemp')
			IF m.llSucces
				ADDPROPERTY(loFactura, 'cIdIncarcare', cAnafEfacturaTemp.id_incarcare)
				ADDPROPERTY(loFactura, 'cIdDescarcare', cAnafEfacturaTemp.id_incarcare)							

				llSucces = This.AnafeFacturaServer.cUpdateFactura(loFactura, 'cAnafEfacturaTemp')

				IF m.llSucces
					llSucces = This.AnafeFacturaServer.UpdateDb('cAnafEfacturaTemp')
				ENDIF 	
			ENDIF 

			USE IN (SELECT('cAnafEfacturaTemp'))	
		Catch To loEx
			llSucces = .F.
		ENDTRY
		RETURN m.llSucces
	ENDPROC && Detalii2UpdateFactura
	

	
	
	* Salveaza pe disk arhiva cu detalii ANAF_EFACTURA.DETALII_ZIP
	FUNCTION DownloadDetaliiZip
		LPARAMETERS tnIdeFactura	
		
		PRIVATE poDetaliiZip
		poDetaliiZip = null
			
		lcSchema = [id_incarcare V(36), fisier W]
		lcSelect = [select id_incarcare, detalii_zip from anaf_efactura where id = ] + Alltrim(Str(tnIdeFactura))
		lcOrder = []
		lcgroup = []
		lcFiltru = []
		lcFiltruOriginal = []
		llModParam = .T.
		llAfiseaza = .F.

		gencursor('poDetaliiZip','cRegFisierTemp', lcSelect, lcFiltru, lcSchema, lcOrder, llAfiseaza,  lcgroup, llModParam, lcFiltruOriginal)
		poDetaliiZip.ca_baza1.afisare()
		If Used('cRegFisierTemp')
			lcIdIncarcare = ALLTRIM(NVL(id_incarcare, ''))
			lcFisier = fisier
			Use In (Select('cRegFisierTemp'))

			lcFile = PUTFILE('Fisier', m.lcIdIncarcare, 'zip')
			IF !EMPTY(m.lcFile)
				Strtofile(lcFisier, m.lcFile)
				open_default_app(JUSTPATH(m.lcFile))
			ENDIF 	
		Endif
	ENDFUNC && DownloadDetaliiZip
		
ENDDEFINE && ANAFeFactura



*********************
* Parseaza xml efactura si intoarce obiect VFP cu datele facturii xml cu detaliile facturii
*********************
Procedure ParseEFactura
	Lparameters tcFile, tlVariable
* tcFile: fisier sau variabila care contine xml eFactura
* tlVariable: .T. daca tcFile este o variabila care contine xml eFactura

	Local lcFileText, lcDetalii, lcFacturaDetalii, loEx As Exception, loReturn
	Local laLinii[1], laLiniiDisc[1], laDetalii[1], laDetaliiLinie[1], laDetaliiPlata[1], laCommodityClassification[1]
	Local lcDataFactura, lcDataScad, lcDetaliiLinie, lcUM, lcValuta, lnAn, lnCant, lnDetalii
	Local lnDetaliiLinie, lnDetaliu, lnDetaliuLinie, lnLinie, lnLinii, lnLuna, lnNr, lnPret, lnProcTva
	Local lnZi, loFactura, loLinie, lcArticol, lcDetaliu
	Local lcArticolDescriere, lcBanca, lcCodClient, lcCodFurnizor, lcTip, lcCod, lcCodBare, lcCodCPV, lcCodNC8
	Local lcCodPlata, lcContBanca, lcPrefixInvoice, llCreditNote
	Local lnCommodityClassification, lnCommodityClassifications, lnValoareFaraTVA
	Local loCommodityClassification, loDetaliu, loItemClassificationCode
	Local lnDiscount, lnDiscountLinie, lnValoareTVA, loTaxTotal



*!*		IF '4114569629'$lcfile
*!*		SET STEP ON
*!*		ENDIF
	loReturn = Createobject("empty")
	AddProperty(loReturn, "nId", "") && ANAF_EFACTURA.ID
	AddProperty(loReturn, "NumarAct", "")
	AddProperty(loReturn, "DataAct", {})
	AddProperty(loReturn, "DataScad", {})
	
	AddProperty(loReturn, "Furnizor", "")
	AddProperty(loReturn, "CodTaraFurnizor", "")		
	AddProperty(loReturn, "CodJudetFurnizor", "")
	AddProperty(loReturn, "LocalitateFurnizor", "")		
	AddProperty(loReturn, "StradaFurnizor", "")
	AddProperty(loReturn, "CodFiscalFurnizor", "")	
	
	AddProperty(loReturn, "Client", "")
	AddProperty(loReturn, "CodTaraClient", "")	
	AddProperty(loReturn, "CodJudetClient", "")
	AddProperty(loReturn, "LocalitateClient", "")		
	AddProperty(loReturn, "StradaClient", "")
	AddProperty(loReturn, "CodFiscalClient", "")		
	
	AddProperty(loReturn, "TotalFaraTva", 0.00)
	AddProperty(loReturn, "TotalTva", 0.00)
	AddProperty(loReturn, "TotalTvaRON", 0.00)	
	AddProperty(loReturn, "TotalCuTva", 0.00)
	AddProperty(loReturn, "TaxeFaraTVA", 0.00)
	AddProperty(loReturn, "DiscountFaraTVA", 0.00)
	AddProperty(loReturn, "ValoareFaraTVA", 0.00) && suma valoare articole
	AddProperty(loReturn, "TotaldePlata", 0.00)
	AddProperty(loReturn, "Valuta", "")
	AddProperty(loReturn, "Detalii", "") && note factura
	AddProperty(loReturn, "DetaliiPlata", "") && detalii plata (conturi bancare)
	AddProperty(loReturn, "FacturaDetalii", "") && liniile facturii
	AddProperty(loReturn, "FacturaDetaliiDisc", "") && linii discount la nivel de factura
	AddProperty(loReturn, "Eroare", .F.) && daca a aparut o eroare la parsarea facturii
	AddProperty(loReturn, "CreditNote", 0) && 1 = CreditNote, 0 = Invoice

	Create Cursor cFacturaDetaliiTemp(nr I, cant N(16, 6), um V(20), articol V(250), descriere V(250), detalii M, Pret N(16, 6), proctva N(10, 2), tiptva V(2), valoarefaratva N(16,4), discountfaratva N(16,4), codfurnizor V(100), codclient V(100), codbare V(50), codcpv V(50), codnc8 V(50))
	CREATE CURSOR cFacturaDetaliiDisc(valoare N(20,6), procentTVA N(5,2), tiptva V(10), discount N(1), motivdiscount V(200), motivdiscountcod V(50))
	
	If m.tlVariable
		lcFileText = m.tcFile
	Else
		lcFileText = Iif(File(m.tcFile), Filetostr(m.tcFile), '')
	Endif

	If Empty(m.lcFileText)
		loReturn.eroare = .T.
		Return loReturn
	Endif

	* CreditNote to Invoice
	llCreditNote = 'CreditNote' $ lcFileText
	loReturn.CreditNote = IIF(m.llCreditNote, 1, 0)
	lcFileText = Strtran(lcFileText, 'CreditNote', 'Invoice', 1, 100000, 1)
	lcFileText = Strtran(lcFileText, 'Credited', 'Invoiced', 1, 100000, 1)

	* Scot cbc: cac:
	* Unele fisiere nu au, altele au. Le scot din toate
	lcFileText = Strtran(lcFileText, 'cac:', '', 1, 1000000, 1)
	lcFileText = Strtran(lcFileText, 'cbc:', '', 1, 1000000, 1)

	lcPrefixInvoice = STREXTRACT(m.lcFileText, [<], [Invoice],1,1) && un prefix custom la Invoice <p:Invoice xlmns...
	IF LEN(m.lcPrefixInvoice) > 10 && caut prefixul la a doua aparitie a <
		lcPrefixInvoice = STREXTRACT(m.lcFileText, [<], [Invoice],2,1) && un prefix custom la Invoice <p:Invoice xlmns...	
	ENDIF 
	IF !EMPTY(m.lcPrefixInvoice)
		lcFileText = Strtran(lcFileText, m.lcPrefixInvoice, '', 1, 100000, 1) && elimin prefixul custom Invoice
	ENDIF 	

	* elimin prefixuri custom: n2:, n3:
	lcPattern = [<\/.{1,6}:Amount>] && [<n3:Amount ]
	lcPrefix = GetRegExp(m.lcFileText, m.lcPattern)
	lcPrefix = STREXTRACT(NVL(m.lcPrefix, ''), [</], [Amount],1,1)
	IF !EMPTY(m.lcPrefix)
		lcFileText = Strtran(lcFileText, m.lcPrefix, '', 1, 100000, 1) && elimin prefixul custom
	ENDIF 
		
	lcPattern = [<\/.{1,6}:AccountingSupplierParty>]
	lcPrefix = GetRegExp(m.lcFileText, m.lcPattern)
	lcPrefix = STREXTRACT(NVL(m.lcPrefix, ''), [</], [AccountingSupplierParty],1,1)
	IF !EMPTY(m.lcPrefix)
		lcFileText = Strtran(lcFileText, m.lcPrefix, '', 1, 100000, 1) && elimin prefixul custom
	ENDIF 

	lcPattern = [<\/.{1,6}:LineExtensionAmount>]
	lcPrefix = GetRegExp(m.lcFileText, m.lcPattern)
	lcPrefix = STREXTRACT(NVL(m.lcPrefix, ''), [</], [LineExtensionAmount],1,1)
	IF !EMPTY(m.lcPrefix)
		lcFileText = Strtran(lcFileText, m.lcPrefix, '', 1, 100000, 1) && elimin prefixul custom
	ENDIF 


	TRY
* Nu prea functioneaza transformarea in array-uri a tag-urilor care apar o singura data
		loFactura = nfxmlread(m.lcFileText)
*!*					MESSAGEBOX(lofactura.invoice.cac_legalmonetarytotal.cbc_taxinclusiveamount._attr_.currencyid)
*!*					MESSAGEBOX(lofactura.invoice.cac_legalmonetarytotal.cbc_taxinclusiveamount._nodetext_)
*!*					loNrFacturaPrimit = nfxmlread(m.pcDetalii, '.Invoice.cac:InvoiceLine[]', '//Invoice/cbc:ID' )
*!*					loDataFacturaPrimit = nfxmlread(m.pcDetalii, '.Invoice.cac:InvoiceLine[]', '//Invoice/cbc:IssueDate' ) && 2022-09-30
*!*					loDataFacturaPrimit = nfxmlread(m.pcDetalii, '.Invoice.cac:InvoiceLine[]', '//Invoice/cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount' ) && 2022-09-30
		DO CASE 
			CASE Type('loFactura.invoice.id') = 'C'
				loReturn.numaract = loFactura.Invoice.id				
			CASE Type('loFactura.invoice.id._nodetext_') = 'C'
				loReturn.numaract = loFactura.Invoice.id._nodetext_
		ENDCASE 

		If Type('loFactura.invoice.issuedate') = 'C'
			lcDataFactura = loFactura.Invoice.issuedate
		Else
			If Type('loFactura.invoice.issuedate._nodetext_	') = 'C'
				lcDataFactura = loFactura.Invoice.issuedate._nodetext_
			Endif
		Endif
		If !Empty(m.lcDataFactura)
			lnAn = Int(Val(Substr(m.lcDataFactura, 1, 4)))
			lnLuna = Int(Val(Substr(m.lcDataFactura, 6, 2)))
			lnZi = Int(Val(Substr(m.lcDataFactura, 9, 2)))
			loReturn.dataact = Date(m.lnAn, m.lnLuna, m.lnZi)
		Endif

		If Type('loFactura.invoice.duedate') = 'C'
			lcDataScad = loFactura.Invoice.duedate
		Else
			If Type('loFactura.invoice.duedate._nodetext_') = 'C'
				lcDataScad = loFactura.Invoice.duedate._nodetext_
			Endif
		Endif
		If !Empty(m.lcDataScad)
			lnAn = Int(Val(Substr(m.lcDataScad, 1, 4)))
			lnLuna = Int(Val(Substr(m.lcDataScad, 6, 2)))
			lnZi = Int(Val(Substr(m.lcDataScad, 9, 2)))
			loReturn.datascad = Date(m.lnAn, m.lnLuna, m.lnZi)
		Endif

		If Type('lofactura.invoice.legalmonetarytotal.LineExtensionAmount._nodetext_') = 'C'
			loReturn.valoarefaratva = Val(loFactura.Invoice.legalmonetarytotal.LineExtensionAmount._nodetext_)
		Endif

		If Type('lofactura.invoice.legalmonetarytotal.taxinclusiveamount._nodetext_') = 'C'
			loReturn.totalcutva = Val(loFactura.Invoice.legalmonetarytotal.taxinclusiveamount._nodetext_)
		Endif
		If Type('lofactura.invoice.legalmonetarytotal.taxinclusiveamount._attr_.currencyid') = 'C'
			loReturn.valuta = loFactura.Invoice.legalmonetarytotal.taxinclusiveamount._attr_.currencyid
		Endif

		If Type('lofactura.invoice.legalmonetarytotal.TaxExclusiveAmount._nodetext_') = 'C'
			loReturn.totalfaratva = Val(loFactura.Invoice.legalmonetarytotal.TaxExclusiveAmount._nodetext_)
		Endif

		loReturn.totaltva = loReturn.totalcutva - loReturn.totalfaratva

		If Type('lofactura.invoice.legalmonetarytotal.AllowanceTotalAmount._nodetext_') = 'C'
			loReturn.discountfaratva = Val(loFactura.Invoice.legalmonetarytotal.AllowanceTotalAmount._nodetext_)
		Endif

		If Type('lofactura.invoice.legalmonetarytotal.ChargeTotalAmount._nodetext_') = 'C'
* Transport trecut ca valoare totala pe document, in loc de o linie din factura
			loReturn.taxefaratva = Val(loFactura.Invoice.legalmonetarytotal.ChargeTotalAmount._nodetext_)
		Endif

		If Type('lofactura.invoice.legalmonetarytotal.PayableAmount._nodetext_') = 'C'
			loReturn.totaldeplata = Val(loFactura.Invoice.legalmonetarytotal.PayableAmount._nodetext_)
		Endif

		* Daca moneda facturii este in valuta <> RON, atunci extrag valoare tva in RON
		* Sunt 2 TaxTotal, una in valuta facturii si una in RON
*!*			<cac:TaxTotal>
*!*				<cbc:TaxAmount currencyID="RON">0.00</cbc:TaxAmount>
*!*			</cac:TaxTotal>
		IF UPPER(ALLTRIM(loReturn.valuta)) <> 'RON'
			If Type('loFactura.Invoice.TaxTotal') <> 'U'
				If Type('loFactura.Invoice.TaxTotal', 1) = 'A'
					FOR EACH loTaxTotal IN loFactura.Invoice.TaxTotal
						IF TYPE('loTaxTotal.TaxAmount._attr_.CurrencyId') = 'C' AND TYPE('loTaxTotal.TaxAmount._nodetext_') = 'C' AND loTaxTotal.TaxAmount._attr_.CurrencyId = "RON" 
							loReturn.TotalTVARON = VAL(loTaxTotal.TaxAmount._nodetext_)
						ENDIF 
					ENDFOR 
				ELSE
					IF TYPE('loFactura.Invoice.TaxTotal') = 'O'
						loTaxTotal = loFactura.Invoice.TaxTotal
						IF TYPE('loTaxTotal.TaxAmount._attr_') = 'C' AND TYPE('loTaxTotal.TaxAmount._nodetext_') = 'C' AND loTaxTotal.TaxAmount._attr_.CurrencyId = "RON" 
							loReturn.TotalTVARON = VAL(loTaxTotal.TaxAmount._nodetext_)
						ENDIF 		
					ENDIF 	
				ENDIF			
			ENDIF && <> U
		ELSE 
			loReturn.TotalTVARON = loReturn.totaltva			
		ENDIF && <> RON
		
		
	
		loReturn.detalii = ""
		If Type('loFactura.Invoice.note') <> 'U'
			If Type('loFactura.Invoice.note', 1) = 'A'
				Acopy(loFactura.Invoice.note, laDetalii)
			ELSE
				IF TYPE('loFactura.Invoice.note') = 'C'
					laDetalii[1] = loFactura.Invoice.note
				ELSE
					IF TYPE('loFactura.Invoice.note._nodetext_') = 'C'
						laDetalii[1] = loFactura.Invoice.note._nodetext_
					ENDIF 	
				ENDIF 	
			Endif

			lnDetalii = Alen(laDetalii)
			For lnDetaliu = 1 To m.lnDetalii
				lcDetaliu = ''
				IF TYPE('laDetalii[m.lnDetaliu]') = 'C'
					lcDetaliu = laDetalii[m.lnDetaliu]
				ELSE
					IF TYPE('laDetalii[m.lnDetaliu]._nodetext_') = 'C'
						lcDetaliu = laDetalii[m.lnDetaliu]._nodetext_
					ENDIF 					
				ENDIF 	
				loReturn.detalii  = loReturn.detalii + Iif(m.lnDetaliu > 1, " ", "") + m.lcDetaliu
			Endfor
		Endif

* Detalii plata = conturi bancare plata
		loReturn.detaliiplata = ""
		If Type('loFactura.Invoice.paymentmeans') <> 'U'
			If Type('loFactura.Invoice.paymentmeans', 1) = 'A'
				Acopy(loFactura.Invoice.paymentmeans, laDetaliiPlata)
			Else
				laDetaliiPlata[1] = loFactura.Invoice.paymentmeans
			Endif

			lnDetalii = Alen(laDetaliiPlata)
			For lnDetaliu = 1 To m.lnDetalii
				loDetaliu = laDetaliiPlata[m.lnDetaliu]
				lcCodPlata = ''
				lcContBanca = ''
				lcBanca = ''
				If Type('loDetaliu.paymentmeanscode') = 'C'
					lcCodPlata = loDetaliu.paymentmeanscode
				Else
					If Type('loDetaliu.paymentmeanscode._nodetext_') = 'C'
						lcCodPlata = loDetaliu.paymentmeanscode._nodetext_
					Endif
				Endif
				If !Empty(m.lcCodPlata)
					Do Case
						Case lcCodPlata = '10'
							lcCodPlata = lcCodPlata + ' Numerar'
						Case lcCodPlata = '20'
							lcCodPlata = lcCodPlata + ' CEC'
						Case lcCodPlata = '31'
							lcCodPlata = lcCodPlata + ' Transfer'
						Case lcCodPlata = '42'
							lcCodPlata = lcCodPlata + ' OP'
						Case lcCodPlata = '48'
							lcCodPlata = lcCodPlata + ' Card'
						Case lcCodPlata = '60'
							lcCodPlata = lcCodPlata + ' BO'
						Case lcCodPlata = '68'
							lcCodPlata = lcCodPlata + ' Online'
						Case lcCodPlata = '97'
							lcCodPlata = lcCodPlata + ' Compensare'
					Endcase
				Endif

				If Type('loDetaliu.payeefinancialaccount.id') = 'C'
					lcContBanca = loDetaliu.payeefinancialaccount.id
				Else
					If Type('loDetaliu.payeefinancialaccount.id._nodetext_') = 'C'
						lcContBanca = loDetaliu.payeefinancialaccount.id._nodetext_
					Endif
				Endif
				If Type('loDetaliu.payeefinancialaccount.name') = 'C'
					lcBanca = loDetaliu.payeefinancialaccount.name
				Else
					If Type('loDetaliu.payeefinancialaccount.name._nodetext_') = 'C'
						lcBanca = loDetaliu.payeefinancialaccount.name._nodetext_
					Endif
				Endif
				loReturn.detaliiplata  = loReturn.detaliiplata + Iif(m.lnDetaliu > 1, "; ", "") + ;
					Iif(Empty(m.lcCodPlata), '', 'Tip: ' + m.lcCodPlata) + ;
					Iif(Empty(m.lcContBanca), '', Iif(!Empty(m.lcCodPlata), ',', '') + ' IBAN: ' + m.lcContBanca) + ;
					Iif(Empty(m.lcBanca), '', Iif(!Empty(m.lcContBanca), ',', '') + ' Banca: ' + m.lcBanca)
			Endfor
		Endif
		
		* Furnizor Denumire
		If Type('lofactura.invoice.AccountingSupplierParty.Party.PartyLegalEntity.RegistrationName') = 'C'
			loReturn.Furnizor = Alltrim(loFactura.Invoice.AccountingSupplierParty.Party.PartyLegalEntity.RegistrationName)
		Else
			If Type('lofactura.invoice.AccountingSupplierParty.Party.PartyLegalEntity.RegistrationName._nodetext_') = 'C'
				loReturn.Furnizor = Alltrim(loFactura.Invoice.AccountingSupplierParty.Party.PartyLegalEntity.RegistrationName._nodetext_)
			ELSE
				If Type('lofactura.invoice.AccountingSupplierParty.Party.PartyLegalEntity[1].RegistrationName') = 'C'
					loReturn.Furnizor = Alltrim(loFactura.Invoice.AccountingSupplierParty.Party.PartyLegalEntity[1].RegistrationName)
				ELSE 
					If Type('lofactura.invoice.AccountingSupplierParty.Party.PartyLegalEntity[2].RegistrationName') = 'C'
						loReturn.Furnizor = Alltrim(loFactura.Invoice.AccountingSupplierParty.Party.PartyLegalEntity[2].RegistrationName)
					ENDIF 
				ENDIF 
			Endif
		ENDIF
		
		* Cod fiscal Furnizor
		If Type('lofactura.invoice.AccountingSupplierParty.Party.PartyTaxScheme.CompanyId') = 'C'
			loReturn.CodFiscalFurnizor = Alltrim(lofactura.invoice.AccountingSupplierParty.Party.PartyTaxScheme.CompanyId)
		Else		
			If Type('lofactura.invoice.AccountingSupplierParty.Party.PartyTaxScheme.CompanyId._nodetext_') = 'C'
				loReturn.CodFiscalFurnizor = Alltrim(lofactura.invoice.AccountingSupplierParty.Party.PartyTaxScheme.CompanyId._nodetext_)
			ELSE 
				If Type('lofactura.invoice.AccountingSupplierParty.Party.PartyLegalEntity.CompanyId') = 'C'
					loReturn.CodFiscalFurnizor = Alltrim(lofactura.invoice.AccountingSupplierParty.Party.PartyLegalEntity.CompanyId)
				Else
					If Type('lofactura.invoice.AccountingSupplierParty.Party.PartyLegalEntity.CompanyId._nodetext_') = 'C'
						loReturn.CodFiscalFurnizor = Alltrim(lofactura.invoice.AccountingSupplierParty.Party.PartyLegalEntity.CompanyId._nodetext_)
					Endif
				ENDIF			
			ENDIF 
		ENDIF 				


		* Furnizor Cod Tara
		If Type('lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.Country.IdentificationCode') = 'C'
			loReturn.CodTaraFurnizor = Alltrim(lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.Country.IdentificationCode)
		Else
			If Type('lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.Country.IdentificationCode._nodetext_') = 'C'
				loReturn.CodTaraFurnizor = Alltrim(lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.Country.IdentificationCode._nodetext_)
			Endif
		ENDIF
		
		* Furnizor Cod Judet
		If Type('lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.CountrySubentity') = 'C'
			loReturn.CodJudetFurnizor = Alltrim(lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.CountrySubentity)
		Else
			If Type('lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.CountrySubentity._nodetext_') = 'C'
				loReturn.CodJudetFurnizor = Alltrim(lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.CountrySubentity._nodetext_)
			Endif
		Endif

		* Furnizor Localitate
		If Type('lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.CityName') = 'C'
			loReturn.LocalitateFurnizor = Alltrim(lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.CityName)
		Else
			If Type('lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.CityName._nodetext_') = 'C'
				loReturn.LocalitateFurnizor = Alltrim(lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.CityName._nodetext_)
			Endif
		ENDIF
					
		* Furnizor Strada
		If Type('lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.StreetName') = 'C'
			loReturn.StradaFurnizor = Alltrim(lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.StreetName)
		Else
			If Type('lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.StreetName._nodetext_') = 'C'
				loReturn.StradaFurnizor = Alltrim(lofactura.invoice.AccountingSupplierParty.Party.PostalAddress.StreetName._nodetext_)
			Endif
		ENDIF

		* Client Denumire
		If Type('lofactura.invoice.AccountingCustomerParty.Party.PartyLegalEntity.RegistrationName') = 'C'
			loReturn.client = Alltrim(loFactura.Invoice.AccountingCustomerParty.Party.PartyLegalEntity.RegistrationName)
		Else
			If Type('lofactura.invoice.AccountingCustomerParty.Party.PartyLegalEntity.RegistrationName._nodetext_') = 'C'
				loReturn.client = Alltrim(loFactura.Invoice.AccountingCustomerParty.Party.PartyLegalEntity.RegistrationName._nodetext_)
			Endif
		ENDIF

		* Cod fiscal Client
		If Type('lofactura.invoice.AccountingCustomerParty.Party.PartyTaxScheme.CompanyId') = 'C'
			loReturn.CodFiscalClient = Alltrim(lofactura.invoice.AccountingCustomerParty.Party.PartyTaxScheme.CompanyId)
		Else		
			If Type('lofactura.invoice.AccountingCustomerParty.Party.PartyTaxScheme.CompanyId._nodetext_') = 'C'
				loReturn.CodFiscalClient = Alltrim(lofactura.invoice.AccountingCustomerParty.Party.PartyTaxScheme.CompanyId._nodetext_)
			ELSE 
				If Type('lofactura.invoice.AccountingCustomerParty.Party.PartyLegalEntity.CompanyId') = 'C'
					loReturn.CodFiscalClient = Alltrim(lofactura.invoice.AccountingCustomerParty.Party.PartyLegalEntity.CompanyId)
				Else
					If Type('lofactura.invoice.AccountingCustomerParty.Party.PartyLegalEntity.CompanyId._nodetext_') = 'C'
						loReturn.CodFiscalClient = Alltrim(lofactura.invoice.AccountingCustomerParty.Party.PartyLegalEntity.CompanyId._nodetext_)
					Endif
				ENDIF			
			ENDIF 
		ENDIF 		
		
		* Client Cod Tara
		If Type('lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.Country.IdentificationCode') = 'C'
			loReturn.CodTaraClient = Alltrim(lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.Country.IdentificationCode)
		Else
			If Type('lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.Country.IdentificationCode._nodetext_') = 'C'
				loReturn.CodTaraClient = Alltrim(lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.Country.IdentificationCode._nodetext_)
			Endif
		ENDIF
		
		* Client Cod Judet
		If Type('lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.CountrySubentity') = 'C'
			loReturn.CodJudetClient = Alltrim(lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.CountrySubentity)
		Else
			If Type('lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.CountrySubentity._nodetext_') = 'C'
				loReturn.CodJudetClient = Alltrim(lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.CountrySubentity._nodetext_)
			Endif
		Endif

		* Client Localitate
		If Type('lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.CityName') = 'C'
			loReturn.LocalitateClient = Alltrim(lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.CityName)
		Else
			If Type('lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.CityName._nodetext_') = 'C'
				loReturn.LocalitateClient = Alltrim(lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.CityName._nodetext_)
			Endif
		ENDIF
					
		* Client Strada
		If Type('lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.StreetName') = 'C'
			loReturn.StradaClient = Alltrim(lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.StreetName)
		Else
			If Type('lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.StreetName._nodetext_') = 'C'
				loReturn.StradaClient = Alltrim(lofactura.invoice.AccountingCustomerParty.Party.PostalAddress.StreetName._nodetext_)
			Endif
		ENDIF

								
		* Cursor linii factura
		If Type('lofactura.invoice.invoiceline', 1) = 'A'
			Acopy(loFactura.Invoice.invoiceline, laLinii)
		Else
			laLinii[1] =  loFactura.Invoice.invoiceline
		Endif

		Try
			lnLinii = Alen(laLinii)
			For lnLinie = 1 To m.lnLinii
				loLinie = laLinii[m.lnLinie]
				lnNr = 0
				If Type('loLinie.id') = 'C'
					lnNr = Int(Val(loLinie.id))
				Else
					If Type('loLinie.id._nodetext_') = 'C'
						lnNr = Int(Val(loLinie.id._nodetext_))
					Endif
				ENDIF
				
				lnValoareFaraTVA = 0
				If Type('loLinie.LineExtensionAmount._nodetext_') = 'C'
					lnValoareFaraTVA = Val(loLinie.LineExtensionAmount._nodetext_)
				Endif				

				lcArticol = ''
				If Type('loLinie.item.name') = 'C'
					lcArticol = Alltrim(loLinie.item.name)
				Else
					If Type('loLinie.item.name._nodetext_') = 'C'
						lcArticol = Alltrim(loLinie.item.name._nodetext_)
					Endif
				Endif
				lcArticolDescriere = ''
				If Type('loLinie.item.description') = 'C'
					lcArticolDescriere = Alltrim(loLinie.item.description)
				Else
					If Type('loLinie.item.description._nodetext_') = 'C'
						lcArticolDescriere = Alltrim(loLinie.item.description._nodetext_)
					Endif
				Endif

				lcDetaliiLinie = ''
				If Type('loLinie.note') <> 'U'
					If Type('loLinie.note', 1) = 'A'
						Acopy(loLinie.note, laDetaliiLinie)
					Else
						If Type('loLinie.note') = 'C'
							laDetaliiLinie[1] = loLinie.note
						Else
							If Type('loLinie.note._nodetext_') = 'C'
								laDetaliiLinie[1] = loLinie.note._nodetext_
							Endif
						Endif
					Endif

					lnDetaliiLinie = Alen(laDetaliiLinie)
					For lnDetaliuLinie = 1 To m.lnDetaliiLinie
						lcDetaliiLinie = m.lcDetaliiLinie + Iif(m.lnDetaliuLinie > 1, " ", "") + laDetaliiLinie[m.lnDetaliuLinie]
					Endfor
				ENDIF
				
				* Cod articol cumparator/client
				lcCodClient = ''
				If Type('loLinie.item.BuyersItemIdentification.ID') = 'C'
					lcCodClient = Alltrim(loLinie.item.BuyersItemIdentification.ID)
				Else
					If Type('loLinie.item.BuyersItemIdentification.ID._nodetext_') = 'C'
						lcCodClient = Alltrim(loLinie.item.BuyersItemIdentification.ID._nodetext_)
					Endif
				ENDIF
				
				* Cod articol vanzator/furnizor
				lcCodFurnizor = ''
				If Type('loLinie.item.SellersItemIdentification.ID') = 'C'
					lcCodFurnizor = Alltrim(loLinie.item.SellersItemIdentification.ID)
				Else
					If Type('loLinie.item.SellersItemIdentification.ID._nodetext_') = 'C'
						lcCodFurnizor = Alltrim(loLinie.item.SellersItemIdentification.ID._nodetext_)
					Endif
				ENDIF												

				* Cod de bare articol
				lcCodBare = ''
				If Type('loLinie.item.StandardItemIdentification.ID') = 'C'
					lcCodBare = Alltrim(loLinie.item.StandardItemIdentification.ID)
				Else
					If Type('loLinie.item.StandardItemIdentification.ID._nodetext_') = 'C'
						lcCodBare = Alltrim(loLinie.item.StandardItemIdentification.ID._nodetext_)
					Endif
				ENDIF
				
				lcCodCPV = ''
				lcCodNC8 = ''
				If Type('loLinie.item.CommodityClassification') <> 'U'
					If Type('loLinie.item.CommodityClassification', 1) = 'A'
						Acopy(loLinie.item.CommodityClassification, laCommodityClassification)
					Else
						If Type('loLinie.item.CommodityClassification') = 'O'
							laCommodityClassification[1] = loLinie.item.CommodityClassification
						Endif
					Endif

					lnCommodityClassifications = Alen(laCommodityClassification)
					For lnCommodityClassification = 1 To m.lnCommodityClassifications
						loCommodityClassification = laCommodityClassification[lnCommodityClassification]
						IF TYPE('loCommodityClassification.ItemClassificationCode') = 'O'
							loItemClassificationCode = loCommodityClassification.ItemClassificationCode
							IF TYPE('loItemClassificationCode._attr_.listid') = 'C' AND TYPE('loItemClassificationCode._nodetext_') = 'C'
								lcTip = UPPER(ALLTRIM(loItemClassificationCode._attr_.listid))
								lcCod = ALLTRIM(loItemClassificationCode._nodetext_)
								DO CASE 
									CASE m.lcTip = 'EN' AND EMPTY(m.lcCodBare)&& cod bare
										lcCodBare = m.lcCod
									CASE m.lcTip = 'STI' && cod CPV
										lcCodCPV = m.lcCod					
									CASE m.lcTip = 'TSP' && cod NC8
										lcCodNC8 = m.lcCod
								ENDCASE  
							ENDIF && type	
						ENDIF && type 
					Endfor
				ENDIF
								
				lnCant = Val(loLinie.invoicedquantity._nodetext_)
				lcUM =  loLinie.invoicedquantity._attr_.unitcode
				lnPret = Val(loLinie.price.priceamount._nodetext_)
				lcValuta = loLinie.price.priceamount._attr_.currencyid
				lnDiscountLinie = 0
				IF TYPE('loLinie.AllowanceCharge.Amount._nodetext_') = 'C'
					lnDiscountLinie = Val(loLinie.AllowanceCharge.Amount._nodetext_)
				ENDIF 	
				
				lnProcTva = 0
				If Type('loLinie.item.ClassifiedTaxCategory.percent') = 'C'
					lnProcTva = Val(loLinie.item.ClassifiedTaxCategory.percent)
				Else
					If Type('loLinie.item.ClassifiedTaxCategory.percent._nodetext_') = 'C'
						lnProcTva = Val(loLinie.item.ClassifiedTaxCategory.percent._nodetext_)
					Endif
				ENDIF
				
				lcTipTVA = "" && S standard/Z neplatitor TVA/AE taxare inversa
				If Type('loLinie.item.ClassifiedTaxCategory.ID') = 'C'
					lcTipTva = loLinie.item.ClassifiedTaxCategory.ID
				Else
					If Type('loLinie.item.ClassifiedTaxCategory.ID._nodetext_') = 'C'
						lcTipTva = loLinie.item.ClassifiedTaxCategory.ID._nodetext_
					Endif
				Endif				

* Tip CreditNote am vazut ca nu are cantitate si pret negative pe linie, dar are valoare fara tva negativ!!!
				If m.llCreditNote And m.lnCant > 0 And m.lnPret > 0 And m.lnValoareFaraTVA< 0
					lnCant = -1 * m.lnCant
				Endif

				Insert Into cFacturaDetaliiTemp(nr, cant, um, articol, descriere, detalii, Pret, proctva, tiptva, valoarefaratva, discountfaratva, codfurnizor, codclient, codbare, codcpv, codnc8) Values (m.lnNr, m.lnCant, m.lcUM, m.lcArticol, m.lcArticolDescriere, m.lcDetaliiLinie, m.lnPret, lnProcTva, m.lcTipTva, m.lnValoareFaraTVA, m.lnDiscountLinie, m.lcCodFurnizor, m.lcCodClient, m.lcCodBare, m.lcCodCPV, m.lcCodNC8)
			Endfor
		Catch To loEx
			loReturn.eroare = .T.
			goLog.Log('Eroare la salvarea datelor extrase din xml eFactura. ' + 'Eroare: ' + TRANSFORM(loEx.ErrorNo) + ' ' + loEx.Message + ' Continut:' + loEx.LineContents +   + ' Linia: ' + TRANSFORM(loEx.LineNo) + ' Program: ' + loEx.Procedure)
			Set Step On
		Endtry
	
		Cursortoxml("cfacturadetaliitemp", "lcFacturaDetalii", 1, 0 + 8, 0, "1")
		loReturn.facturadetalii = m.lcFacturaDetalii

		USE IN (SELECT('cFacturaDetaliiTemp'))
		
		* cursor linii discount/taxe la nivel de factura
		IF TYPE('lofactura.invoice.AllowanceCharge') <> 'U'
		
			If Type('lofactura.invoice.AllowanceCharge', 1) = 'A'
				Acopy(loFactura.Invoice.AllowanceCharge, laLiniiDisc)
			Else
				laLiniiDisc[1] =  loFactura.Invoice.AllowanceCharge
			Endif

			Try
				lnLinii = Alen(laLiniiDisc)
				For lnLinie = 1 To m.lnLinii
					loLinie = laLiniiDisc[m.lnLinie]
					lnDiscount = 1
					If Type('loLinie.ChargeIndicator') = 'C'
						lnDiscount = IIF(LOWER(ALLTRIM(loLinie.ChargeIndicator)) = 'false', 1, 0) && discount = false, taxe = true
					Else
						If Type('loLinie.ChargeIndicator._nodetext_') = 'C'
							lnDiscount = IIF(LOWER(ALLTRIM(loLinie.ChargeIndicator._nodetext_)) = 'false', 1, 0)
						Endif
					ENDIF
					
					lcMotivDiscount = ''
					If Type('loLinie.AllowanceChargeReason') = 'C'
						lcMotivDiscount = ALLTRIM(loLinie.AllowanceChargeReason)
					Else
						If Type('loLinie.AllowanceChargeReason._nodetext_') = 'C'
							lcMotivDiscount = ALLTRIM(loLinie.AllowanceChargeReason._nodetext_)
						Endif
					ENDIF

					lcMotivDiscountCod = ''
					If Type('loLinie.AllowanceChargeReasonCode') = 'C'
						lcMotivDiscountCod = ALLTRIM(loLinie.AllowanceChargeReasonCode)
					Else
						If Type('loLinie.AllowanceChargeReasonCode._nodetext_') = 'C'
							lcMotivDiscountCod = ALLTRIM(loLinie.AllowanceChargeReasonCode._nodetext_)
						Endif
					ENDIF
					
					lnValoare = 0
					If Type('loLinie.Amount._nodetext_') = 'C'
						lnValoare = Val(loLinie.Amount._nodetext_)
					ENDIF
					
					lnProcTva = 0			
					If Type('loLinie.TaxCategory.Percent') = 'C'
						lnProcTva = val(loLinie.TaxCategory.Percent)
					Else
						If Type('loLinie.TaxCategory.Percent._nodetext_') = 'C'
							lnProcTva = val(loLinie.TaxCategory.Percent._nodetext_)
						Endif
					ENDIF
					
					lcTipTVA = "" && S standard/Z neplatitor TVA/AE taxare inversa
					If Type('loLinie.item.ClassifiedTaxCategory.ID') = 'C'
						lcTipTva = loLinie.item.ClassifiedTaxCategory.ID
					Else
						If Type('loLinie.item.ClassifiedTaxCategory.ID._nodetext_') = 'C'
							lcTipTva = loLinie.item.ClassifiedTaxCategory.ID._nodetext_
						Endif
					Endif					
					
					Insert Into cFacturaDetaliiDisc(valoare, procenttva, tiptva, discount, motivdiscount, motivdiscountcod) Values (m.lnValoare, m.lnProcTva, m.lcTipTVA, m.lnDiscount, m.lcMotivDiscount, m.lcMotivDiscountCod)
				Endfor
			Catch To loEx
				loReturn.eroare = .T.
				goLog.Log('Eroare la salvarea datelor extrase din xml eFactura. ' + 'Eroare: ' + TRANSFORM(loEx.ErrorNo) + ' ' + loEx.Message + ' Continut:' + loEx.LineContents +   + ' Linia: ' + TRANSFORM(loEx.LineNo) + ' Program: ' + loEx.Procedure)
				Set Step On
			Endtry
		
			Cursortoxml("cFacturaDetaliiDisc", "lcFacturaDetaliiDisc", 1, 0 + 8, 0, "")
			loReturn.facturadetaliiDisc = m.lcFacturaDetaliiDisc

			USE IN (SELECT('cFacturaDetaliiTVA'))
		ENDIF && TYPE('lofactura.invoice.AllowanceCharge') <> 'U'
				
	Catch To loEx
		loReturn.eroare = .T.
		AMESSAGEBOX(loEx.Message)
		Set Step On
	Endtry

	Return loReturn
Endproc && ParseEFactura

******************************
PROCEDURE TestParseEFactura
	
	Local loEfactura As "ExportEFactura"
	Local lcFile, loFactura
	*:Global pcDetaliiXML, pcFurnizorXML, pcNumarActXML, pcNumeValutaXML, pcXMLFacturaDetalii
	*:Global pdDataActXML, pdDataScadXML, pnDiscountFaraTVAXML, pnTaxeFaraTVAXML, pnTotalCuTVAXML
	*:Global pnTotalFaraTVAXML, pnTotalTVAXML, pnTotaldePlataXML, pnValoareFaraTVAXML

	lcSetProcedure = LOWER(SET("Procedure"))
	lcSetClasslib = LOWER(SET("Classlib"))

	* json read
	IF !'nfxmlread'$lcSetProcedure
		SET PROCEDURE TO 'd:\roa\roacont\comun\utile\nfxml\nfxmlread.prg' ADDITIVE 
	ENDIF 	
	
	* amessagebox
	IF !'oproceduri_comune'$lcSetProcedure
		SET PROCEDURE TO 'd:\roa\roacont\comun\programe\oproceduri_comune.prg' ADDITIVE 
	ENDIF 	
	SET STEP ON 
	
	lcFile = GETFILE('xml','Fisier xml','Deschide', 0, "Fisier xml eFactura")
	IF EMPTY(m.lcFile)
		RETURN
	ENDIF 

	TRY	
		loFactura = ParseEfactura(m.lcFile)

		pcNumarActXML = loFactura.numaract
		pdDataActXML = loFactura.dataact
		pdDataScadXML = loFactura.datascad
		pcFurnizorXML = loFactura.furnizor
		pcDetaliiXML = loFactura.detalii
		pcDetaliiPlataXML = loFactura.DetaliiPlata		
		pnTotalFaraTVAXML = loFactura.TotalFaraTva
		pnTotalTVAXML = loFactura.TotalTva
		pnTotalTVARONXML = loFactura.TotalTvaRON && daca factura este in valuta, se completeaza TotalTVARON
		pnTotalCuTVAXML = loFactura.TotalCuTva	
		pnDiscountFaraTVAXML = loFactura.DiscountFaraTVA																					
		pnTaxeFaraTVAXML = loFactura.TaxeFaraTVA
		pnValoareFaraTVAXML = loFactura.ValoareFaraTVA && suma valoare fara tva articole
		pnTotaldePlataXML = loFactura.TotaldePlata
		pcNumeValutaXML = loFactura.valuta
		pcXMLFacturaDetalii = loFactura.FacturaDetalii
		
		XMLTOCURSOR(m.pcXmlFacturaDetalii, "factura_detalii")
	Catch To loEx
		MESSAGEBOX(loEx.message)
	ENDTRY

ENDPROC && TestParseEFactura
                 