* test_s10_cablare_vfp.prg * Proba de cablare S10 (docs\raport_s10_cablare_vfp.md) - LIMITA semnalata explicit in * docs\propunere_s10_proc_tvav.md §11.0: test_s10_proc_tvav.prg dovedeste ca pachetul Oracle * (CASE-ul din PACK_FACTURARE.adauga_articol_factura) respecta flag-ul/parametrul nou, dar apeleaza * pack_facturare DIRECT - nu dovedeste ca frm_facturare_articole2.do_scrie_articole (ofacturare.vc2, * diff-ul din propunere §8) chiar APRINDE pack_facturare.nregenerare_editare si chiar TRIMITE al * 28-lea argument. Aceasta proba umple exact acel gol. * * Metoda: mock pe goExecutor care CAPTUREAZA lcSql-ul trimis prin oExecute()/oExecuta(), FARA sa * execute nimic in Oracle (tiparul S4e-5, verificare pe sirul SQL construit, nu pe rezultatul * Oracle). Documentul se incarca REAL (IncarcaAntetFacturaEditare + IncarcaLiniiFacturaEditare, * tiparul test_s9_8_flux.prg) - CITIRE, cu goExecutor REAL, inainte de orice mock; abia dupa * incarcare se inlocuieste goExecutor cu mock-ul, inainte de a chema loForm.do_scrie_articole(). * Rezultat: ZERO scriere reala, nici in Oracle, nici in VANZARI_DETALII_TEMP - captura e strict pe * text, nu pe efect. * * Parametru tnCaz: * 1 = flag=0 (plRegenerareEditare NEDECLARAT - RELEASE explicit inainte, ca sa fie sigur Type()='U', * exact starea unei prime emiteri, fara nicio regenerare in curs). Asterturi: * - lcSql contine "pack_facturare.nregenerare_editare := 0" * - fiecare apel adauga_articol_factura din text are 28 argumente (parametrul nou se trimite * oricum, necondiționat - Oracle il ignora fara flag, cf. §11.0/§7.3 din propunere) * 2 = flag=1 (plRegenerareEditare = .T., PRIVATE, cu poSnapshotEditare minimal construit ca sa * treaca garda din StergeDocumentFacturare - an/luna = perioada activa, id_fact=0 ca sa sara * peste ForteazaIdFactReemitere). Asterturi: * - lcSql contine "pack_facturare.nregenerare_editare := 1" * - fiecare apel adauga_articol_factura din text are 28 argumente * - ORDINEA: "initializeaza_date_factura" apare INAINTEA lui "nregenerare_editare := 1" in * acelasi sir - daca ordinea ar fi inversa, reset-ul din initializeaza_date_factura (aplicat * pe Oracle, verificat la runtime in docs\raport_s10_aplicare_oracle.md §4.1) ar sterge * flag-ul tacit, exact defectul pe care insertia din propunere §8.1 il evita prin ancorare * DUPA capatul apelului la initializeaza_date_factura. * * Document folosit: 630 (CONTRACT-A din test_s9_8_flux.prg rularea 5 - driver deja validat pe el). * Cursorul crsfactura e curatat local (explicatie/serie/lot golite, opt_facturare fortat la 0 pe * toate randurile) DOAR in memorie, ca sa garanteze ca (a) textul capturat n-are ")" accidental * intr-un camp text si (b) toate randurile cad pe branch-ul adauga_articol_factura, nu pe * adauga_rata_factura (poArt.opt_facturare in (1,2)) - fara asta proba n-ar mai testa ce trebuie. * Documentul real din baza NU e atins - toate modificarile sunt pe cursorul local incarcat in RAM. * * Tranzactia: do_scrie_articole() (ofacturare.vc2:19842) deschide Transactions=2 pe gnHandle * (conexiunea REALA - SQLSetprop, nu goExecutor) si NU o inchide pe ramura de succes (o lasa * deschisa pentru do_scrie_factura, care nu se apeleaza aici) - ROLLBACK explicit dupa fiecare caz, * direct pe gnHandle, indiferent de rezultat. LPARAMETERS tnCaz SET SAFETY OFF SET TALK OFF PUBLIC gcErrLog, gnPass, gnFail PUBLIC poDate gcErrLog = 'D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_s10_cablare_vfp_log_' + ; STRTRAN(STRTRAN(STRTRAN(TTOC(DATETIME()), '/', ''), ':', ''), ' ', '_') + '.txt' STRTOFILE('start ' + TRANSFORM(DATETIME()) + ' caz=' + TRANSFORM(tnCaz) + CHR(13) + CHR(10), gcErrLog) ON ERROR DO test_error_handler WITH ERROR(), MESSAGE(), PROGRAM(), LINENO() ON SHUTDOWN QUIT DO ('D:\ROA\ROAFACTURARE\COMUN\utile\Teste\test_init_env_auto_roafacturare.prg') WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT' IF gnHandle <= 0 STRTOFILE('EROARE: conectare esuata' + CHR(13) + CHR(10), gcErrLog, 1) QUIT ENDIF gnIdUtil = 8 SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare_editare.prg ADDITIVE SET PROCEDURE TO D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare_rutare_scriere.prg ADDITIVE *!* la nume duplicat de procedura castiga PRIMUL fisier din lista SET PROCEDURE, nu ultimul LOCAL lcProcExistent lcProcExistent = SET("PROCEDURE") SET PROCEDURE TO "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\mock_amessagebox.prg", &lcProcExistent LOCAL lcPathVechi, lcPathNou lcPathVechi = SET("PATH") lcPathNou = 'D:\ROA\ROAFACTURARE\COMUN\Utile\Teste\achizitie_import\stub_verificare;' + lcPathVechi SET PATH TO &lcPathNou PUBLIC gnMockRaspuns, gcMockUltimMesaj, gnMockUltimTip gnMockRaspuns = 7 gcMockUltimMesaj = '' gnMockUltimTip = 0 gnPass = 0 gnFail = 0 LOCAL lnCaz lnCaz = VAL(TRANSFORM(tnCaz)) DO CASE CASE lnCaz = 1 DO CazFlag WITH .F. CASE lnCaz = 2 DO CazFlag WITH .T. OTHERWISE STRTOFILE('EROARE: tnCaz trebuie sa fie 1 (flag=0) / 2 (flag=1)' + CHR(13) + CHR(10), gcErrLog, 1) ENDCASE STRTOFILE('REZULTAT: ' + TRANSFORM(gnPass) + ' PASS / ' + TRANSFORM(gnFail) + ' FAIL' + CHR(13) + CHR(10), gcErrLog, 1) STRTOFILE('end ' + TRANSFORM(DATETIME()) + CHR(13) + CHR(10), gcErrLog, 1) QUIT *============================================================================================== * CazFlag: incarca REAL doc 630, curata local crsfactura, apeleaza loForm.do_scrie_articole() cu * goExecutor MOCKAT (nicio scriere reala), verifica textul capturat. *============================================================================================== PROCEDURE CazFlag LPARAMETERS tlFlagPornit LOCAL loForm, loMock, loExecutorReal, lnIdV, lcPrefix lnIdV = 630 lcPrefix = IIF(m.tlFlagPornit, 'FLAG1', 'FLAG0') DO asserteaza WITH 'PRECONDITIE documentul ' + TRANSFORM(lnIdV) + ' e viu (STERS=0)', ; Val1([select count(*) as v from vanzari where id_vanzare = ] + TRANSFORM(lnIdV) + [ and sters = 0]) = 1, ; TRANSFORM(Val1([select count(*) as v from vanzari where id_vanzare = ] + TRANSFORM(lnIdV) + [ and sters = 0])) LOCAL lnDiscRon, lnDiscVal lnDiscRon = 0 lnDiscVal = 0 poDate = IncarcaAntetFacturaEditare(lnIdV, @lnDiscRon, @lnDiscVal) DO asserteaza WITH lcPrefix + '-0a antetul documentului ' + TRANSFORM(lnIdV) + ' s-a incarcat', VARTYPE(poDate) = 'O', VARTYPE(poDate) IF VARTYPE(poDate) <> 'O' RETURN ENDIF IncarcaLiniiFacturaEditare(poDate, lnIdV) DO asserteaza WITH lcPrefix + '-0b liniile documentului ' + TRANSFORM(lnIdV) + ' s-au incarcat', ; USED('crsfactura') AND RECCOUNT('crsfactura') > 0, TRANSFORM(IIF(USED('crsfactura'), RECCOUNT('crsfactura'), -1)) IF !USED('crsfactura') OR RECCOUNT('crsfactura') = 0 RETURN ENDIF *!* curatare LOCALA (doar cursorul din RAM): (a) fara ")" accidental in text, (b) toate randurile *!* pe branch-ul adauga_articol_factura, (c) fara NULL pe niciun camp NUMERIC folosit NEprotejat *!* (fara Nvl()/Iif(Isnull())) in constructia lcSql din do_scrie_articole (ofacturare.vc2:19978- *!* 20001) - un NULL real pe orice document istoric prabuseste tot sirul concatenat la NULL *!* (VFP propaga NULL prin "+"), descoperit la runtime: PCOUNT()=1 dar VARTYPE(tcSql)='X' (NULL) SELECT crsfactura REPLACE ALL ; id_temp WITH NVL(id_temp,0), id_articol WITH NVL(id_articol,0), ; pret_achizitie WITH NVL(pret_achizitie,0), cu_tva WITH NVL(cu_tva,0), tip_valuta WITH NVL(tip_valuta,0), ; pretftva WITH NVL(pretftva,0), vpretftva WITH NVL(vpretftva,0), ; pretctva WITH NVL(pretctva,0), vpretctva WITH NVL(vpretctva,0), ; id_valuta WITH NVL(id_valuta,0), gestionabil WITH NVL(gestionabil,0), cantitate WITH NVL(cantitate,0), ; discountftva WITH NVL(discountftva,0), vdiscountftva WITH NVL(vdiscountftva,0), ; discountctva WITH NVL(discountctva,0), vdiscountctva WITH NVL(vdiscountctva,0), ; Curs WITH NVL(Curs,1), multiplicator WITH NVL(multiplicator,1), id_jtva_coloana WITH NVL(id_jtva_coloana,0), ; pretv_orig WITH NVL(pretv_orig,0), ; explicatie WITH 'test-s10-cablare', serie WITH '', lot WITH '', opt_facturare WITH 0 ; IN crsfactura *!* REPLACE ALL lasa pointerul pe EOF - Scan (folosit de do_scrie_articole) porneste de la *!* POZITIA CURENTA, nu de la Top - fara acest GO TOP, bucla de articole rula 0 iteratii GO TOP IN crsfactura LOCAL lnRandurAsteptate lnRandurAsteptate = RECCOUNT('crsfactura') loForm = CREATEOBJECT('frm_facturare_articole2') IF m.tlFlagPornit PRIVATE plRegenerareEditare PUBLIC poSnapshotEditare plRegenerareEditare = .T. poSnapshotEditare = CREATEOBJECT('Empty') AddProperty(poSnapshotEditare, 'id_vanzare', m.lnIdV) AddProperty(poSnapshotEditare, 'cod', 1) AddProperty(poSnapshotEditare, 'an', gnAn) AddProperty(poSnapshotEditare, 'luna', gnLuna) AddProperty(poSnapshotEditare, 'id_fact', 0) ELSE IF TYPE('plRegenerareEditare') <> 'U' RELEASE plRegenerareEditare ENDIF ENDIF *!* dupa acest punct: NICIO citire/scriere reala in Oracle - totul trece prin mock loExecutorReal = goExecutor loMock = CREATEOBJECT('MockGoExecutorS10Cablare') goExecutor = loMock LOCAL llReturn llReturn = loForm.do_scrie_articole() *!* ROLLBACK explicit pe conexiunea REALA - do_scrie_articole nu inchide tranzactia pe succes *!* (o lasa deschisa pentru do_scrie_factura, care nu se apeleaza aici) goExecutor = loExecutorReal SQLROLLBACK(gnHandle) SQLSetProp(gnHandle, 'Transactions', 1) DO asserteaza WITH lcPrefix + '-1 do_scrie_articole() a intors .T. (nicio eroare in constructia sirului)', llReturn, TRANSFORM(llReturn) STRTOFILE(lcPrefix + ' apeluri capturate de mock: ' + TRANSFORM(loMock.nApeluri) + CHR(13) + CHR(10), gcErrLog, 1) STRTOFILE(lcPrefix + ' --- lcSql capturat ---' + CHR(13) + CHR(10) + loMock.cSqlCapturat + CHR(13) + CHR(10), gcErrLog, 1) LOCAL lcAsteptat lcAsteptat = 'pack_facturare.nregenerare_editare := ' + IIF(m.tlFlagPornit, '1', '0') + ';' DO asserteaza WITH lcPrefix + '-2 lcSql contine [' + lcAsteptat + ']', ; lcAsteptat $ loMock.cSqlCapturat, IIF(lcAsteptat $ loMock.cSqlCapturat, 'gasit', 'LIPSA') IF m.tlFlagPornit LOCAL lnPozInit, lnPozFlag lnPozInit = AT('initializeaza_date_factura', loMock.cSqlCapturat) lnPozFlag = AT('nregenerare_editare := 1', loMock.cSqlCapturat) DO asserteaza WITH lcPrefix + '-3 ORDINE: initializeaza_date_factura (pozitia ' + TRANSFORM(lnPozInit) + ; ') apare INAINTEA nregenerare_editare := 1 (pozitia ' + TRANSFORM(lnPozFlag) + ')', ; lnPozInit > 0 AND lnPozFlag > 0 AND lnPozInit < lnPozFlag, ; TRANSFORM(lnPozInit) + ' vs ' + TRANSFORM(lnPozFlag) ENDIF *!* AT() cu al treilea parametru (nr. de ordine al aparitiei) - gaseste direct a n-a aparitie, *!* fara iterare manuala pe substring-uri LOCAL lnNrApeluriAdauga, lnN, lnPozGasit, lnPozInceputArg, lnPozSfarsitRel, lcSegmentArg, lnVirgule lnNrApeluriAdauga = 0 lnN = 0 DO WHILE .T. lnN = lnN + 1 lnPozGasit = AT('adauga_articol_factura(', loMock.cSqlCapturat, lnN) IF lnPozGasit = 0 EXIT ENDIF lnNrApeluriAdauga = lnNrApeluriAdauga + 1 lnPozInceputArg = lnPozGasit + LEN('adauga_articol_factura(') lnPozSfarsitRel = AT(');', SUBSTR(loMock.cSqlCapturat, lnPozInceputArg)) lcSegmentArg = SUBSTR(loMock.cSqlCapturat, lnPozInceputArg, lnPozSfarsitRel - 1) lnVirgule = OCCURS(',', lcSegmentArg) DO asserteaza WITH lcPrefix + '-4.' + TRANSFORM(lnNrApeluriAdauga) + ' apelul #' + TRANSFORM(lnNrApeluriAdauga) + ; ' la adauga_articol_factura are 28 argumente (27 virgule)', lnVirgule = 27, TRANSFORM(lnVirgule) + ' virgule -> ' + TRANSFORM(lnVirgule + 1) + ' argumente' ENDDO DO asserteaza WITH lcPrefix + '-5 numarul de apeluri adauga_articol_factura = numarul de randuri din crsfactura (' + TRANSFORM(lnRandurAsteptate) + ')', ; lnNrApeluriAdauga = lnRandurAsteptate, TRANSFORM(lnNrApeluriAdauga) + ' vs ' + TRANSFORM(lnRandurAsteptate) IF m.tlFlagPornit IF TYPE('poSnapshotEditare') <> 'U' RELEASE poSnapshotEditare ENDIF ENDIF IF TYPE('plRegenerareEditare') <> 'U' RELEASE plRegenerareEditare ENDIF ENDPROC *============================================================================================== FUNCTION Val1 LPARAMETERS tcSql LOCAL lnRet lnRet = -1 IF USED('v_val10c') USE IN v_val10c ENDIF IF goExecutor.oExecuta(tcSql, 'v_val10c') SELECT v_val10c IF RECCOUNT('v_val10c') > 0 GO TOP lnRet = NVL(v_val10c.v, -1) ENDIF USE IN v_val10c ELSE STRTOFILE('EROARE Val1: ' + goExecutor.cEroare + CHR(13) + CHR(10), gcErrLog, 1) ENDIF RETURN lnRet ENDFUNC PROCEDURE asserteaza LPARAMETERS tcNume, tlConditie, tcValoare IF m.tlConditie gnPass = gnPass + 1 STRTOFILE('PASS ' + m.tcNume + CHR(13) + CHR(10), gcErrLog, 1) ELSE gnFail = gnFail + 1 STRTOFILE('FAIL ' + m.tcNume + ' (valoare: ' + TRANSFORM(m.tcValoare) + ')' + CHR(13) + CHR(10), gcErrLog, 1) ENDIF ENDPROC PROCEDURE test_error_handler LPARAMETERS tnError, tcMessage, tcProgram, tnLineNo STRTOFILE('EROARE ' + TRANSFORM(tnError) + ' [' + tcProgram + ':' + TRANSFORM(tnLineNo) + '] ' + tcMessage + CHR(13) + CHR(10), gcErrLog, 1) *!* daca a ramas o tranzactie manuala deschisa dupa o eroare in mijlocul CazFlag, o inchidem *!* aici - nu lasam conexiunea agatata pe Transactions=2 IF TYPE('gnHandle') = 'N' AND gnHandle > 0 SQLROLLBACK(gnHandle) SQLSetProp(gnHandle, 'Transactions', 1) ENDIF gnFail = gnFail + 1 STRTOFILE('REZULTAT: ' + TRANSFORM(gnPass) + ' PASS / ' + TRANSFORM(gnFail) + ' FAIL' + CHR(13) + CHR(10), gcErrLog, 1) STRTOFILE('end (eroare) ' + TRANSFORM(DATETIME()) + CHR(13) + CHR(10), gcErrLog, 1) QUIT ENDPROC *============================================================================================== * MockGoExecutorS10Cablare: captureaza fiecare lcSql trimis prin oExecute()/oExecuta(), fara sa * execute NIMIC in Oracle. oExecuta cu alias de cursor creeaza un cursor GOL (0 randuri) cu acel * nume - StergeDocumentFacturare (ofacturare_rutare_scriere.prg:344) citeste doar Reccount() pe * cursoarele intoarse, niciodata continutul lor, deci 0 randuri il duce corect pe ramura * "sterge_factura" (fara nota contabila de reversat) - ramura simpla, un singur oExecuta in plus, * tot mockat. *============================================================================================== DEFINE CLASS MockGoExecutorS10Cablare AS Custom cSqlCapturat = '' nApeluri = 0 cEroare = '' FUNCTION oExecute(tcSql) THIS.nApeluri = THIS.nApeluri + 1 LOCAL lcDiagCrs IF USED('crsfactura') lcDiagCrs = ' [DIAG crsfactura: RECNO=' + TRANSFORM(RECNO('crsfactura')) + ' RECCOUNT=' + TRANSFORM(RECCOUNT('crsfactura')) + ' EOF=' + TRANSFORM(EOF('crsfactura')) + ' ALIAS()=' + ALIAS() + ']' ELSE lcDiagCrs = ' [DIAG crsfactura: NEUSED]' ENDIF THIS.cSqlCapturat = THIS.cSqlCapturat + '>>>APEL ' + TRANSFORM(THIS.nApeluri) + ' (oExecute) VARTYPE(tcSql)=' + VARTYPE(m.tcSql) + lcDiagCrs + CHR(13) + CHR(10) + TRANSFORM(m.tcSql) + CHR(13) + CHR(10) RETURN 1 ENDFUNC FUNCTION oExecuta(tcSql, tcCursor) THIS.nApeluri = THIS.nApeluri + 1 THIS.cSqlCapturat = THIS.cSqlCapturat + '>>>APEL ' + TRANSFORM(THIS.nApeluri) + ' (oExecuta)' + CHR(13) + CHR(10) + TRANSFORM(m.tcSql) + CHR(13) + CHR(10) IF VARTYPE(m.tcCursor) = 'C' AND !EMPTY(m.tcCursor) IF USED(m.tcCursor) USE IN (m.tcCursor) ENDIF CREATE CURSOR (m.tcCursor) (xdummy I) ENDIF RETURN .T. ENDFUNC FUNCTION oPrelucrareEroare() RETURN 'MockGoExecutorS10Cablare: ' + THIS.cEroare ENDFUNC ENDDEFINE