*!* 01.09.2026 *!* Biblioteca de comparatie documente v1/v2 (S6-0): fara efecte laterale, doar SELECT, nu emite *!* nimic. Compara doua documente identificate prin SERIE_ACT + NRACT (nu ID_FACT - offset *!* constant intre ID_FACT si ID_VANZARE, vezi docs\propunere_s6_test_flux_real.md 4.1a) pe *!* VANZARI, VANZARI_DETALII, ACT si RUL. *!* *!* Functii publice (consumate de testele S6-1...S6-5): *!* CompDoc(tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta) *!* ruleaza toate cele patru comparatii de mai jos si intoarce numarul total de esecuri *!* CompVanzari(tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta) *!* antetul (VANZARI): campurile de paritate + totalurile denormalizate, egalitate exacta *!* CompVanzariDetalii(tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta) *!* liniile (VANZARI_DETALII), linie cu linie, sortate dupa id_articol, pret, proc_tvav, plus *!* invariantul minim (count, sum(cantitate), sum(cantitate*pret), setul de id_jtva_coloana) *!* CompAct(tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta) *!* multimea de randuri ACT, jonctiune pe serie_act+nract, comparata sortat (nu depinde de *!* ordinea de inserare) *!* CompRul(tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta) *!* multimea de randuri RUL; gol pe ambele parti = PASS, dar raportat explicit ca paritate *!* vida/neconcludenta (RUL are randuri doar cu gnScadereStoc = 1) *!* *!* Fiecare functie de mai sus intoarce numarul de esecuri (0 = paritate completa pe campurile *!* comparate) si scrie fiecare FAIL/REZUMAT in gcLog daca apelantul l-a definit PUBLIC (conventia *!* din acest director); altfel scrie in propriul log implicit (out\lib_comparatie_documente.log). *!* Cere conexiune Oracle deja deschisa (goExecutor functional, gnIdUtil setat de apelant) - nu *!* deschide conexiune proprie si nu face niciun INSERT/UPDATE/DELETE/DDL. *!* *!* Incarcare: SET PROCEDURE TO lib_comparatie_documente ADDITIVE (dupa test_init_env_auto_*). *!* Restul functiilor (Cdoc*) sunt suportul intern, neconsumat direct de teste. #DEFINE CDOC_LOG_IMPLICIT "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_unificat\out\lib_comparatie_documente.log" *---------------------------------------------------------------------------------------- FUNCTION CompDoc LPARAMETERS tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta LOCAL nFail tcEticheta = IIF(EMPTY(tcEticheta), '[fara eticheta]', tcEticheta) DO CdocLog WITH "===== CompDoc " + tcEticheta + " : " + ALLTRIM(tcSerie1) + " " + TRANSFORM(tnNr1) + ; " vs " + ALLTRIM(tcSerie2) + " " + TRANSFORM(tnNr2) + " =====" nFail = 0 nFail = nFail + CompVanzari(tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta) nFail = nFail + CompVanzariDetalii(tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta) nFail = nFail + CompAct(tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta) nFail = nFail + CompRul(tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta) DO CdocLog WITH "TOTAL CompDoc " + tcEticheta + " esecuri=" + TRANSFORM(nFail) RETURN nFail ENDFUNC *---------------------------------------------------------------------------------------- * VANZARI - antetul, campurile din 5.2 (paritate) + totalurile denormalizate (egalitate exacta) FUNCTION CompVanzari LPARAMETERS tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta LOCAL nId1, nId2, nFail, lcCampuri, lcSql, nCnt tcEticheta = IIF(EMPTY(tcEticheta), '[fara eticheta]', tcEticheta) nFail = 0 nId1 = CdocGasesteIdVanzare(tcSerie1, tnNr1) nId2 = CdocGasesteIdVanzare(tcSerie2, tnNr2) IF nId1 <= 0 OR nId2 <= 0 DO CdocLog WITH "FAIL " + tcEticheta + " VANZARI: document negasit, serie1=" + ; ALLTRIM(TRANSFORM(tcSerie1)) + " nr1=" + TRANSFORM(tnNr1) + " id1=" + TRANSFORM(nId1) + ; ", serie2=" + ALLTRIM(TRANSFORM(tcSerie2)) + " nr2=" + TRANSFORM(tnNr2) + " id2=" + TRANSFORM(nId2) RETURN 1 ENDIF lcCampuri = "TIP, ID_PART, ID_GESTIUNE, ID_AGENT, ID_SECTIE, ID_SUCURSALA, ID_RUTA, ID_CTR, " + ; "ID_COMANDA, ID_DELEGAT, ID_MASINA, IN_VALUTA, ID_VALUTA, CURS, MULTIPLICATOR, DISCOUNT, " + ; "DISCOUNT_EVIDENTIAT, DISCOUNT_TVA, TVA_INCASARE, TEXT_ADITIONAL, LISTARE_DETALIATA, " + ; "AFISARE_SCADENTA, COEFICIENT_K, TIP_FACTURA, TIP_SAFT, EFACTURA, EPROFORMA, ID_FACTURARE, " + ; "ID_BENEFICIAR, NR_PERSOANE, NRINMAT, COD, ID_LUCRARE, ID_PUNCTVANZARE, VALOARE_ACHIZITIE, " + ; "DIFTOTFTVA, DIFTOTTVA, COMANDA, CONTRACT, AVIZE, TIP_INCASAT, SERIE_INCASAT, NR_INCASAT, " + ; "SUMA_INCASAT, SERIE_ACT, FACTURAT, TOTAL_FARA_TVA, TOTAL_TVA, TOTAL_CU_TVA, VALVAL, TVAVAL, TOTVAL" nCnt = OCCURS(",", lcCampuri) + 1 lcSql = [select ] + lcCampuri + [ from vanzari where id_vanzare = ] + ALLTRIM(STR(nId1, 20, 0)) IF goExecutor.oExecute(lcSql, 'crslibv1') < 0 DO CdocLog WITH "FAIL " + tcEticheta + " VANZARI: select document 1 esuat - " + goExecutor.oPrelucrareEroare() RETURN 1 ENDIF lcSql = [select ] + lcCampuri + [ from vanzari where id_vanzare = ] + ALLTRIM(STR(nId2, 20, 0)) IF goExecutor.oExecute(lcSql, 'crslibv2') < 0 DO CdocLog WITH "FAIL " + tcEticheta + " VANZARI: select document 2 esuat - " + goExecutor.oPrelucrareEroare() DO CdocInchide WITH 'crslibv1' RETURN 1 ENDIF IF !USED('crslibv1') OR RECCOUNT('crslibv1') = 0 OR !USED('crslibv2') OR RECCOUNT('crslibv2') = 0 DO CdocLog WITH "FAIL " + tcEticheta + " VANZARI: unul din documente nu are rand in VANZARI" nFail = 1 ELSE nFail = CdocComparaCampuri('crslibv1', 'crslibv2', lcCampuri, tcEticheta, ; "VANZARI id1=" + TRANSFORM(nId1) + " id2=" + TRANSFORM(nId2)) ENDIF DO CdocInchide WITH 'crslibv1' DO CdocInchide WITH 'crslibv2' DO CdocLog WITH "REZUMAT " + tcEticheta + " VANZARI id1=" + TRANSFORM(nId1) + " id2=" + ; TRANSFORM(nId2) + " campuri=" + TRANSFORM(nCnt) + " esecuri=" + TRANSFORM(nFail) RETURN nFail ENDFUNC *---------------------------------------------------------------------------------------- * VANZARI_DETALII - linie cu linie (sortate 5.3) + invariantul minim FUNCTION CompVanzariDetalii LPARAMETERS tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta LOCAL nId1, nId2, nFail, lcCampuri, lcSql, nCnt1, nCnt2, i tcEticheta = IIF(EMPTY(tcEticheta), '[fara eticheta]', tcEticheta) nFail = 0 nCnt1 = 0 nCnt2 = 0 nId1 = CdocGasesteIdVanzare(tcSerie1, tnNr1) nId2 = CdocGasesteIdVanzare(tcSerie2, tnNr2) IF nId1 <= 0 OR nId2 <= 0 DO CdocLog WITH "FAIL " + tcEticheta + " VANZARI_DETALII: document negasit (vezi CompVanzari)" RETURN 1 ENDIF lcCampuri = "ID_ARTICOL, ID_POL, CANTITATE, PRET, PRET_CU_TVA, PROC_TVAV, DISCOUNT_UNITAR, " + ; "ID_GESTIUNE, ID_JTVA_COLOANA, ID_JTVA_COLOANA_EX, ID_VALUTA, CONT, EXPLICATIE, SERIE, LOT, " + ; "TAXCODE, CUSTODIE, ID_RATA, ID_CTR, ID_VANZARE_SET, PRET_ACHIZITIE, PRETD, ID_VALUTAD, DIFERENTA" lcSql = [select ] + lcCampuri + [ from vanzari_detalii where sters = 0 and id_vanzare = ] + ; ALLTRIM(STR(nId1, 20, 0)) + [ order by id_articol, pret, proc_tvav] IF goExecutor.oExecute(lcSql, 'crslibd1') < 0 DO CdocLog WITH "FAIL " + tcEticheta + " VANZARI_DETALII: select document 1 esuat - " + goExecutor.oPrelucrareEroare() RETURN 1 ENDIF lcSql = [select ] + lcCampuri + [ from vanzari_detalii where sters = 0 and id_vanzare = ] + ; ALLTRIM(STR(nId2, 20, 0)) + [ order by id_articol, pret, proc_tvav] IF goExecutor.oExecute(lcSql, 'crslibd2') < 0 DO CdocLog WITH "FAIL " + tcEticheta + " VANZARI_DETALII: select document 2 esuat - " + goExecutor.oPrelucrareEroare() DO CdocInchide WITH 'crslibd1' RETURN 1 ENDIF nCnt1 = IIF(USED('crslibd1'), RECCOUNT('crslibd1'), 0) nCnt2 = IIF(USED('crslibd2'), RECCOUNT('crslibd2'), 0) IF nCnt1 <> nCnt2 nFail = nFail + 1 DO CdocLog WITH "FAIL " + tcEticheta + " VANZARI_DETALII numar de linii diferit: v1=" + ; TRANSFORM(nCnt1) + " v2=" + TRANSFORM(nCnt2) ELSE FOR i = 1 TO nCnt1 GO i IN crslibd1 GO i IN crslibd2 nFail = nFail + CdocComparaCampuri('crslibd1', 'crslibd2', lcCampuri, tcEticheta, ; "VANZARI_DETALII linia " + TRANSFORM(i) + " (sortata)") ENDFOR ENDIF * invariantul minim din 5.3, chiar cand liniile nu sunt identice camp cu camp nFail = nFail + CdocInvariantDetalii('crslibd1', nCnt1, 'crslibd2', nCnt2, tcEticheta) DO CdocInchide WITH 'crslibd1' DO CdocInchide WITH 'crslibd2' DO CdocLog WITH "REZUMAT " + tcEticheta + " VANZARI_DETALII id1=" + TRANSFORM(nId1) + " id2=" + ; TRANSFORM(nId2) + " linii1=" + TRANSFORM(nCnt1) + " linii2=" + TRANSFORM(nCnt2) + ; " esecuri=" + TRANSFORM(nFail) RETURN nFail ENDFUNC *---------------------------------------------------------------------------------------- * ACT - multimea de randuri (5.4), jonctiune pe serie_act+nract, comparata sortat FUNCTION CompAct LPARAMETERS tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta LOCAL nFail, lcCampuri, lcOrder, lcSql, nCnt1, nCnt2, i tcEticheta = IIF(EMPTY(tcEticheta), '[fara eticheta]', tcEticheta) nFail = 0 nCnt1 = 0 nCnt2 = 0 lcCampuri = "SCD, SCC, SUMA, ID_JTVA_COLOANA, ID_SET, ID_PARTD, ID_PARTC, ID_SECTIE, " + ; "ID_VENCHELT, ID_CTR, PROC_TVA, NEIMPOZAB, TAXCODE, EXPLICATIA4" lcOrder = " order by " + lcCampuri lcSql = [select ] + lcCampuri + [ from act where sters = 0 and serie_act = '] + ALLTRIM(TRANSFORM(tcSerie1)) + ; [' and nract = ] + ALLTRIM(STR(tnNr1, 20, 0)) + lcOrder IF goExecutor.oExecute(lcSql, 'crsliba1') < 0 DO CdocLog WITH "FAIL " + tcEticheta + " ACT: select document 1 esuat - " + goExecutor.oPrelucrareEroare() RETURN 1 ENDIF lcSql = [select ] + lcCampuri + [ from act where sters = 0 and serie_act = '] + ALLTRIM(TRANSFORM(tcSerie2)) + ; [' and nract = ] + ALLTRIM(STR(tnNr2, 20, 0)) + lcOrder IF goExecutor.oExecute(lcSql, 'crsliba2') < 0 DO CdocLog WITH "FAIL " + tcEticheta + " ACT: select document 2 esuat - " + goExecutor.oPrelucrareEroare() DO CdocInchide WITH 'crsliba1' RETURN 1 ENDIF nCnt1 = IIF(USED('crsliba1'), RECCOUNT('crsliba1'), 0) nCnt2 = IIF(USED('crsliba2'), RECCOUNT('crsliba2'), 0) IF nCnt1 = 0 OR nCnt2 = 0 nFail = nFail + 1 DO CdocLog WITH "FAIL " + tcEticheta + " ACT: unul din documente nu are randuri (v1=" + ; TRANSFORM(nCnt1) + " v2=" + TRANSFORM(nCnt2) + ")" ELSE IF nCnt1 <> nCnt2 nFail = nFail + 1 DO CdocLog WITH "FAIL " + tcEticheta + " ACT numar de randuri diferit: v1=" + ; TRANSFORM(nCnt1) + " v2=" + TRANSFORM(nCnt2) ENDIF FOR i = 1 TO MIN(nCnt1, nCnt2) GO i IN crsliba1 GO i IN crsliba2 nFail = nFail + CdocComparaCampuri('crsliba1', 'crsliba2', lcCampuri, tcEticheta, ; "ACT rand " + TRANSFORM(i) + " (sortat)") ENDFOR ENDIF DO CdocInchide WITH 'crsliba1' DO CdocInchide WITH 'crsliba2' DO CdocLog WITH "REZUMAT " + tcEticheta + " ACT randuri1=" + TRANSFORM(nCnt1) + " randuri2=" + ; TRANSFORM(nCnt2) + " esecuri=" + TRANSFORM(nFail) RETURN nFail ENDFUNC *---------------------------------------------------------------------------------------- * RUL - multimea de randuri (5.5); gol pe ambele parti = PASS, raportat ca paritate vida/neconcludenta FUNCTION CompRul LPARAMETERS tcSerie1, tnNr1, tcSerie2, tnNr2, tcEticheta LOCAL nFail, lcCampuri, lcOrder, lcSql, nCnt1, nCnt2, i tcEticheta = IIF(EMPTY(tcEticheta), '[fara eticheta]', tcEticheta) nFail = 0 nCnt1 = 0 nCnt2 = 0 lcCampuri = "ID_ARTICOL, ID_GESTIUNE, ID_GESTIUNEC, CANT, PRET, PRETV, PROC_TVAV, VALOARE, " + ; "VALOAREV, VALTVA, VALTVAV, DISCUNITAR, PROC_DISC, ID_TIP_RULAJ, ID_SET, CONT, SERIE, LOT, " + ; "TAXCODE, ID_JTVA_COLOANA" lcOrder = " order by " + lcCampuri lcSql = [select ] + lcCampuri + [ from rul where sters = 0 and serie_act = '] + ALLTRIM(TRANSFORM(tcSerie1)) + ; [' and nract = ] + ALLTRIM(STR(tnNr1, 20, 0)) + lcOrder IF goExecutor.oExecute(lcSql, 'crslibr1') < 0 DO CdocLog WITH "FAIL " + tcEticheta + " RUL: select document 1 esuat - " + goExecutor.oPrelucrareEroare() RETURN 1 ENDIF lcSql = [select ] + lcCampuri + [ from rul where sters = 0 and serie_act = '] + ALLTRIM(TRANSFORM(tcSerie2)) + ; [' and nract = ] + ALLTRIM(STR(tnNr2, 20, 0)) + lcOrder IF goExecutor.oExecute(lcSql, 'crslibr2') < 0 DO CdocLog WITH "FAIL " + tcEticheta + " RUL: select document 2 esuat - " + goExecutor.oPrelucrareEroare() DO CdocInchide WITH 'crslibr1' RETURN 1 ENDIF nCnt1 = IIF(USED('crslibr1'), RECCOUNT('crslibr1'), 0) nCnt2 = IIF(USED('crslibr2'), RECCOUNT('crslibr2'), 0) IF nCnt1 = 0 AND nCnt2 = 0 DO CdocLog WITH "PASS " + tcEticheta + " RUL: gol pe ambele parti - paritate VIDA, NECONCLUDENTA " + ; "(RUL are randuri doar cu gnScadereStoc = 1)" ELSE IF nCnt1 = 0 OR nCnt2 = 0 nFail = nFail + 1 DO CdocLog WITH "FAIL " + tcEticheta + " RUL: gol doar pe o parte (v1=" + TRANSFORM(nCnt1) + ; " v2=" + TRANSFORM(nCnt2) + ") - diferenta reala, nu paritate vida" ELSE IF nCnt1 <> nCnt2 nFail = nFail + 1 DO CdocLog WITH "FAIL " + tcEticheta + " RUL numar de randuri diferit: v1=" + ; TRANSFORM(nCnt1) + " v2=" + TRANSFORM(nCnt2) ENDIF FOR i = 1 TO MIN(nCnt1, nCnt2) GO i IN crslibr1 GO i IN crslibr2 nFail = nFail + CdocComparaCampuri('crslibr1', 'crslibr2', lcCampuri, tcEticheta, ; "RUL rand " + TRANSFORM(i) + " (sortat)") ENDFOR ENDIF ENDIF DO CdocInchide WITH 'crslibr1' DO CdocInchide WITH 'crslibr2' DO CdocLog WITH "REZUMAT " + tcEticheta + " RUL randuri1=" + TRANSFORM(nCnt1) + " randuri2=" + ; TRANSFORM(nCnt2) + " esecuri=" + TRANSFORM(nFail) RETURN nFail ENDFUNC *---------------------------------------------------------------------------------------- * Suport intern - nu se consuma direct din testele S6-1...S6-5 *---------------------------------------------------------------------------------------- * gaseste id_vanzare pornind de la serie_act+numar_act; 0 = negasit, -1 = eroare Oracle * ORDER BY id_vanzare DESC: (serie_act,numar_act) nu e garantat unic pe tot istoricul (numere * vechi, dinainte de seria de teste, pot coincide) - apelantii cauta mereu documentul scris ACUM, * deci cel mai mare id_vanzare e alegerea corecta (descoperit la coliziunea SSS 1001: id_vanzare * 451 din 2009 vs. 1623 scris azi de acest test) FUNCTION CdocGasesteIdVanzare LPARAMETERS tcSerie, tnNr LOCAL lcSql lcSql = [select id_vanzare as nr from vanzari where sters = 0 and serie_act = '] + ; ALLTRIM(TRANSFORM(tcSerie)) + [' and numar_act = ] + ALLTRIM(STR(tnNr, 20, 0)) + ; [ order by id_vanzare desc] RETURN CdocValoareScalara(lcSql, 'crslibidv') ENDFUNC * executa un select ... as nr FROM ... si intoarce prima valoare; -1 = eroare Oracle FUNCTION CdocValoareScalara LPARAMETERS tcSql, tcCursorTmp LOCAL lnRez, lnSucces, lcCur lcCur = IIF(EMPTY(tcCursorTmp), 'crslibscalar', tcCursorTmp) lnRez = -1 lnSucces = goExecutor.oExecute(tcSql, lcCur) IF lnSucces >= 0 AND USED(lcCur) IF RECCOUNT(lcCur) > 0 SELECT (lcCur) GO TOP lnRez = NVL(EVALUATE(lcCur + '.nr'), 0) ELSE lnRez = 0 ENDIF USE IN (lcCur) ELSE DO CdocLog WITH "SQL ESEC: " + TRANSFORM(goExecutor.oPrelucrareEroare()) + " | " + tcSql ENDIF RETURN lnRez ENDFUNC * egalitate NULL-safe intre doua valori de cursor (numeric, caracter sau logic) FUNCTION CdocEgal LPARAMETERS tu1, tu2 IF ISNULL(tu1) AND ISNULL(tu2) RETURN .T. ENDIF IF ISNULL(tu1) OR ISNULL(tu2) RETURN .F. ENDIF IF VARTYPE(tu1) = 'C' OR VARTYPE(tu2) = 'C' RETURN ALLTRIM(TRANSFORM(tu1)) == ALLTRIM(TRANSFORM(tu2)) ENDIF RETURN tu1 = tu2 ENDFUNC * compara toate campurile din tcListaCampuri (lista "camp1, camp2, ...") intre doua alias-uri * POZITIONATE deja pe randul de comparat; logheaza fiecare FAIL si intoarce numarul de esecuri. * Lista se primeste ca sir, nu ca array: un array trecut ca parametru intre functii isi pierde * pentru compilator statutul de array (ambiguitate cu un apel de program), de-aici array-ul local * construit chiar in aceasta functie. FUNCTION CdocComparaCampuri LPARAMETERS tcAlias1, tcAlias2, tcListaCampuri, tcEticheta, tcContext LOCAL ARRAY laCampuri[1] LOCAL nCnt, nFail, i, lcCamp, lu1, lu2 nCnt = ALINES(laCampuri, tcListaCampuri, 1, ",") nFail = 0 FOR i = 1 TO nCnt lcCamp = laCampuri[i] lu1 = EVALUATE(tcAlias1 + '.' + lcCamp) lu2 = EVALUATE(tcAlias2 + '.' + lcCamp) IF !CdocEgal(lu1, lu2) nFail = nFail + 1 DO CdocLog WITH "FAIL " + tcEticheta + " " + tcContext + " camp=" + lcCamp + ; " v1=" + TRANSFORM(lu1) + " v2=" + TRANSFORM(lu2) ENDIF ENDFOR RETURN nFail ENDFUNC * invariantul minim de pe VANZARI_DETALII (5.3): count(*), sum(cantitate), sum(cantitate*pret), * setul de id_jtva_coloana - valabil chiar cand liniile nu sunt identice camp cu camp FUNCTION CdocInvariantDetalii LPARAMETERS tcAlias1, tnCnt1, tcAlias2, tnCnt2, tcEticheta LOCAL nFail, nSumCant1, nSumCant2, nSumVal1, nSumVal2, lcSet1, lcSet2, lcCod nFail = 0 nSumCant1 = 0 nSumVal1 = 0 lcSet1 = '' IF USED(tcAlias1) AND tnCnt1 > 0 SELECT (tcAlias1) GO TOP SCAN nSumCant1 = nSumCant1 + NVL(cantitate, 0) nSumVal1 = nSumVal1 + NVL(cantitate, 0) * NVL(pret, 0) lcCod = TRANSFORM(NVL(id_jtva_coloana, 0)) IF !(";" + lcCod + ";" $ ";" + lcSet1) lcSet1 = lcSet1 + lcCod + ";" ENDIF ENDSCAN ENDIF nSumCant2 = 0 nSumVal2 = 0 lcSet2 = '' IF USED(tcAlias2) AND tnCnt2 > 0 SELECT (tcAlias2) GO TOP SCAN nSumCant2 = nSumCant2 + NVL(cantitate, 0) nSumVal2 = nSumVal2 + NVL(cantitate, 0) * NVL(pret, 0) lcCod = TRANSFORM(NVL(id_jtva_coloana, 0)) IF !(";" + lcCod + ";" $ ";" + lcSet2) lcSet2 = lcSet2 + lcCod + ";" ENDIF ENDSCAN ENDIF IF !CdocEgal(ROUND(nSumCant1, 6), ROUND(nSumCant2, 6)) nFail = nFail + 1 DO CdocLog WITH "FAIL " + tcEticheta + " VANZARI_DETALII invariant sum(cantitate) diferit: v1=" + ; TRANSFORM(nSumCant1) + " v2=" + TRANSFORM(nSumCant2) ENDIF IF !CdocEgal(ROUND(nSumVal1, 2), ROUND(nSumVal2, 2)) nFail = nFail + 1 DO CdocLog WITH "FAIL " + tcEticheta + " VANZARI_DETALII invariant sum(cantitate*pret) diferit: v1=" + ; TRANSFORM(nSumVal1) + " v2=" + TRANSFORM(nSumVal2) ENDIF IF !(CdocSortSet(lcSet1) == CdocSortSet(lcSet2)) nFail = nFail + 1 DO CdocLog WITH "FAIL " + tcEticheta + " VANZARI_DETALII invariant set id_jtva_coloana diferit: v1=" + ; lcSet1 + " v2=" + lcSet2 ENDIF RETURN nFail ENDFUNC * normalizeaza un set ";"-delimitat de coduri numerice ca sa nu depinda de ordinea de aparitie FUNCTION CdocSortSet LPARAMETERS tcSet LOCAL ARRAY laSet[1] LOCAL nCnt, i, j, lcTmp, lcRez nCnt = ALINES(laSet, tcSet, 1, ";") IF nCnt = 0 RETURN '' ENDIF FOR i = 1 TO nCnt - 1 FOR j = i + 1 TO nCnt IF VAL(laSet[j]) < VAL(laSet[i]) lcTmp = laSet[i] laSet[i] = laSet[j] laSet[j] = lcTmp ENDIF ENDFOR ENDFOR lcRez = '' FOR i = 1 TO nCnt lcRez = lcRez + laSet[i] + ";" ENDFOR RETURN lcRez ENDFUNC * elibereaza un alias daca e deschis PROCEDURE CdocInchide LPARAMETERS tcAlias IF USED(tcAlias) USE IN (tcAlias) ENDIF ENDPROC * scrie in gcLog (daca apelantul l-a definit PUBLIC) sau in logul implicit al bibliotecii PROCEDURE CdocLog LPARAMETERS tcMsg LOCAL lcLog lcLog = IIF(TYPE('gcLog') = 'C' AND !EMPTY(gcLog), gcLog, CDOC_LOG_IMPLICIT) IF !DIRECTORY(JUSTPATH(lcLog)) MD (JUSTPATH(lcLog)) ENDIF STRTOFILE(tcMsg + CHR(13) + CHR(10), lcLog, 1) ENDPROC