Files
comun/utile/Teste/facturare_unificat/lib_comparatie_documente.prg
Marius Mutu 8e022d332e #13: formular de facturare unificat - etapa curenta
Squash al branch-ului de lucru plan13-s2.

Clase: ofacturare (nucleul formularului unificat), ofacturare_comun,
ferestre_cere_date, ocomenzi, caut_ora (lista de preturi in combo-urile de
cautare), omodificari.

Programe: ofacturare impartit - ofacturare_antet, ofacturare_rutare_scriere si
ogrid_latimi sunt fisiere noi; oproceduri_facturare primeste discountul pe linie
si cota standard de TVA cand articolul nu are cota pe politica.

Documentatie: capcana SQLExec no_data_found, conventia de encoding, depanarea
testelor VFP si regulile de lucru - conflictele cu modificarile venite din alte
proiecte sunt rezolvate pastrand ambele parti.

Loguri de rulare a testelor scoase din versionare; testele raman.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PkyjGyrV2S7932om4kfSiK
2026-09-09 21:38:25 +03:00

460 lines
19 KiB
Plaintext

*!* 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