From 0c9255842d2be07a175f6625385ee038a8fb66ff Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Mon, 27 Jul 2026 20:18:49 +0300 Subject: [PATCH] D406 SAF-T: raport erori validator pe intelesul utilizatorului La validarea cu erori se genereaza _explicat.txt: un rand pe eroare (pagina, pozitie, partener/cont identificat, explicatie) + sectiunea "Cum rezolvati". Erorile fictive TaxCode "nu se afla in lista" (bug DUKIntegrator) sunt separate si ignorabile. Se deschid ambele fisiere, raportul explicat deasupra; chatbot-ul primeste doar erorile reale. Mesajul separat de parteneri respinsi + exportul Excel eliminate din flux. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01ExTWMJbKantwNvL6AtEwzH --- Programe/saft_d406.prg | 365 +++++++++++++++++++++++++++++++++++++++-- changelog_roacont.txt | 15 ++ 2 files changed, 367 insertions(+), 13 deletions(-) diff --git a/Programe/saft_d406.prg b/Programe/saft_d406.prg index 2cae4d9..32aa464 100644 --- a/Programe/saft_d406.prg +++ b/Programe/saft_d406.prg @@ -81,6 +81,10 @@ *!* 01.072026 *!* oSalesInvoices - se facea join dublu vanzari - jv2007 in cazul facturilor cu tva la incasare +*!* 27.07.2026 +*!* do_erori_saft, do_ident_saft - raport erori validator pe intelesul utilizatorului (fisierul _explicat.txt): pagina, pozitie, partener/cont identificat, explicatie scurta si sectiunea "Cum rezolvati" +*!* erorile fictive TaxCode "nu se afla in lista" (bug DUKIntegrator) sunt separate si ignorabile; chatbot-ul primeste doar erorile reale; mesajul separat de parteneri respinsi (do_erori_partener_saft) eliminat din flux + * saft_D406 Procedure viz_saft_d406 loD406 = Createobject("D406") @@ -254,10 +258,10 @@ Define Class d406 As Custom Local lcTaxTable, lcTipDeclaratie LOCAL lnBytes, llSucces Local lcAssetTransactions, lcAssets, lcCaleFisier, lcComunPath, lcConfigDir, lcFileName - Local lcFisierRaspuns, lcMovementofGoods, lcNumeFisier, lcOwners, lcParams, lcPhysicalStock + Local lcFisierExplicat, lcFisierRaspuns, lcMovementofGoods, lcNumeFisier, lcOwners, lcParams, lcPhysicalStock Local lcProducts, lcUOMTable, lcValidator, lcXMLTemp, lnFileHandle, lnSec, lcSufixCale, lcSufixFisier LOCAL lcMessage, loChatBot, lcMesajErori - LOCAL lnAn1, lnAn2, lnLuna1, lnLuna2 + LOCAL lnAn1, lnAn2, lnLuna1, lnLuna2, lnEroriFictive, lnEroriReale lnAn1 = This.oUnitate.an1 lnLuna1 = This.oUnitate.luna1 @@ -556,20 +560,23 @@ Define Class d406 As Custom OPEN_DEFAULT_APP(m.lcValidator, m.lcParams) ELSE - *!* 26.07.2026 scot din fisierul de erori codurile de partener respinse de validator - lcMesajErori = This.do_erori_partener_saft(m.lcFisierRaspuns) - IF !EMPTY(m.lcMesajErori) - IF AMESSAGEBOX(m.lcMesajErori + CHR(13) + CHR(10) + CHR(13) + CHR(10) + 'Doriti exportul listei in Excel?',0+4+48,_screen.Caption) = 6 - goExport.export2xlsx('cEroriPartSaft', 'erori_cod_partener_saft_' + ALLTRIM(STR(m.lnAn2)) + PADL(m.lnLuna2, 2, '0')) - ENDIF - USE IN (SELECT('cEroriPartSaft')) + *!* 27.07.2026 un singur raport compact cu erorile explicate si identificate, erorile fictive de TaxCode (bug DUKIntegrator) separate + lnEroriReale = 0 + lnEroriFictive = 0 + lcMesajErori = '' + lcFisierExplicat = This.do_erori_saft(m.lcFisierRaspuns, @lnEroriReale, @lnEroriFictive, @lcMesajErori) + OPEN_DEFAULT_APP(m.lcFisierRaspuns) + IF !EMPTY(m.lcFisierExplicat) + OPEN_DEFAULT_APP(m.lcFisierExplicat) ENDIF - IF AMESSAGEBOX('Validare cu erori fisier: ' + m.lcFileName + CHR(13) + CHR(10) + 'Doriti sa interogati chatbot-ul de suport tehnic?',0+4+48,_screen.Caption) = 6 - lcMessage = FILETOSTR(m.lcFisierRaspuns) + IF AMESSAGEBOX('Validare cu erori fisier: ' + m.lcFileName + CHR(13) + CHR(10) + ; + 'Erori de rezolvat: ' + ALLTRIM(STR(m.lnEroriReale)) + ; + IIF(m.lnEroriFictive > 0, ' (+' + ALLTRIM(STR(m.lnEroriFictive)) + ' fictive - bug validator, se pot ignora)', '') + CHR(13) + CHR(10) + CHR(13) + CHR(10) + ; + 'Doriti sa interogati chatbot-ul de suport tehnic?',0+4+48,_screen.Caption) = 6 + lcMessage = EVL(m.lcMesajErori, FILETOSTR(m.lcFisierRaspuns)) loChatBot = CREATEOBJECT("oChatBotLaunch", m.lcMessage) loChatBot.Launch() - ENDIF - OPEN_DEFAULT_APP(m.lcFisierRaspuns) + ENDIF ENDIF ELSE AMESSAGEBOX('Nu s-a creat fisierul raspuns ' + m.lcFisierRaspuns + ' dupa validare!', 0+48,_screen.Caption) @@ -1311,6 +1318,338 @@ and b1.cont = b2.cont RETURN m.lcMesaj ENDPROC && do_erori_partener_saft + ************************************************* + * Parseaza fisierul de raspuns al validatorului ANAF, grupeaza erorile cu + * explicatii pe intelesul utilizatorului si separa erorile fictive de TaxCode + * (bug DUKIntegrator: apar cand exista alta eroare reala, pentru coduri valide) + * Scrie raportul in _explicat.txt si intoarce calea lui, gol la esec + ************************************************* + PROCEDURE do_erori_saft + LPARAMETERS tcFisierRaspuns, tnReale, tnFictive, tcMesajChat + + LOCAL lcActiune, lcCRLF, lcCod, lcFisierExplicat, lcIdent, lcLegenda, lcLinie, lcLocatie, lcMarker + LOCAL lcMesaj, lcMesajChat, lcPagina, lcProblema, lcRaport, lcSelect, lcValoare, llFictiv, lnCateg + LOCAL lnFictive, lnFile, lnI, lnPoz, lnRand, lnReale + + lcFisierExplicat = '' + lcCRLF = CHR(13) + CHR(10) + lcSelect = SELECT() + + IF !FILE(m.tcFisierRaspuns) + RETURN m.lcFisierExplicat + ENDIF + + *!* o eroare = linia de localizare "E:/F: sectiune ... (N)" + linia de mesaj; erorile fatale de parsare sunt pe o singura linie + CREATE CURSOR cErrSaft (categ N(3), pagina C(30), rand N(7), valoare C(30), mesaj C(240), brut M) + lnFile = FOPEN(m.tcFisierRaspuns, 0) + IF m.lnFile < 0 + USE IN (SELECT('cErrSaft')) + SELECT (m.lcSelect) + RETURN m.lcFisierExplicat + ENDIF + lcLocatie = '' + DO WHILE !FEOF(m.lnFile) + lcLinie = FGETS(m.lnFile, 8192) + IF INLIST(LEFT(LTRIM(m.lcLinie), 2), 'E:', 'F:') + lcLocatie = m.lcLinie + LOOP + ENDIF + IF ATC('Eroare fatala de parsare', m.lcLinie) > 0 + INSERT INTO cErrSaft (categ, pagina, rand, valoare, mesaj, brut) VALUES (11, '', 0, '', LEFT(ALLTRIM(m.lcLinie), 240), m.lcLinie) + lcLocatie = '' + LOOP + ENDIF + lcMesaj = ALLTRIM(m.lcLinie) + IF EMPTY(m.lcMesaj) OR EMPTY(m.lcLocatie) + LOOP + ENDIF + + * pagina din aplicatie, dupa sectiunea din linia de localizare + DO CASE + CASE ATC('PurchaseInvoices', m.lcLocatie) > 0 + lcPagina = 'Facturi achizitie' + CASE ATC('SalesInvoices', m.lcLocatie) > 0 + lcPagina = 'Facturi vanzare' + CASE ATC('Payments', m.lcLocatie) > 0 + lcPagina = 'Plati' + CASE ATC('MovementOfGoods', m.lcLocatie) > 0 + lcPagina = 'Miscari bunuri' + CASE ATC('AssetTransactions', m.lcLocatie) > 0 + lcPagina = 'Tranzactii active' + CASE ATC('GeneralLedgerEntries', m.lcLocatie) > 0 + lcPagina = 'Inregistrari contabile' + CASE ATC('GeneralLedgerAccounts', m.lcLocatie) > 0 + lcPagina = 'Conturi contabile' + CASE ATC('Customers', m.lcLocatie) > 0 + lcPagina = 'Clienti' + CASE ATC('Suppliers', m.lcLocatie) > 0 + lcPagina = 'Furnizori' + CASE ATC('TaxTable', m.lcLocatie) > 0 + lcPagina = 'Nomenclator coduri taxa' + CASE ATC('Products', m.lcLocatie) > 0 + lcPagina = 'Articole' + CASE ATC('PhysicalStock', m.lcLocatie) > 0 + lcPagina = 'Stocuri' + CASE ATC('Assets', m.lcLocatie) > 0 + lcPagina = 'Active' + CASE ATC('Header', m.lcLocatie) > 0 + lcPagina = 'Definirea Companiei' + OTHERWISE + lcPagina = '' + ENDCASE + + * pozitia din grid = indexul elementului de nivel document din localizare + lnRand = 0 + FOR lnI = 1 TO 8 + lcMarker = 'sectiune ' + GETWORDNUM('Transaction,Invoice,Payment,Customer,Supplier,Account,Asset,Product', m.lnI, ',') + ' (' + lnPoz = ATC(m.lcMarker, m.lcLocatie) + IF m.lnPoz > 0 + lnRand = INT(VAL(SUBSTR(m.lcLocatie, m.lnPoz + LEN(m.lcMarker)))) + EXIT + ENDIF + ENDFOR + + lcValoare = '' + DO CASE + CASE ATC('formatul este invalid', m.lcMesaj) > 0 AND (ATC('CustomerID', m.lcMesaj) > 0 OR ATC('SupplierID', m.lcMesaj) > 0 OR ATC('RegistrationNumber', m.lcMesaj) > 0) + lnCateg = 1 + CASE ATC('nu se afla in lista', m.lcMesaj) > 0 AND ATC('TaxCode (', m.lcLocatie) > 0 + lnCateg = 12 + lcValoare = STREXTRACT(m.lcMesaj, [valoarea '], [']) + CASE ATC('vid nepermis', m.lcMesaj) > 0 AND (ATC('CustomerID (', m.lcLocatie) > 0 OR ATC('SupplierID (', m.lcLocatie) > 0) + lnCateg = 2 + CASE ATC([elementul 'AccountID'], m.lcMesaj) > 0 AND ATC('Payments', m.lcLocatie) > 0 + lnCateg = 3 + CASE ATC([elementul 'InvoiceLine'], m.lcMesaj) > 0 + lnCateg = 4 + CASE ATC([elementul 'RegistrationNumber'], m.lcMesaj) > 0 OR (ATC('vid nepermis', m.lcMesaj) > 0 AND ATC('RegistrationNumber (', m.lcLocatie) > 0) + lnCateg = 5 + CASE ATC('planul de conturi', m.lcMesaj) > 0 + lnCateg = 6 + lcValoare = STREXTRACT(m.lcMesaj, '[', ']') + CASE ATC('vid nepermis', m.lcMesaj) > 0 AND ATC('AccountDescription', m.lcLocatie) > 0 + lnCateg = 7 + CASE ATC('BankAccount_choice', m.lcMesaj) > 0 + lnCateg = 8 + CASE ATC('SupplierInfo_choice', m.lcMesaj) > 0 + lnCateg = 9 + CASE ATC([elementul 'Transaction'], m.lcMesaj) > 0 + lnCateg = 10 + OTHERWISE + lnCateg = 13 + ENDCASE + INSERT INTO cErrSaft (categ, pagina, rand, valoare, mesaj, brut) ; + VALUES (m.lnCateg, m.lcPagina, m.lnRand, LEFT(m.lcValoare, 30), IIF(m.lnCateg = 13, LEFT(m.lcMesaj, 240), ''), m.lcLocatie + m.lcCRLF + m.lcLinie) + lcLocatie = '' + ENDDO + = FCLOSE(m.lnFile) + + IF RECCOUNT('cErrSaft') = 0 + USE IN (SELECT('cErrSaft')) + SELECT (m.lcSelect) + RETURN m.lcFisierExplicat + ENDIF + + *!* erorile fictive TaxCode (bug DUKIntegrator): codul semnalat exista de fapt in nomenclator + SELECT DISTINCT valoare FROM cErrSaft WHERE categ = 12 INTO CURSOR cCodTaxaVerif + SELECT cCodTaxaVerif + SCAN + lcCod = ALLTRIM(cCodTaxaVerif.valoare) + IF EMPTY(m.lcCod) OR LEN(CHRTRAN(m.lcCod, '0123456789', '')) > 0 + LOOP + ENDIF + llFictiv = .F. + IF USED('cTaxTable') + SELECT cTaxTable + LOCATE FOR ALLTRIM(STR(taxcode)) == m.lcCod + llFictiv = FOUND() + ELSE + IF goExecutor.oExecuta('SELECT taxcode FROM vsaft_taxtable WHERE taxcode = ' + m.lcCod, 'cTaxVerifTmp') + llFictiv = (RECCOUNT('cTaxVerifTmp') > 0) + USE IN (SELECT('cTaxVerifTmp')) + ENDIF + ENDIF + IF m.llFictiv + UPDATE cErrSaft SET categ = 90 WHERE categ = 12 AND ALLTRIM(valoare) == m.lcCod + ENDIF + SELECT cCodTaxaVerif + ENDSCAN + USE IN (SELECT('cCodTaxaVerif')) + + SELECT cErrSaft + COUNT FOR categ = 90 TO lnFictive + + *!* textul pentru chatbot: erorile brute, fara cele fictive (bug validator) + lcMesajChat = '' + SELECT cErrSaft + SCAN FOR categ < 90 + lcMesajChat = m.lcMesajChat + brut + m.lcCRLF + ENDSCAN + + *!* dedup: aceeasi problema pe aceeasi pozitie o singura data (ex: CustomerID + RegistrationNumber pe acelasi client) + SELECT DISTINCT categ, pagina, valoare, mesaj, rand FROM cErrSaft WHERE categ < 90 ORDER BY 1, 2, 5 INTO CURSOR cErrPoz + lnReale = RECCOUNT('cErrPoz') + + lcRaport = 'ERORI VALIDARE D406 SAF-T - ' + JUSTFNAME(m.tcFisierRaspuns) + m.lcCRLF + ; + 'Erori de rezolvat: ' + ALLTRIM(STR(m.lnReale)) + ' | Fictive (bug validator, se pot ignora): ' + ALLTRIM(STR(m.lnFictive)) + m.lcCRLF + ; + REPLICATE('=', 110) + m.lcCRLF + lcLegenda = '' + SELECT cErrPoz + SCAN + lcIdent = This.do_ident_saft(ALLTRIM(cErrPoz.pagina), cErrPoz.rand) + lcActiune = '' + DO CASE + CASE cErrPoz.categ = 1 + lcProblema = 'cod partener SAF-T invalid (CUI/CNP gresit sau tip PJ/PF gresit)' + lcActiune = 'Parteneri: corectati tip persoana / cod fiscal in Initializare > Entitati; CNP-uri invalide in masa: Initializari cod taxa/plata > Stergere CNP-uri invalide' + CASE cErrPoz.categ = 2 + lcProblema = 'partener fara cod fiscal pe plata (sau nota nu e plata catre terti)' + lcActiune = 'Plati: completati codul fiscal al partenerului (partener virtual: CUI-ul firmei) sau stergeti codul de plata de pe notele care nu sunt plati catre terti, in Registrul Jurnal' + CASE cErrPoz.categ = 3 + lcProblema = 'plata fara cont contabil (nota nu e plata catre terti)' + lcActiune = 'Plati: completati codul fiscal al partenerului (partener virtual: CUI-ul firmei) sau stergeti codul de plata de pe notele care nu sunt plati catre terti, in Registrul Jurnal' + CASE cErrPoz.categ = 4 + lcProblema = 'factura fara articole (probabil document sters)' + lcActiune = 'Facturi fara articole: Refacere Registru TVA Cumparari/Vanzari, apoi regenerati D406' + CASE cErrPoz.categ = 5 + lcProblema = 'PJ fara cod fiscal sau PF marcata ca PJ' + lcActiune = 'Parteneri: corectati tip persoana / cod fiscal in Initializare > Entitati; CNP-uri invalide in masa: Initializari cod taxa/plata > Stergere CNP-uri invalide' + CASE cErrPoz.categ = 6 + lcProblema = 'contul ' + ALLTRIM(cErrPoz.valoare) + ' nu exista in planul de conturi' + lcActiune = 'Conturi: corectati contul in notele din Registrul Jurnal sau completati planul de conturi al firmei' + CASE cErrPoz.categ = 7 + lcProblema = 'cont fara denumire (nu exista in planul de conturi al firmei)' + lcActiune = 'Conturi: corectati contul in notele din Registrul Jurnal sau completati planul de conturi al firmei' + CASE cErrPoz.categ = 8 + lcProblema = 'lipseste contul bancar (IBAN) al firmei' + lcActiune = 'Cont bancar: completati IBAN-ul in Definirea Companiei' + CASE cErrPoz.categ = 9 + lcProblema = 'adresa furnizorului incompleta (judet/localitate) sau document sters' + lcActiune = 'Adresa furnizor: dublu click pe furnizor in Facturi achizitie; daca e document sters cu valoare 0: Refacere Registru TVA Cumparari' + CASE cErrPoz.categ = 10 + lcProblema = 'nu exista note contabile in perioada' + lcActiune = 'Registru gol: introduceti o nota cu valoare 0 (ex: 371 = 371)' + CASE cErrPoz.categ = 11 + lcProblema = ALLTRIM(cErrPoz.mesaj) + lcActiune = 'Caracter nepermis: inlocuiti & cu "si" in campul sursa (denumire/adresa) si regenerati D406' + CASE cErrPoz.categ = 12 + lcProblema = 'cod taxa ' + ALLTRIM(cErrPoz.valoare) + ' inexistent in nomenclatorul SAF-T' + lcActiune = 'Cod taxa: corectati codul de taxa pe notele din Registrul Jurnal' + OTHERWISE + lcProblema = ALLTRIM(cErrPoz.mesaj) + ENDCASE + IF !EMPTY(m.lcActiune) AND ATC(m.lcActiune, m.lcLegenda) = 0 + lcLegenda = m.lcLegenda + '- ' + m.lcActiune + m.lcCRLF + ENDIF + lcRaport = m.lcRaport + PADR(ALLTRIM(cErrPoz.pagina), 20) + ' ' + ; + PADR(IIF(cErrPoz.rand > 0, 'poz.' + ALLTRIM(STR(cErrPoz.rand)), ''), 8) + ' ' + ; + IIF(EMPTY(m.lcIdent), '', PADR(m.lcIdent, 45) + ' ') + '- ' + m.lcProblema + m.lcCRLF + ENDSCAN + USE IN (SELECT('cErrPoz')) + IF m.lnReale = 0 + lcRaport = m.lcRaport + 'Niciuna.' + m.lcCRLF + ENDIF + IF !EMPTY(m.lcLegenda) + lcRaport = m.lcRaport + m.lcCRLF + 'CUM REZOLVATI:' + m.lcCRLF + m.lcLegenda + ENDIF + + IF m.lnFictive > 0 + lcIdent = '' + SELECT valoare, COUNT(*) AS nr FROM cErrSaft WHERE categ = 90 GROUP BY 1 ORDER BY 1 INTO CURSOR cErrFictivSaft + SELECT cErrFictivSaft + SCAN + lcIdent = m.lcIdent + IIF(EMPTY(m.lcIdent), '', ', ') + ALLTRIM(cErrFictivSaft.valoare) + ' (' + ALLTRIM(STR(cErrFictivSaft.nr)) + 'x)' + ENDSCAN + USE IN (SELECT('cErrFictivSaft')) + lcRaport = m.lcRaport + m.lcCRLF + 'FICTIVE - BUG VALIDATOR ANAF (se pot ignora): cod taxa ' + m.lcIdent + m.lcCRLF + ; + 'Codurile sunt valide (exista in nomenclator); erorile apar doar cand exista alta eroare reala si dispar dupa rezolvarea ei.' + m.lcCRLF + ENDIF + + lcRaport = m.lcRaport + m.lcCRLF + 'Erorile brute: ' + m.tcFisierRaspuns + m.lcCRLF + + lcFisierExplicat = ADDBS(JUSTPATH(m.tcFisierRaspuns)) + JUSTSTEM(m.tcFisierRaspuns) + '_explicat.txt' + IF FILE(m.lcFisierExplicat) + DELETE FILE (m.lcFisierExplicat) + ENDIF + = STRTOFILE(m.lcRaport, m.lcFisierExplicat) + IF !FILE(m.lcFisierExplicat) + lcFisierExplicat = '' + ENDIF + + USE IN (SELECT('cErrSaft')) + SELECT (m.lcSelect) + tnReale = m.lnReale + tnFictive = m.lnFictive + tcMesajChat = m.lcMesajChat + + RETURN m.lcFisierExplicat + ENDPROC && do_erori_saft + + ************************************************* + * Identificatorul de afisat pentru pozitia tnRand din cursorul paginii tcPagina + * (sectiunile XML se scriu prin SCAN secvential, deci pozitia din eroare este + * a tnRand-a inregistrare vizibila; la Conturi ramane activ filtrul writer-ului) + ************************************************* + PROCEDURE do_ident_saft + LPARAMETERS tcPagina, tnRand + + LOCAL lcAlias, lcIdent, lcSelect, lnRecno + + lcIdent = '' + IF m.tnRand <= 0 + RETURN m.lcIdent + ENDIF + DO CASE + CASE m.tcPagina == 'Clienti' + lcAlias = 'cCustomers' + CASE m.tcPagina == 'Furnizori' + lcAlias = 'cSuppliers' + CASE m.tcPagina == 'Conturi contabile' + lcAlias = 'cGeneralLedgerAccounts' + CASE m.tcPagina == 'Inregistrari contabile' + lcAlias = 'cGeneralLedgerEntries' + CASE m.tcPagina == 'Plati' + lcAlias = 'cPayments' + CASE m.tcPagina == 'Facturi vanzare' + lcAlias = 'cSalesInvoices' + CASE m.tcPagina == 'Facturi achizitie' + lcAlias = 'cPurchaseInvoices' + OTHERWISE + lcAlias = '' + ENDCASE + IF EMPTY(m.lcAlias) OR !USED(m.lcAlias) + RETURN m.lcIdent + ENDIF + + lcSelect = SELECT() + SELECT (m.lcAlias) + lnRecno = RECNO() + GO TOP + IF m.tnRand > 1 AND !EOF() + SKIP m.tnRand - 1 + ENDIF + IF !EOF() + DO CASE + CASE INLIST(m.lcAlias, 'cCustomers', 'cSuppliers') + lcIdent = ALLTRIM(NVL(saftpartid, '')) + ' ' + ALLTRIM(NVL(denumire, '')) + CASE m.lcAlias == 'cGeneralLedgerAccounts' + lcIdent = 'cont ' + ALLTRIM(NVL(cont, '')) + ' ' + ALLTRIM(NVL(denumire, '')) + CASE m.lcAlias == 'cGeneralLedgerEntries' + lcIdent = 'nota ' + ALLTRIM(TRANSFORM(cod)) + IIF(EMPTY(dataact), '', ' / ' + DTOC(dataact)) + ' cont ' + ALLTRIM(NVL(cont, '')) + ' ' + ALLTRIM(NVL(saftpartid, '')) + CASE m.lcAlias == 'cPayments' + lcIdent = IIF(TYPE('denumire') = 'C', ALLTRIM(NVL(denumire, '')) + ' ', '') + LEFT(ALLTRIM(NVL(explicatia, '')), 40) + OTHERWISE + lcIdent = 'fact. ' + ALLTRIM(TRANSFORM(nract)) + IIF(EMPTY(dataact), '', ' / ' + DTOC(dataact)) + ' ' + ALLTRIM(NVL(saftpartid, '')) + ENDCASE + ENDIF + IF BETWEEN(m.lnRecno, 1, RECCOUNT(m.lcAlias)) + GO m.lnRecno + ENDIF + SELECT (m.lcSelect) + + RETURN LEFT(ALLTRIM(m.lcIdent), 45) + ENDPROC && do_ident_saft + && IAU SOLDURILE DIN BALANTA DE VERIFICARE PENTRU CONTURILE DE IMOBLIZARI SI AMORTIZARI && SI LE COMPAR CU VALOAREA DE INVENTAR SI AMORTIZAREA TOTALA DIN IMOBILIZARI CORPORALE/NECORPORALE CONTABIL Procedure do_verifica_imobilizari diff --git a/changelog_roacont.txt b/changelog_roacont.txt index 138df97..5ecb72a 100644 --- a/changelog_roacont.txt +++ b/changelog_roacont.txt @@ -1,3 +1,18 @@ + +