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

@@ -5228,7 +5228,7 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
PROCEDURE citesteraspunsuri PROCEDURE citesteraspunsuri
Local llSucces, lnOptiune, lnZile, llFortareRaspunsuri, llTest Local llSucces, lnOptiune, lnZile, llFortareRaspunsuri, llTest
lnOptiune = xmenu('Ultima zi;Ultimele 2 zile;Ultimele 3 zile;Ultimele 7 zile;Ultimele 15 zile;Ultimele 30 zile;Ultimele 60 zile') lnOptiune = xmenu('Ultima zi;Ultimele 2 zile;Ultimele 3 zile;Ultimele 7 zile;Ultimele 15 zile;Ultimele 30 zile;Ultimele 60 zile;Import arhiva zip de pe disc...')
IF EMPTY(m.lnOptiune) IF EMPTY(m.lnOptiune)
RETURN RETURN
ENDIF ENDIF
@@ -5238,7 +5238,11 @@ DEFINE CLASS anaf_efactura AS _frmbase OF "_frm_base.vcx"
llTest = This.lTest llTest = This.lTest
*!* llSucces = Thisform.oAnaf.RaspunsuriFacturi(m.lnZile, m.llFortareRaspunsuri) *!* llSucces = Thisform.oAnaf.RaspunsuriFacturi(m.lnZile, m.llFortareRaspunsuri)
llSucces = efactura_client(m.lnZile, m.llFortareRaspunsuri, m.llTest) IF m.lnOptiune = 8
llSucces = Thisform.oAnaf.AnafeFacturaServer.ImportZipLocal()
ELSE
llSucces = efactura_client(m.lnZile, m.llFortareRaspunsuri, m.llTest)
ENDIF
Thisform.LockScreen = .T. Thisform.LockScreen = .T.
save_grid_tag(Thisform.pgfeFactura.page2.grdFacturiPrimite) save_grid_tag(Thisform.pgfeFactura.page2.grdFacturiPrimite)

View File

