#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 ********************************* * 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\\ \\ 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) = '<>' 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 && \\raspunsuri\ This.cSendPath = ADDBS(ALLTRIM(NVL(citeste_optiune("EFACTURA_SENDPATH"),''))) && FACTURI DE TRIMIS && \\emise\ This.cSaveFurnizoriPath = ADDBS(ALLTRIM(NVL(citeste_optiune("EFACTURA_SAVE_FURNIZORI_PATH"), ''))) && \\furnizori\\ \\ This.cSaveFurnizoriFile = ALLTRIM(citeste_optiune("EFACTURA_SAVE_FURNIZORI_FILE")) && __ This.cSaveClientiPath = Addbs(ALLTRIM(NVL(citeste_optiune("EFACTURA_SAVE_CLIENTI_PATH"), ''))) && \\clienti\\ \\ This.cSaveClientiFile = ALLTRIM(citeste_optiune("EFACTURA_SAVE_CLIENTI_FILE")) && ___ 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, '', m.lcPath, 1, 1, 1), '\\', '\', 1, 10, 1) This.cSaveClientiPath = STRTRAN(STRTRAN(This.cSaveClientiPath, '', m.lcPath, 1, 1, 1), '\\', '\', 1, 10, 1) This.cResponsesPath = ADDBS(ALLTRIM(NVL(citeste_optiune("EFACTURA_RESPONSESPATH"),''))) && RASPUNSURI && \raspunsuri\ This.cSendPath = ADDBS(ALLTRIM(NVL(citeste_optiune("EFACTURA_SENDPATH"),''))) && FACTURI DE TRIMIS && \emise\ This.cResponsesPath = STRTRAN(STRTRAN(This.cResponsesPath, '', m.lcPath, 1, 1, 1), '\\', '\', 1, 10, 1) This.cResponsesPath = STRTRAN(This.cResponsesPath,'', 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, '', m.lcPath, 1, 1, 1), '\\', '\', 1, 10, 1) This.cSendPath = STRTRAN(This.cSendPath,'', 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 * 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 lcTokenURL 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) Endfunc * 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 llSucces = .F. lcRefreshToken = Alltrim(This.cRefreshToken) tcMesaj = '' 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 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) ENDTRY 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, 0 + 48, _Screen.Caption) 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, '', '',1,1) lcPartyLegal = STREXTRACT(lcCustomer, '', '',1,1) lcCodFiscalClient = ALLTRIM(STREXTRACT(m.lcPartyLegal, '','',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 = '' ENDTRY Else loReturn.cResponse = '' 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
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 ********************************* * 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/<>/FCTEL/rest/listaMesajePaginatieFactura?startTime=<>&endTime=<>&cif=<>&pagina=<> 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, '', m.lcAn, 1, 100, 1) lcSavePath = Strtran(m.lcSavePath, '', m.lcAn, 1, 100, 1) lcSavePath = Strtran(m.lcSavePath, '', m.lcIdIncarcare, 1, 100, 1) lcSavePath = Strtran(m.lcSavePath, '', m.lcIdDescarcare, 1, 100, 1) lcSavePath = Strtran(m.lcSavePath, '', m.lcLuna, 1, 100, 1) lcSavePath = Strtran(m.lcSavePath, '', m.lcLuna3, 1, 100, 1) lcSavePath = Strtran(m.lcSavePath, '', m.lcLuna2, 1, 100, 1) lcSavePath = Strtran(m.lcSavePath, '', m.lcDataAct, 1, 100, 1) lcSavePath = Strtran(m.lcSavePath, '', m.lcDataAct, 1, 100, 1) lcSavePath = Strtran(m.lcSavePath, '', m.lcPartener, 1, 100, 1) lcSavePath = Strtran(m.lcSavePath, '', m.lcPartener, 1, 100, 1) lcSavePath = Strtran(m.lcSavePath, '', 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, '', m.lcIdIncarcare, 1, 100, 1) lcFile2 = Strtran(m.lcFile2, '', m.lcIdDescarcare, 1, 100, 1) lcFile2 = Strtran(m.lcFile2, '', m.lcDataAct, 1, 100, 1) lcFile2 = Strtran(m.lcFile2, '', m.lcPartener, 1, 100, 1) lcFile2 = Strtran(m.lcFile2, '', 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, [ ], []) * 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('', 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 într-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 într-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('', 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), descriere M null, detalii_plata M null, diferenta N(16,4), 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, decode(creditnote,0,1,-1) * NVL(total_cu_tva, 0.00)-NVL(jtotctva, 0.00) 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), descriere M null, detalii_plata M null, diferenta N(16,4), 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, decode(creditnote,0,1,-1) * NVL(total_cu_tva, 0.00)-NVL(jtotctva, 0.00) 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 * 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), diferenta N(16,4), 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, decode(creditnote,0,1,-1) * ROUND(NVL(xtotal_cu_tva , 0.00) * decode(in_valuta,1,curs,1), 2)-NVL(jtotctva, 0.00) 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) If m.lcToken <> loServer.cToken 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 * Intoarce tokenul de acces la ANAF (eFactura) daca este salvat sau obtine un nou token * Se apeleaza din formularul anaf_token.do_executa Function newToken AMESSAGEBOX('Introduceti in calculator tokenul USB cu semnatura electronica' + Chr(13) + Chr(10) + ; 'Se va deschide pagina ANAF de generare token. Introduceti PIN-ul pentru semnatura electronica.' + Chr(13) + Chr(10) + ; 'Copiati codurile "Token" si "Refresh Token" afisate si completati-le in ROA.', 0 + 64, _Screen.Caption) lcURL = [https://romfast.ro/oauth2/] open_default_app(m.lcURL) 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) + '' 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 10 && caut prefixul la a doua aparitie a < lcPrefixInvoice = STREXTRACT(m.lcFileText, [<], [Invoice],2,1) && un prefix custom la Invoice ] && [] lcPrefix = GetRegExp(m.lcFileText, m.lcPattern) lcPrefix = STREXTRACT(NVL(m.lcPrefix, ''), [] lcPrefix = GetRegExp(m.lcFileText, m.lcPattern) lcPrefix = STREXTRACT(NVL(m.lcPrefix, ''), [ RON, atunci extrag valoare tva in RON * Sunt 2 TaxTotal, una in valuta facturii si una in RON *!* *!* 0.00 *!* 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