Borderou eFactura: import manual arhiva zip descarcata din SPV

AnafeFacturaServer.ImportZipLocal (programe/anaf_efactura.prg): dezarhiveaza
arhiva aleasa de utilizator, ia xml-ul facturii (ignora semnatura MFinante),
ParseEFactura, decide FACTURA PRIMITA/TRIMISA dupa codul fiscal al firmei
curente, copiaza arhiva in directorul local de raspunsuri si scrie in Oracle
prin acelasi lant ca descarcarea din SPV (cursor temporar canaf_efactura_temp
+ cUpdateFactura + UpdateDb -> pack_anaf.AdaugaRaspunsFactura si
anaf_efactura_detalii). Fara SQL scris de mana si fara duplicarea maparii de
campuri.

clase/anaf_efactura.vcx (clasa anaf_efactura, metoda citesteraspunsuri):
optiunea 8 in meniul butonului "Raspunsuri" - "Import arhiva zip de pe disc...".

Necesar cand mesajul nu mai e in lista de raspunsuri ANAF (expira dupa 60 zile)
si factura primita nu a ajuns in borderou.

Testare (CENTRAL/MARIUSM_AUTO, ianuarie 2026, 12 PASS / 0 FAIL):
utile/Teste/efactura_import/ - garda pe cod fiscal, import complet cu verificarea
campurilor si a liniilor in anaf_efactura_detalii, factura vizibila in grila reala
"Facturi primite in SPV".

utile/Teste/test_init_env_auto.prg: adauga goFirma.codfiscalfro ca in start_firma
(ostartfirma.prg) - proprietatea nu e coloana in v_firme, iar fara ea orice cod
care o citeste nepazit crapa in mediul headless.

docs/depanare_testare_vfp.md: verificarea de sintaxa prin compilare headless
(config.fpw cu SAFETY=OFF, copie in scratchpad) si capcana literalelor string
mai lungi de 255 de caractere (eroare de compilare, nu de runtime).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RqJ7D5ftMbChDyz5mpVkCd
This commit is contained in:
2026-07-24 10:43:28 +03:00
parent 97ec743559
commit 95bb2b5b74
6 changed files with 415 additions and 3 deletions

View File

