From 4c9b6cbddbb25be6ecf1dbfb4f5ce7da3a1a7ae4 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Fri, 21 Aug 2026 21:09:26 +0300 Subject: [PATCH] Verificarea de duplicate se face document cu document, nu pe primul document din lot Verificarea folosea o singura data VerificaFactura, pe primul rand din actactan. Daca acel document exista deja in ROA nu se scria nimic din tot intervalul; daca nu exista, se scria tot lotul, inclusiv documentele deja importate, care apareau duplicate. EliminaFacturiDuplicate ia intr-o singura interogare pe (an, luna) documentele existente in ACT, le pune intr-un cursor indexat pe an+luna+nract+dataact+explicatia5 si scoate din actactan doar randurile care se potrivesc. VerificaFactura, ramasa fara apelanti, e stearsa. In modul "Nu scrie note contabile" xls-ul de verificare se genereaza chiar daca actualizarea partenerilor sau verificarea de duplicate nu a reusit: notele nu ajung oricum in ROA. Verificat pe ROA_CONPRESS, read-only, pe intrarile din 07/2026: din 152 de randuri raman 15, toate cele 11 facturi reclamate ca lipsa raman in lot, iar factura 1178734 e scoasa doar pe 30.07 (exista in ROA) si pastrata pe 13.07 (nu exista). Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01PmUPGiStqNKSu4wWq2y77Q --- .gitignore | 1 + Teste/test_dry_duplicate.prg | 159 ++++++++++++++++++++++++++++++++ Teste/test_dry_intrari.prg | 150 ++++++++++++++++++++++++++++++ changelog_flora2roa.txt | 13 +++ flora2roa.txt | 2 +- frm_import.sc2 | 173 ++++++++++++++++++++++------------- 6 files changed, 433 insertions(+), 65 deletions(-) create mode 100644 Teste/test_dry_duplicate.prg create mode 100644 Teste/test_dry_intrari.prg diff --git a/.gitignore b/.gitignore index eb64719..0ae9898 100644 --- a/.gitignore +++ b/.gitignore @@ -93,6 +93,7 @@ Teste/screenshots/ Teste/_erori_test.txt Teste/*_log.txt Teste/raport_*.csv +Teste/dry_*.csv # --- Cache text extern (inlocuit de fluxul in-arbore .??2) --- _textcache/ diff --git a/Teste/test_dry_duplicate.prg b/Teste/test_dry_duplicate.prg new file mode 100644 index 0000000..0793d8f --- /dev/null +++ b/Teste/test_dry_duplicate.prg @@ -0,0 +1,159 @@ +* Dry run pe ROA (READ-ONLY): construieste actactan pentru INTRARI 07/2026 exact ca in +* CreeazaNote, apoi apeleaza metoda reala EliminaFacturiDuplicate si raporteaza ce ar fi +* scos din lot si ce ar fi ramas. NU scrie nimic in ROA (metoda face doar SELECT pe act). +* Rezultat: Teste\dry_duplicate_log.txt +SET SAFETY OFF +SET TALK OFF +PUBLIC gcUILog, gcSyncDir, gcDryLog, gnMockRaspuns, gcMockUltimMesaj, gnMockUltimTip + +LOCAL lcDir, lnSucces, lnInainte, lnDupa +LOCAL lnCodSectieBarFlora, lnCodSectieBucatarieFlora, lnCodSectieBarRestaurant, lnCodSectieBucatarieRestaurant +LOCAL lcAcontMarfaBar, lcAcontMarfaBucatarie + +gnMockRaspuns = 6 +gcMockUltimMesaj = '' +gnMockUltimTip = 0 + +lcDir = ADDBS(JUSTPATH(SYS(16,0))) + +DO (m.lcDir + 'test_init_env_auto.prg') WITH .T. +SET PROCEDURE TO (m.lcDir + 'ui_harness.prg') ADDITIVE +SET PROCEDURE TO (m.lcDir + 'mock_amessagebox.prg') ADDITIVE + +gcDryLog = m.lcDir + "dry_duplicate_log.txt" +STRTOFILE('DRY RUN DUPLICATE ' + TTOC(DATETIME()) + CHR(13)+CHR(10), m.gcDryLog) + +DO FORM (gcAppPath + 'frm_import') NAME goImportFrm NOSHOW +goImportFrm.WindowType = 0 +goImportFrm.Show() +goImportFrm.txtData1.Value = DATE(2026,7,1) +goImportFrm.txtData2.Value = DATE(2026,7,31) +goImportFrm.chkTest.Value = 1 + +lnSucces = goImportFrm.ExportDate() +DO Raport WITH 'ExportDate = ' + TRANSFORM(m.lnSucces) +DO Raport WITH 'cIntrariRestaurant = ' + TRANSFORM(RECCOUNT('cIntrariRestaurant')) + ' randuri' + +* --- cClientiFurnizori fara scriere in ROA (id_part = 0) +Select Distinct Cast(0 As I) As id_part, cod, denumire, cod_fiscal, reg_com, adresa, ; + judet As indicativ_judet, tara As cod_tara, banca, cont_banca ; + From npart Into Cursor cClientiFurnizori Readwrite + +* --- cIntrari, copie exacta a SELECT-ului din frm_import.sc2 +lnCodSectieBarFlora = 3 +lnCodSectieBucatarieFlora = 4 +lnCodSectieBarRestaurant = 1 +lnCodSectieBucatarieRestaurant = 2 +lcAcontMarfaBar = goApp.oSettings.cAcontMarfaBar +lcAcontMarfaBucatarie = goApp.oSettings.cAcontMarfaBucatarie + +Select '371' Cont, IIF(INLIST(codsectiedeintrare, m.lnCodSectieBarFlora, m.lnCodSectieBarRestaurant), m.lcAcontMarfaBar, IIF(INLIST(codsectiedeintrare, m.lnCodSectieBucatarieFlora, m.lnCodSectieBucatarieRestaurant), m.lcAcontMarfaBucatarie, '')) AS acont, ; + CAST(IIF(EMPTY(i.cotatva), 0, i.cotatva) as N(2)) As proctva, CAST(Nvl(p.id_part, 0) as I) As id_part, ; + STRTRAN(idinregistrare,'-','0') as nir, ; + TTOD(CTOT(i.DataDocument)) As dataact, CAST(LEFT(ALLTRIM(i.nrdocument),14) as N(14)) As nract, UPPER(ALLTRIM(STR(codsectiedeintrare))) as codsectie, UPPER(denumiresectiedeintrare) as sectie, ; + Sum(i.valoareajustatafaratva) As VALACH, Sum(i.tvavaloareajustata) As VALTVAA ; + FROM cIntrariRestaurant i ; + LEFT Join cClientiFurnizori p On p.cod_fiscal = i.codfiscal ; + Group By 1,2,3,4,5,6,7,8,9 ; + INTO Cursor cIntrari + +* --- actactan, copie exacta a INSERT-ului de baza din frm_import.sc2 +lnIdSet = 50100 +lnIdFdocFactura = 42 +lnAn = 2026 +lnLuna = 7 +lcAcont401 = '01' +lnIdBazaAch21 = 208 +lnIdBazaAch11 = 212 +lnIdBazaAch19 = 103 +lnIdBazaAch9 = 109 +lnIdBazaAch5 = 154 +lnIdBazaAch0 = 113 +lnIdBazaAchS = m.lnIdBazaAch21 +lcExplicatia5 = 'FACTURA ACHIZITIE' + +Create Cursor actactan (cod I, id_set N(5), id_fdoc N(5), an N(4), luna N(2), explicatia C(100) Null, dataact D, dataireg D, nract N(14), serie_act C(10), nnir N(14), scd C(4), ascd V(4), scc C(4), ascc V(4), id_partd N(10), partd C(200), id_partc N(10), partc C(200), proc_tva N(5,2), id_jtva_coloana N(4) Null, explicatia4 C(100), explicatia5 C(100), suma N(16,2), taxcode N(6) null, paymentcode C(9) null, id_factc I, perechec I, id_factD I, pereched I, id_fact I) + +Insert Into actactan (id_set, id_fdoc, an, luna, dataact, dataireg, nract, nnir, scd, ascd, scc, ascc, id_partd, id_partc, proc_tva, id_jtva_coloana, explicatia, explicatia5, suma) ; + SELECT lnIdSet As id_set, lnIdFdocFactura As id_fdoc, m.lnAn As an, m.lnLuna As luna, dataact, dataact As dataireg, INT(nract), INT(VAL(nir)), ; + cont As scd, acont As ascd, '401' As scc, m.lcAcont401 As ascc, 0 As id_partd, id_part As id_partc, ; + 1 + Round(proctva / 100, 2) As proc_tva, ; + CAST(Iif(proctva = 21, m.lnIdBazaAch21, ; + Iif(proctva = 11, m.lnIdBazaAch11, ; + Iif(proctva = 19, m.lnIdBazaAch19, ; + Iif(proctva = 9, m.lnIdBazaAch9, ; + Iif(proctva = 5, m.lnIdBazaAch5, ; + Iif(proctva = 0, m.lnIdBazaAch0, ; + m.lnIdBazaAchS)))))) AS N(4)) As id_jtva_coloana, ; + sectie As explicatia, lcExplicatia5 As explicatia5, ; + SUM(ROUND(VALACH,2)) As suma ; + FROM cIntrari ; + Group by 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 + +lnInainte = RECCOUNT('actactan') +DO Raport WITH 'actactan inainte de filtrare = ' + TRANSFORM(m.lnInainte) + ' randuri' + +* pastrez lista completa, ca sa pot spune exact ce s-a scos +SELECT nract, dataact, explicatia5, suma FROM actactan ORDER BY dataact, nract INTO CURSOR cInainte + +DO Raport WITH '' +DO Raport WITH '--- apel EliminaFacturiDuplicate(50100) pe ROA_CONPRESS ---' +lnSucces = goImportFrm.EliminaFacturiDuplicate(50100) +DO Raport WITH 'EliminaFacturiDuplicate = ' + TRANSFORM(m.lnSucces) + ' (1 = CT_SUCCES)' +IF !EMPTY(gcMockUltimMesaj) + DO Raport WITH 'AMESSAGEBOX: ' + gcMockUltimMesaj +ENDIF + +IF !USED('actactan') + DO Raport WITH 'EROARE: cursorul actactan nu mai exista dupa apel!' + QUIT +ENDIF + +lnDupa = RECCOUNT('actactan') +DO Raport WITH 'actactan dupa filtrare = ' + TRANSFORM(m.lnDupa) + ' randuri' +DO Raport WITH 'randuri scoase = ' + TRANSFORM(m.lnInainte - m.lnDupa) +DO Raport WITH 'tip ascd dupa filtrare = ' + TYPE('actactan.ascd') + +* ce s-a scos (adica exista deja in ROA) +SELECT a.nract, a.dataact, a.suma FROM cInainte a ; + WHERE NOT EXISTS (SELECT 1 FROM actactan b WHERE b.nract = a.nract AND b.dataact = a.dataact) ; + INTO CURSOR cScoase +DO Raport WITH '' +DO Raport WITH '--- documente scoase din lot (deja in ROA): ' + TRANSFORM(RECCOUNT('cScoase')) +SELECT cScoase +SCAN + DO Raport WITH ' scos: nract=' + TRANSFORM(nract) + ' ' + DTOC(dataact) + ' suma=' + TRANSFORM(suma) +ENDSCAN + +DO Raport WITH '' +DO Raport WITH '--- documente ramase de scris: ' + TRANSFORM(m.lnDupa) +SELECT actactan +SCAN + DO Raport WITH ' ramas: nract=' + TRANSFORM(nract) + ' ' + DTOC(dataact) + ' suma=' + TRANSFORM(suma) +ENDSCAN + +* verificarea cheie: cele 11 facturi raportate ca lipsa NU trebuie sa fie scoase +DO Raport WITH '' +DO Raport WITH '--- control: facturile raportate ca lipsa din ROA trebuie sa RAMANA ---' +SELECT nract, dataact FROM actactan ; + WHERE INLIST(nract, 30285003, 1178734, 30285604, 154, 30286234, 30286444, 30286604, 6019064715, 30286873, 6019082505, 30287485) ; + ORDER BY dataact, nract INTO CURSOR cControl +DO Raport WITH 'regasite in lotul ramas: ' + TRANSFORM(RECCOUNT('cControl')) + ' din 12 randuri asteptate' +SELECT cControl +SCAN + DO Raport WITH ' OK ramas: nract=' + TRANSFORM(nract) + ' ' + DTOC(dataact) +ENDSCAN + +SELECT actactan +COPY TO (m.lcDir + 'dry_duplicate_ramase.csv') TYPE CSV +SELECT cScoase +COPY TO (m.lcDir + 'dry_duplicate_scoase.csv') TYPE CSV + +DO Raport WITH '' +DO Raport WITH 'GATA - nu s-a scris nimic in ROA' +QUIT + +PROCEDURE Raport + LPARAMETERS tcText + STRTOFILE(m.tcText + CHR(13) + CHR(10), m.gcDryLog, 1) +ENDPROC diff --git a/Teste/test_dry_intrari.prg b/Teste/test_dry_intrari.prg new file mode 100644 index 0000000..549b171 --- /dev/null +++ b/Teste/test_dry_intrari.prg @@ -0,0 +1,150 @@ +* Dry run: reproduce local pasii din CreeazaNote pentru INTRARI si numara randurile la fiecare pas. +* Fara Oracle, fara scriere. Rezultat: Teste\dry_intrari_log.txt +SET SAFETY OFF +SET TALK OFF +PUBLIC gcUILog, gcSyncDir, gcDryLog + +LOCAL lcDir, lnSucces +LOCAL lnCodSectieBarFlora, lnCodSectieBucatarieFlora, lnCodSectieBarRestaurant, lnCodSectieBucatarieRestaurant +LOCAL lcAcontMarfaBar, lcAcontMarfaBucatarie + +DO test_init_env_auto WITH .F. +SET PROCEDURE TO ui_harness ADDITIVE +SET PROCEDURE TO mock_amessagebox ADDITIVE + +lcDir = ADDBS(JUSTPATH(SYS(16,0))) +gcDryLog = m.lcDir + "dry_intrari_log.txt" +STRTOFILE('DRY RUN INTRARI ' + TTOC(DATETIME()) + CHR(13)+CHR(10), m.gcDryLog) + +DO FORM (gcAppPath + 'frm_import') NAME goImportFrm NOSHOW +goImportFrm.WindowType = 0 +goImportFrm.Show() +goImportFrm.txtData1.Value = DATE(2026,7,1) +goImportFrm.txtData2.Value = DATE(2026,7,31) +goImportFrm.chkTest.Value = 1 + +lnSucces = goImportFrm.ExportDate() +DO Raport WITH 'ExportDate = ' + TRANSFORM(m.lnSucces) +DO Raport WITH 'cIntrariRestaurant = ' + TRANSFORM(RECCOUNT('cIntrariRestaurant')) + ' randuri' +DO Raport WITH 'nPart = ' + TRANSFORM(RECCOUNT('nPart')) + ' randuri' + +* --- cClientiFurnizori, ca in CompleteazaParteneriROA, dar fara scriere in ROA (id_part = 0) +Select Distinct Cast(0 As I) As id_part, cod, denumire, cod_fiscal, reg_com, adresa, ; + judet As indicativ_judet, tara As cod_tara, banca, cont_banca ; + From npart Into Cursor cClientiFurnizori Readwrite +DO Raport WITH 'cClientiFurnizori = ' + TRANSFORM(RECCOUNT('cClientiFurnizori')) + ' randuri' + +* --- pasul 1: cIntrari (copie exacta a SELECT-ului din frm_import.sc2:832) +lnCodSectieBarFlora = 3 +lnCodSectieBucatarieFlora = 4 +lnCodSectieBarRestaurant = 1 +lnCodSectieBucatarieRestaurant = 2 +lcAcontMarfaBar = goApp.oSettings.cAcontMarfaBar +lcAcontMarfaBucatarie = goApp.oSettings.cAcontMarfaBucatarie + +Select '371' Cont, IIF(INLIST(codsectiedeintrare, m.lnCodSectieBarFlora, m.lnCodSectieBarRestaurant), m.lcAcontMarfaBar, IIF(INLIST(codsectiedeintrare, m.lnCodSectieBucatarieFlora, m.lnCodSectieBucatarieRestaurant), m.lcAcontMarfaBucatarie, '')) AS acont, ; + CAST(IIF(EMPTY(i.cotatva), 0, i.cotatva) as N(2)) As proctva, CAST(Nvl(p.id_part, 0) as I) As id_part, ; + STRTRAN(idinregistrare,'-','0') as nir, ; + TTOD(CTOT(i.DataDocument)) As dataact, CAST(LEFT(ALLTRIM(i.nrdocument),14) as N(14)) As nract, UPPER(ALLTRIM(STR(codsectiedeintrare))) as codsectie, UPPER(denumiresectiedeintrare) as sectie, ; + Sum(i.valoareajustatafaratva) As VALACH, Sum(i.tvavaloareajustata) As VALTVAA ; + FROM cIntrariRestaurant i ; + LEFT Join cClientiFurnizori p On p.cod_fiscal = i.codfiscal ; + Group By 1,2,3,4,5,6,7,8,9 ; + INTO Cursor cIntrari + +DO Raport WITH 'cIntrari = ' + TRANSFORM(RECCOUNT('cIntrari')) + ' randuri (asteptat 152)' + +* ce s-a pierdut intre XML si cIntrari +SELECT x.idinregistrare, x.nrdocument, x.datadocument, x.codfiscal, x.denumirefurnizor, x.cotatva, x.valoareajustatafaratva ; + FROM cIntrariRestaurant x ; + WHERE STRTRAN(x.idinregistrare,'-','0') NOT IN (SELECT nir FROM cIntrari) ; + INTO CURSOR cPierduteIntrari +DO Raport WITH 'LIPSA in cIntrari = ' + TRANSFORM(RECCOUNT('cPierduteIntrari')) +DO ListaPierdute WITH 'cPierduteIntrari' + +* --- pasul 2: actactan (copie exacta a celor doua INSERT-uri din frm_import.sc2:917) +lnIdSet = 50100 +lnIdFdocFactura = 42 +lnAn = 2026 +lnLuna = 7 +lcAcont401 = '01' +lcContTVAAchizitie = '4426' +lnIdBazaAch21 = 208 +lnIdTVAAch21 = 209 +lnIdBazaAch11 = 212 +lnIdTVAAch11 = 213 +lnIdBazaAch19 = 103 +lnIdTVAAch19 = 104 +lnIdBazaAch9 = 109 +lnIdTVAAch9 = 110 +lnIdBazaAch5 = 154 +lnIdTVAAch5 = 155 +lnIdBazaAch0 = 113 +lnIdBazaAchS = m.lnIdBazaAch21 +lnIdTVAAchS = m.lnIdTVAAch21 +lcExplicatia5 = 'FACTURA ACHIZITIE' + +Create Cursor actactan (cod I, id_set N(5), id_fdoc N(5), an N(4), luna N(2), explicatia C(100) Null, dataact D, dataireg D, nract N(14), serie_act C(10), nnir N(14), scd C(4), ascd V(4), scc C(4), ascc V(4), id_partd N(10), partd C(200), id_partc N(10), partc C(200), proc_tva N(5,2), id_jtva_coloana N(4) Null, explicatia4 C(100), explicatia5 C(100), suma N(16,2), taxcode N(6) null, paymentcode C(9) null, id_factc I, perechec I, id_factD I, pereched I, id_fact I) + +Insert Into actactan (id_set, id_fdoc, an, luna, dataact, dataireg, nract, nnir, scd, ascd, scc, ascc, id_partd, id_partc, proc_tva, id_jtva_coloana, explicatia, explicatia5, suma) ; + SELECT lnIdSet As id_set, lnIdFdocFactura As id_fdoc, m.lnAn As an, m.lnLuna As luna, dataact, dataact As dataireg, INT(nract), INT(VAL(nir)), ; + cont As scd, acont As ascd, '401' As scc, m.lcAcont401 As ascc, 0 As id_partd, id_part As id_partc, ; + 1 + Round(proctva / 100, 2) As proc_tva, ; + CAST(Iif(proctva = 21, m.lnIdBazaAch21, ; + Iif(proctva = 11, m.lnIdBazaAch11, ; + Iif(proctva = 19, m.lnIdBazaAch19, ; + Iif(proctva = 9, m.lnIdBazaAch9, ; + Iif(proctva = 5, m.lnIdBazaAch5, ; + Iif(proctva = 0, m.lnIdBazaAch0, ; + m.lnIdBazaAchS)))))) AS N(4)) As id_jtva_coloana, ; + sectie As explicatia, lcExplicatia5 As explicatia5, ; + SUM(ROUND(VALACH,2)) As suma ; + FROM cIntrari ; + Group by 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 + +DO Raport WITH 'actactan baza = ' + TRANSFORM(RECCOUNT('actactan')) + ' randuri' + +SELECT c.nir, c.nract, c.dataact, c.sectie, c.proctva, c.valach ; + FROM cIntrari c ; + WHERE INT(VAL(c.nir)) NOT IN (SELECT nnir FROM actactan) ; + INTO CURSOR cPierduteAct +DO Raport WITH 'LIPSA in actactan = ' + TRANSFORM(RECCOUNT('cPierduteAct')) + +* nnir care se suprapun (doua nir diferite -> acelasi nnir) +SELECT nnir, COUNT(*) as nr FROM actactan GROUP BY nnir HAVING COUNT(*) > 1 INTO CURSOR cColiziuni +DO Raport WITH 'nnir cu > 1 rand = ' + TRANSFORM(RECCOUNT('cColiziuni')) + +* verificare directa: facturile despre care stim ca lipsesc din ROA +DO Raport WITH '' +DO Raport WITH '--- facturile raportate ca lipsa, asa cum arata in actactan ---' +SELECT nract, nnir, DTOC(dataact) as zi, scd, ascd, id_partc, suma, explicatia ; + FROM actactan ; + WHERE INLIST(nract, 30285003, 1178734, 30285604, 154, 30286234, 30286444, 30286604, 6019064715, 30286873, 6019082505, 30287485) ; + ORDER BY dataact, nract INTO CURSOR cVerif +SELECT cVerif +SCAN + DO Raport WITH ' nract=' + TRANSFORM(nract) + ' nnir=' + TRANSFORM(nnir) + ' ' + zi + ' ' + scd + '/' + NVL(ascd,'') + ' idp=' + TRANSFORM(id_partc) + ' suma=' + TRANSFORM(suma) +ENDSCAN + +SELECT actactan +COPY TO (m.lcDir + 'dry_actactan.csv') TYPE CSV +SELECT cIntrari +COPY TO (m.lcDir + 'dry_cintrari.csv') TYPE CSV + +QUIT + +PROCEDURE Raport + LPARAMETERS tcText + STRTOFILE(m.tcText + CHR(13) + CHR(10), m.gcDryLog, 1) +ENDPROC + +PROCEDURE ListaPierdute + LPARAMETERS tcAlias + LOCAL lnArie + lnArie = SELECT() + SELECT (m.tcAlias) + SCAN + DO Raport WITH ' ' + ALLTRIM(idinregistrare) + ' nr=' + ALLTRIM(nrdocument) + ' ' + ALLTRIM(denumirefurnizor) + ' ' + TRANSFORM(valoareajustatafaratva) + ENDSCAN + SELECT (m.lnArie) +ENDPROC diff --git a/changelog_flora2roa.txt b/changelog_flora2roa.txt index bfeca33..32497a1 100644 --- a/changelog_flora2roa.txt +++ b/changelog_flora2roa.txt @@ -1,3 +1,16 @@ + +