@@ -105,6 +105,15 @@ obiecte/coloane din ADD OBJECT (strica structura: "Cannot add this object to a G
- Fix-ul unui typo intr-o clasa partajata poate activa defecte latente in aval - Fix-ul unui typo intr-o clasa partajata poate activa defecte latente in aval
(codul care nu rulase niciodata incepe sa ruleze). La regresii dupa fix-uri (codul care nu rulase niciodata incepe sa ruleze). La regresii dupa fix-uri
"inofensive" in COMUN, cauta defectul latent, nu doar diff-ul. "inofensive" in COMUN, cauta defectul latent, nu doar diff-ul.
- **Literal string de peste 255 de caractere = eroare de COMPILARE, nu de runtime** (masurat
24.07.2026: 255 trece, 256 pica). Mesajul difera dupa forma liniei: `Unrecognized command
verb` daca linia incepe cu un apel de metoda (`goExecutor.oExecuta("<sql lung>", 'c')`),
`Command contains unrecognized phrase/keyword` la o atribuire (`lc = "<sir lung>"`).
Insidios: restul programului ruleaza normal, doar linia aceea lipseste din `.fxp` si da
eroare 16 cand se ajunge la ea - deci un test poate raporta "FAIL" pe altceva decat cauza
reala. De aceea tot SQL-ul lung din codebase e scris cu `TEXT TO <var> [TEXTMERGE] NOSHOW`
... `ENDTEXT` sau concatenat din bucati, nu ca literal unic. Verificare rapida:
`awk 'length($0) > 260 {print NR": "length($0)}' fisier.prg`.
- **Coloana de grid cu ControlSource EXPRESIE (nu camp) cere `Bound = .F.`**. - **Coloana de grid cu ControlSource EXPRESIE (nu camp) cere `Bound = .F.`**.
Fara el: eroare 9 "Data type mismatch" la CREATEOBJECT-ul formei (faza de Fara el: eroare 9 "Data type mismatch" la CREATEOBJECT-ul formei (faza de
constructie, raportata la linia apelanta, Details gol). Caz: import_nota.GridArt constructie, raportata la linia apelanta, Details gol). Caz: import_nota.GridArt
@@ -162,7 +171,49 @@ Descoperite depanand harness-ul pentru "Data type mismatch" la `CREATEOBJECT('IM
cursor pe care nu l-ai deschis tu confirma mecanismul (faza de instantiere), cursor pe care nu l-ai deschis tu confirma mecanismul (faza de instantiere),
chiar daca nu e mesajul EXACT din bug-ul original. chiar daca nu e mesajul EXACT din bug-ul original.
## 7. Studiu de caz: "Property CNRCRT is not found" (15.07.2026) ## 7. Verificare de sintaxa prin compilare headless (dupa orice editare de `.prg`)
Cel mai ieftin test dupa o modificare intr-un `.prg`: `COMPILE` headless, care prinde erorile
de sintaxa fara sa porneasca aplicatia si fara Oracle. Reguli:
- **`config.fpw` propriu cu `SAFETY=OFF` si `RESOURCE=OFF`, pasat cu `-c<cale>`** (lipit de
flag, fara spatiu). Fara el, `COMPILE` peste un `.err`/`.fxp` existent si `STRTOFILE` peste
un log existent scot dialogul modal "overwrite?" si procesul pare agatat. `SET SAFETY OFF`
ca prima linie in script e complementar, nu inlocuitor (`-A` singur porneste cu SAFETY ON).
Verificare ca a fost preluat: logheaza `SET("SAFETY")` / `SET("RESOURCE")` la start.
- **`-c<config>` explicit are prioritate si merge impreuna cu `-A`**: desi `-A` ignora
config.fpw-ul implicit, un `-c` explicit tot e preluat (verificat 24.07.2026:
`vfp9.exe -c<config> -A -T script.prg` a raportat `SAFETY=[OFF] RESOURCE=[OFF]`).
- **Compileaza o COPIE a fisierului, in scratchpad, nu sursa din working copy**: `COMPILE`
scrie `.fxp`-ul langa `.prg`, iar `.fxp`-urile din SVN sunt artefacte de build - regenerate
ad-hoc, ar aparea ca modificari in working copy. VFP compileaza fara sa rezolve simbolurile
(clase, functii din alte fisiere), deci copia izolata e suficienta pentru sintaxa.
- **Sterge `.err`-ul vechi inainte de `COMPILE`**, altfel nu poti distinge un `.err` ramas de
la rularea precedenta de unul nou. Verdictul se citeste din existenta `<nume>.err`:
exista => logheaza continutul lui; nu exista => compilare curata.
Sablon (rulat dupa fiecare runda de editare pe `anaf_efactura.prg`, 24.07.2026):
```
SET SAFETY OFF
lcDir = '<scratchpad>\'
STRTOFILE('START ' + TTOC(DATETIME()) + ' SAFETY=' + SET("SAFETY") + CRLF, lcLog)
IF FILE(lcDir + 'copie.err')
DELETE FILE (lcDir + 'copie.err')
ENDIF
COMPILE (lcDir + 'copie.prg')
IF FILE(lcDir + 'copie.err')
STRTOFILE('ERR:' + CRLF + FILETOSTR(lcDir + 'copie.err'), lcLog, 1)
ELSE
STRTOFILE('OK: compilare fara erori', lcLog, 1)
ENDIF
QUIT
```
Nu inlocuieste testul functional: `COMPILE` valideaza sintaxa, nu apeluri catre metode
inexistente sau proprietati gresite (acelea apar abia la runtime).
## 8. Studiu de caz: "Property CNRCRT is not found" (15.07.2026)
Lant complet: `frm_import_extrase_banca.modificanote` copia `crsJTVATemp` fara index Lant complet: `frm_import_extrase_banca.modificanote` copia `crsJTVATemp` fara index
(defect latent) -> coloana `cExplicatieTVA` din `frm_modific2024.grdRulaje` face (defect latent) -> coloana `cExplicatieTVA` din `frm_modific2024.grdRulaje` face

View File

@@ -1135,6 +1135,109 @@ ENDTEXT
RETURN m.llSucces RETURN m.llSucces
ENDPROC && ProcesareRaspunsuri 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 * RASPUNSURI FACTURI

View File

@@ -0,0 +1,237 @@
* test_import_zip_efactura.prg
* Test UI pentru importul manual al unei arhive zip eFactura in borderou
* (COMUN\clase\anaf_efactura.vcx > clasa anaf_efactura + AnafeFacturaServer.ImportZipLocal).
* Mediu: CENTRAL / MARIUSM_AUTO, perioada ianuarie 2026 (data facturii din xml).
*
* Ce acopera:
* T1 - garda pe cod fiscal: arhiva nu apartine firmei de test => import respins, 0 randuri
* T2 - import complet cu codul fiscal al beneficiarului din xml => anaf_efactura + detalii
* T3 - factura apare in grila "Facturi primite" a borderoului real (captura de ecran)
* GETFILE (alegerea fisierului) NU poate fi automatizat headless - functie nativa VFP,
* nu poate fi umbrita de un mock - de aceea arhiva se transmite ca parametru.
*
* Rulare: powershell -ExecutionPolicy Bypass -File test_import_zip_efactura.ps1
SET SAFETY OFF
SET TALK OFF
PUBLIC gcUILog, gcSyncDir, gnMockRaspuns, gcTestDir, gcZipFile, gcIdInc, gcCifBenef
PUBLIC poFacturiEmise, poFacturiPrimite, poFacturiTrimise, poFacturiDetalii
PUBLIC loAnaf, loForm, gnPass, gnFail
gcTestDir = 'D:\ROA\ROACONT\COMUN\utile\Teste\efactura_import\'
gcUILog = gcTestDir + 'test_import_zip_efactura_log.txt'
gcSyncDir = gcTestDir + 'uisync_importzip\'
gcZipFile = 'D:\ROA\ROACONT\5967557693.zip'
gcIdInc = '5967557693'
gcCifBenef = '29923675'
gnMockRaspuns = 6
gnPass = 0
gnFail = 0
STRTOFILE('START ' + TTOC(DATETIME()) + CHR(13) + CHR(10), gcUILog)
ON ERROR DO TErr WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
ON SHUTDOWN QUIT
* Mock-urile se incarca INAINTE de test_init_env_auto: la nume duplicat de procedura
* castiga fisierul incarcat PRIMUL (vezi docs\testare-ui-vfp.md, punctul j)
SET PROCEDURE TO ('D:\ROA\ROACONT\COMUN\utile\Teste\mock_amessagebox.prg') ADDITIVE
SET PROCEDURE TO ('D:\ROA\ROACONT\COMUN\utile\Teste\ui_harness.prg') ADDITIVE
DO ('D:\ROA\ROACONT\COMUN\utile\Teste\test_init_env_auto.prg') WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT', 2026, 1
DO HarnessLog WITH 'INIT gnHandle=' + TRANSFORM(gnHandle) + ' gcS=' + TRANSFORM(gcS) + ' perioada=' + TRANSFORM(gnLuna) + '/' + TRANSFORM(gnAn)
DO HarnessLog WITH 'FIRMA=' + TRANSFORM(gcFirma) + ' cod fiscal=' + TRANSFORM(goFirma.codfiscalfro)
* Curatenie: sterg importul unei rulari anterioare, ca testul sa fie repetabil
goExecutor.oExecuta("delete from anaf_efactura_detalii where id_efactura in (select id from anaf_efactura where id_incarcare = '" + gcIdInc + "')")
goExecutor.oExecuta("delete from anaf_efactura where id_incarcare = '" + gcIdInc + "'")
DO HarnessLog WITH 'CURATENIE randuri anterioare OK'
loAnaf = CREATEOBJECT('ANAFeFactura')
DO HarnessLog WITH 'ANAFeFactura creat; cod fiscal server=' + TRANSFORM(loAnaf.AnafeFacturaServer.cCodFiscal) + ' lTest=' + TRANSFORM(loAnaf.AnafeFacturaServer.lTest)
* ---------- cursoarele borderoului, copie exacta din ANAFeFactura.vizeFactura (anaf_efactura.prg:2867-2942) ----------
* 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()
* ---------- Formularul REAL al borderoului, non-modal (Show(1) ar bloca testul) ----------
Select crsFacturiEmise
loForm = CREATEOBJECT('anaf_efactura', loAnaf)
loForm.WindowType = 0
loForm.Show()
loForm.WindowState = 2
DO HarnessLog WITH 'BORDEROU deschis: [' + TRANSFORM(loForm.Caption) + ']'
DO HarnessStep WITH 0, 'borderou_deschis'
* ---------- T1: garda pe cod fiscal (firma de test nu e nici emitent, nici beneficiar) ----------
llRezultat = loForm.oAnaf.AnafeFacturaServer.ImportZipLocal(gcZipFile)
lnRanduri = 0
goExecutor.oSelecteaza2Value("select count(*) from anaf_efactura where id_incarcare = '" + gcIdInc + "'", @lnRanduri)
DO TVerdict WITH !llRezultat AND NVL(lnRanduri, 0) = 0, 'T1 garda cod fiscal', 'import respins=' + TRANSFORM(!llRezultat) + ' randuri in anaf_efactura=' + TRANSFORM(lnRanduri)
DO HarnessStep WITH 1, 'garda_cod_fiscal'
* ---------- T2: import complet, cu codul fiscal al beneficiarului din xml ----------
loForm.oAnaf.AnafeFacturaServer.cCodFiscal = gcCifBenef
llRezultat = loForm.oAnaf.AnafeFacturaServer.ImportZipLocal(gcZipFile)
DO TVerdict WITH llRezultat, 'T2 import', 'ImportZipLocal a returnat ' + TRANSFORM(llRezultat)
* SQL in TEXT/ENDTEXT: un literal string mai lung de 255 caractere nu compileaza
TEXT TO lcSqlVerif NOSHOW
select id, xnumar_act, xdata_act, xdata_scad, xtotal_fara_tva, xtotal_tva, xtotal_cu_tva, xnume_valuta,
xfurnizor, xclient, tip_mesaj_raspuns, factura_emisa, cod_fiscal_emitent, cod_fiscal_beneficiar,
descarcat, procesat, creditnote, filepath,
nvl(length(detalii),0) as len_detalii, nvl(length(detalii_zip),0) as len_zip
from anaf_efactura
where id_incarcare = ?gcIdInc
ENDTEXT
goExecutor.oExecuta(lcSqlVerif, 'cVerif')
IF USED('cVerif') AND RECCOUNT('cVerif') = 1
SELECT cVerif
GO TOP
DO HarnessLog WITH 'ANAF_EFACTURA id=' + TRANSFORM(cVerif.id) + ' numar=[' + TRANSFORM(cVerif.xnumar_act) + '] data=' + TRANSFORM(cVerif.xdata_act) + ' scadenta=' + TRANSFORM(cVerif.xdata_scad)
DO HarnessLog WITH ' furnizor=[' + TRANSFORM(cVerif.xfurnizor) + '] client=[' + TRANSFORM(cVerif.xclient) + ']'
DO HarnessLog WITH ' fara tva=' + TRANSFORM(cVerif.xtotal_fara_tva) + ' tva=' + TRANSFORM(cVerif.xtotal_tva) + ' cu tva=' + TRANSFORM(cVerif.xtotal_cu_tva) + ' valuta=' + TRANSFORM(cVerif.xnume_valuta)
DO HarnessLog WITH ' tip=[' + TRANSFORM(cVerif.tip_mesaj_raspuns) + '] emisa=' + TRANSFORM(cVerif.factura_emisa) + ' cif emitent=' + TRANSFORM(cVerif.cod_fiscal_emitent) + ' cif benef=' + TRANSFORM(cVerif.cod_fiscal_beneficiar)
DO HarnessLog WITH ' descarcat=' + TRANSFORM(cVerif.descarcat) + ' procesat=' + TRANSFORM(cVerif.procesat) + ' creditnote=' + TRANSFORM(cVerif.creditnote) + ' len(detalii)=' + TRANSFORM(cVerif.len_detalii) + ' len(zip)=' + TRANSFORM(cVerif.len_zip)
DO HarnessLog WITH ' filepath=[' + TRANSFORM(cVerif.filepath) + '] exista pe disc=' + TRANSFORM(FILE(ALLTRIM(NVL(cVerif.filepath, ''))))
DO TVerdict WITH ALLTRIM(NVL(cVerif.xnumar_act, '')) == 'SRC/0000809', 'T2.1 numar factura', TRANSFORM(cVerif.xnumar_act)
DO TVerdict WITH cVerif.xdata_act = {^2026-01-28}, 'T2.2 data factura', TRANSFORM(cVerif.xdata_act)
DO TVerdict WITH ROUND(NVL(cVerif.xtotal_cu_tva, 0), 2) = -5166.63, 'T2.3 total cu tva', TRANSFORM(cVerif.xtotal_cu_tva)
DO TVerdict WITH ROUND(NVL(cVerif.xtotal_fara_tva, 0), 2) = -4269.94, 'T2.4 total fara tva', TRANSFORM(cVerif.xtotal_fara_tva)
DO TVerdict WITH ALLTRIM(UPPER(NVL(cVerif.tip_mesaj_raspuns, ''))) == 'FACTURA PRIMITA' AND NVL(cVerif.factura_emisa, -1) = 0, 'T2.5 tip factura primita', TRANSFORM(cVerif.tip_mesaj_raspuns)
DO TVerdict WITH ALLTRIM(NVL(cVerif.cod_fiscal_emitent, '')) == '17043227' AND ALLTRIM(NVL(cVerif.cod_fiscal_beneficiar, '')) == gcCifBenef, 'T2.6 coduri fiscale', TRANSFORM(cVerif.cod_fiscal_emitent) + '/' + TRANSFORM(cVerif.cod_fiscal_beneficiar)
DO TVerdict WITH NVL(cVerif.len_detalii, 0) > 4000, 'T2.7 xml salvat in detalii', TRANSFORM(cVerif.len_detalii) + ' caractere'
DO TVerdict WITH FILE(ALLTRIM(NVL(cVerif.filepath, ''))), 'T2.8 arhiva copiata local', TRANSFORM(cVerif.filepath)
lnDetalii = 0
goExecutor.oSelecteaza2Value("select count(*) from anaf_efactura_detalii where id_efactura = " + ALLTRIM(STR(cVerif.id)), @lnDetalii)
DO TVerdict WITH NVL(lnDetalii, 0) > 0, 'T2.9 linii in anaf_efactura_detalii', TRANSFORM(lnDetalii) + ' linii'
goExecutor.oExecuta("select nr, articol, cantitate, um, pret, proctva, valoarefaratva from anaf_efactura_detalii where id_efactura = " + ALLTRIM(STR(cVerif.id)) + " order by nr", 'cLinii')
IF USED('cLinii')
SELECT cLinii
SCAN
DO HarnessLog WITH ' linia ' + TRANSFORM(cLinii.nr) + ': [' + TRANSFORM(cLinii.articol) + '] cant=' + TRANSFORM(cLinii.cantitate) + ' ' + TRANSFORM(cLinii.um) + ' pret=' + TRANSFORM(cLinii.pret) + ' tva=' + TRANSFORM(cLinii.proctva) + ' valoare=' + TRANSFORM(cLinii.valoarefaratva)
ENDSCAN
USE IN (SELECT('cLinii'))
ENDIF
ELSE
DO TVerdict WITH .F., 'T2.1-T2.9 verificare in baza de date', 'nu am gasit exact 1 rand in anaf_efactura'
ENDIF
USE IN (SELECT('cVerif'))
DO HarnessStep WITH 2, 'dupa_import'
* ---------- T3: factura in grila reala "Facturi primite" din borderou ----------
* ATENTIE: pagina "Facturi primite in SPV" e obiectul Page2, dar are PageOrder = 3,
* iar ActivePage merge pe PageOrder - deci activarea ei se face cu 3, nu cu 2.
loForm.pgfeFactura.ActivePage = 3
loForm.Refresh()
lnGasit = 0
IF USED('crsFacturiPrimite')
SELECT crsFacturiPrimite
COUNT FOR ALLTRIM(NVL(numar_act, '')) == 'SRC/0000809' TO lnGasit
DO HarnessLog WITH 'crsFacturiPrimite: ' + TRANSFORM(RECCOUNT('crsFacturiPrimite')) + ' randuri, din care factura importata: ' + TRANSFORM(lnGasit)
ENDIF
DO TVerdict WITH lnGasit = 1, 'T3 factura vizibila in grila Facturi primite', TRANSFORM(lnGasit) + ' randuri gasite'
DO HarnessStep WITH 3, 'grila_facturi_primite'
DO HarnessLog WITH 'REZULTAT FINAL: PASS=' + TRANSFORM(gnPass) + ' FAIL=' + TRANSFORM(gnFail)
DO HarnessDone WITH IIF(gnFail = 0, 'done OK', 'done CU ESECURI')
QUIT
***********************
PROCEDURE TVerdict
LPARAMETERS tlOk, tcNume, tcDetalii
IF tlOk
gnPass = gnPass + 1
ELSE
gnFail = gnFail + 1
ENDIF
DO HarnessLog WITH IIF(tlOk, 'PASS ', 'FAIL ') + tcNume + ' | ' + TRANSFORM(tcDetalii)
ENDPROC
***********************
PROCEDURE TErr
LPARAMETERS tnError, tcMessage, tcProgram, tnLine
DO HarnessLog WITH 'EROARE ' + TRANSFORM(tnError) + ' [' + TRANSFORM(tcMessage) + '] in ' + TRANSFORM(tcProgram) + ' linia ' + TRANSFORM(tnLine)
ENDPROC

View File

@@ -0,0 +1,12 @@
# test_import_zip_efactura.ps1 - wrapper peste harness-ul generic pentru testul de import
# arhiva zip eFactura in borderou (clasa anaf_efactura + AnafeFacturaServer.ImportZipLocal).
# Rulare: powershell -ExecutionPolicy Bypass -File test_import_zip_efactura.ps1
$ErrorActionPreference = 'Stop'
$Teste = $PSScriptRoot
& (Join-Path (Split-Path $Teste -Parent) 'vfp_ui_harness.ps1') `
-TestPrg (Join-Path $Teste 'test_import_zip_efactura.prg') `
-Steps @('borderou_deschis','garda_cod_fiscal','dupa_import','grila_facturi_primite') `
-ShotsDir (Join-Path $Teste 'screenshots_importzip') `
-SyncDir (Join-Path $Teste 'uisync_importzip') `
-ReadyTimeoutSec 300 `
-StepTimeoutSec 180

View File

@@ -253,11 +253,16 @@ IF m.llSucces
gnIdSucursala = null gnIdSucursala = null
gcFirma = ALLTRIM(firma) gcFirma = ALLTRIM(firma)
SCATTER NAME goFirma SCATTER NAME goFirma
*!* 24.07.2026 marius.mutu - ca in start_firma (ostartfirma.prg): codfiscalfro nu e coloana in v_firme
IF TYPE('goFirma.codfiscalfro') = 'U'
ADDPROPERTY(goFirma, 'codfiscalfro', ALLTRIM(STRTRAN(ALLTRIM(NVL(goFirma.cod_fiscal, '')), 'RO', '')))
ENDIF
ELSE ELSE
goFirma = CREATEOBJECT('custom') goFirma = CREATEOBJECT('custom')
goFirma.addproperty('cod_fiscal', '') goFirma.addproperty('cod_fiscal', '')
goFirma.addproperty('schema', m.gcS) goFirma.addproperty('schema', m.gcS)
goFirma.addproperty('firma', m.gcS) goFirma.addproperty('firma', m.gcS)
goFirma.addproperty('codfiscalfro', '')
ENDIF ENDIF
USE IN (SELECT('cFirma')) USE IN (SELECT('cFirma'))