@@ -1135,6 +1135,109 @@ ENDTEXT
RETURN m.llSucces
ENDPROC && ProcesareRaspunsuri
*********************************
*!* 24.07.2026 marius.mutu - import manual arhiva zip eFactura descarcata din SPV
*********************************
PROCEDURE ImportZipLocal
LPARAMETERS tcZipFile
* tcZipFile: (optional) arhiva zip descarcata din SPV. Daca lipseste, se alege cu Getfile
Local laFiles[1], lcCodFiscalClient, lcCodFiscalFurnizor, lcDir, lcErrorMessage, lcFilePath
Local lcId, lcSemnatura, lcTip, lcXmlFile, lcZipFile, llSucces, lnFile, lnFiles, loFactura
lcZipFile = IIF(TYPE('tcZipFile') = 'C' AND !EMPTY(NVL(m.tcZipFile, '')), ALLTRIM(m.tcZipFile), GETFILE('zip', 'Arhiva zip eFactura', 'Import'))
IF EMPTY(m.lcZipFile) OR !FILE(m.lcZipFile)
RETURN .F.
ENDIF
lcDir = ADDBS(SYS(2023)) + SYS(2015) + '\'
lcErrorMessage = ''
llSucces = This.UnzipFile(m.lcZipFile, @lcDir, @lcErrorMessage)
IF !m.llSucces
AMESSAGEBOX('Eroare la dezarhivarea ' + m.lcZipFile + CHR(13) + CHR(10) + m.lcErrorMessage, 0+48, _SCREEN.Caption)
RETURN .F.
ENDIF
* xml-ul facturii este fisierul xml care nu este semnatura MFinante
lcXmlFile = ''
lnFiles = ADIR(laFiles, ADDBS(m.lcDir) + '*.xml')
FOR lnFile = 1 TO m.lnFiles
IF !('SEMNATURA' $ UPPER(laFiles[m.lnFile, 1]))
lcXmlFile = ADDBS(m.lcDir) + ALLTRIM(laFiles[m.lnFile, 1])
EXIT
ENDIF
ENDFOR
IF EMPTY(m.lcXmlFile)
AMESSAGEBOX('Arhiva nu contine fisierul xml al facturii!', 0+48, _SCREEN.Caption)
RETURN .F.
ENDIF
lcId = ALLTRIM(JUSTSTEM(m.lcXmlFile))
loFactura = ParseEFactura(m.lcXmlFile)
IF TYPE('loFactura') <> 'O' OR loFactura.Eroare
AMESSAGEBOX('Eroare la citirea facturii din ' + m.lcXmlFile, 0+48, _SCREEN.Caption)
RETURN .F.
ENDIF
lcCodFiscalFurnizor = UPPER(ALLTRIM(GetNrFromString(NVL(loFactura.CodFiscalFurnizor, ''))))
lcCodFiscalClient = UPPER(ALLTRIM(GetNrFromString(NVL(loFactura.CodFiscalClient, ''))))
DO CASE
CASE !EMPTY(m.lcCodFiscalClient) AND m.lcCodFiscalClient == ALLTRIM(This.cCodFiscal)
lcTip = 'FACTURA PRIMITA'
CASE !EMPTY(m.lcCodFiscalFurnizor) AND m.lcCodFiscalFurnizor == ALLTRIM(This.cCodFiscal)
lcTip = 'FACTURA TRIMISA'
OTHERWISE
AMESSAGEBOX('Factura nu apartine firmei curente (cod fiscal ' + ALLTRIM(This.cCodFiscal) + ')!' + CHR(13) + CHR(10) + ;
'Emitent: ' + m.lcCodFiscalFurnizor + ' Beneficiar: ' + m.lcCodFiscalClient, 0+48, _SCREEN.Caption)
RETURN .F.
ENDCASE
* Salvez arhiva in directorul local de raspunsuri, ca la descarcarea din SPV
lcFilePath = GetPdfPath('EFACTURA', IIF(m.lcTip == 'FACTURA PRIMITA', 'PRIMITE', 'TRIMISE')) + m.lcId + '_' + m.lcId + '.zip'
IF !FILE(m.lcFilePath)
This.SaveFile(m.lcZipFile, .F., JUSTPATH(m.lcFilePath), JUSTFNAME(m.lcFilePath))
ENDIF
* Cursor temporar cu structura din InitDB, cu factura importata
llSucces = goExecutor.oExecuta("select a.*, cast(NULL as varchar2(1000)) as factura_detalii, 0 as modificat from anaf_efactura a where 1 = 0", "canaf_efactura_temp")
IF !m.llSucces
AMESSAGEBOX('Eroare la citirea structurii anaf_efactura!', 0+48, _SCREEN.Caption)
RETURN .F.
ENDIF
INSERT INTO canaf_efactura_temp (id_incarcare, id_descarcare, data_raspuns, mesaj_raspuns, tip_mesaj_raspuns, ;
cod_fiscal_emitent, cod_fiscal_beneficiar, factura_emisa, test, descarcat, filepath, detalii, modificat) ;
VALUES (m.lcId, m.lcId, DATETIME(), 'Import manual ' + JUSTFNAME(m.lcZipFile), m.lcTip, ;
m.lcCodFiscalFurnizor, m.lcCodFiscalClient, IIF(m.lcTip == 'FACTURA PRIMITA', 0, 1), IIF(This.lTest, 1, 0), ;
0, m.lcFilePath, FILETOSTR(m.lcXmlFile), 1)
TABLEUPDATE(1, .F., 'canaf_efactura_temp')
ADDPROPERTY(loFactura, 'cIdIncarcare', m.lcId)
This.cUpdateFactura(loFactura, 'canaf_efactura_temp')
llSucces = This.UpdateDb('canaf_efactura_temp')
USE IN (SELECT('canaf_efactura_temp'))
lcSemnatura = ADDBS(m.lcDir) + 'semnatura_' + m.lcId + '.xml'
DELETE FILE (m.lcXmlFile)
IF FILE(m.lcSemnatura)
DELETE FILE (m.lcSemnatura)
ENDIF
IF m.llSucces
AMESSAGEBOX('Factura ' + ALLTRIM(loFactura.NumarAct) + ' din ' + DTOC(loFactura.DataAct) + ' a fost importata in borderoul eFactura!', 0+64, _SCREEN.Caption)
ENDIF
RETURN m.llSucces
ENDPROC && ImportZipLocal
*********************************
* RASPUNSURI FACTURI