Files
comun/utile/Teste/facturare_unificat/test_s3b_incasare_paritate_campuri.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

313 lines
15 KiB
Plaintext

* test_s3b_incasare_paritate_campuri.prg
* Headless: pentru fiecare din cele patru tipuri de incasare (1=Fara incasare, 2=Chitanta,
* 3=Bon fiscal, 4=POS Card), formularul nou (frm_facturare_articole2) aduce poDate in aceeasi
* stare ca dialogul vechi (frm_alte_date) - fara sa treaca prin do_scrie_factura/Termina, deci
* fara sa scrie nimic in Oracle si fara sa emita niciun document.
* Specificatie: docs\nota_s3b_testare.md sectiunea 2b. Nu acopera lcListaIncasare/do_scrie_factura
* insusi (ar cere emitere reala sau un mock detaliat pe goExecutor - vezi sectiunea 2a/2b, ultimul
* paragraf) - asta ramane proba manuala a lui Marius, cerut si de raport_s3b_incasare.md sectiunea 10.
*
* ATENTIE la citirea rezultatelor: din cele cinci campuri cerute de specificatie (poDate.incasat,
* incasatCARD, incasatTichete, id_casa, ntip_incasare), doar poDate.incasat si poDate.id_casa sunt
* scrise efectiv de actualizeaza_tipincasare()/Init - verificat pe cod (ofacturare.vc2, ferestre_
* cere_date.vc2). incasatCARD, incasatTichete si ntip_incasare sunt scrise abia in Termina /
* inainte_de_do_termin (calea care emite, exclusa explicit din acest test - sectiunea 2a). Pentru
* aceste trei campuri parizatea verificata aici e reala, dar putin adanca: confirma doar ca NICIUNA
* din cele doua cai nu le atinge la simplul toggle al opt_incasat (raman la valoarea implicita 0 pe
* ambele cai), nu ca Termina le populeaza identic pe ambele cai.
*
* SECVENTIAL, nu simultan: frm_alte_date e creata, testata pe toate cele patru tipuri si eliberata
* COMPLET inainte sa existe frm_facturare_articole2 - niciodata doua forme vii in acelasi timp.
* Motiv: ambele forme au propriul cboTipFactura cu RowSource IDENTIC ("...into cursor cTipFacturaX",
* ofacturare.vc2:16157 si ferestre_cere_date.vc2:2388), reevaluat la fiecare apel al lui
* actualizeaza_tipincasare() (Thisform.cboTipFactura.Refresh(), prima linie a metodei pe ambele
* forme); cu ambele vii simultan in aceeasi sesiune de date (fara DataSession propriu), doua
* comboboxuri concureaza pe acelasi nume de cursor - suspectat ca varianta paralela (rulata de patru
* ori, toate agatate in acelasi punct) bloca aici, la nivel de tabel, fara sa arunce o exceptie
* catchabila prin ON ERROR. Nota cerea "acelasi poDate", nu simultaneitate - pastrata aici prin
* pastrarea aceluiasi obiect poDate intre cele doua faze, cu cele cinci campuri resetate explicit
* la starea de start intre faze (ca a doua forma sa porneasca de la aceeasi stare ca prima).
*
* Rulare: vfp9.exe -A -T "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_unificat\test_s3b_incasare_paritate_campuri.prg"
* Log: D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_unificat\out\test_s3b_incasare_paritate_campuri.log
SET SAFETY OFF
SET TALK OFF
SET NOTIFY OFF
PUBLIC gcLog, gnFail, gnPass
gcLog = "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_unificat\out\test_s3b_incasare_paritate_campuri.log"
IF !DIRECTORY("D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_unificat\out")
MD "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_unificat\out"
ENDIF
STRTOFILE("START " + TTOC(DATETIME()) + CHR(13) + CHR(10), gcLog)
gnFail = 0
gnPass = 0
ON ERROR DO AfErr WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
DO "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\test_init_env_auto_roafacturare.prg" WITH 'CENTRAL', 'MARIUSM_AUTO', 'ROMFASTSOFT'
IF TYPE('gnHandle') <> 'N' OR gnHandle <= 0
DO AfLog WITH "FAIL: conexiune Oracle esuata"
DO Final
ENDIF
SET PROCEDURE TO "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\mock_amessagebox.prg" ADDITIVE
PUBLIC gcMockUltimMesaj, gnMockUltimTip
gcMockUltimMesaj = ""
gnMockUltimTip = 0
DO AfLog WITH "ENV OK, gnAn=" + TRANSFORM(gnAn) + " gnLuna=" + TRANSFORM(gnLuna)
IF !actualizeaza_optiuni_program()
DO AfLog WITH "FAIL: actualizeaza_optiuni_program()"
DO Final
ENDIF
gnScadereStoc = 0
gnIdUtil = 8
* aliniaza sucursala cu singura plaja POS/card existenta, evita blocajul Oracle pe cursor OUT
gnIdSucursala = 167
goExecutor.oExecuta([begin pack_sesiune.set_Id_Util(?gnIdUtil); end;])
DO AfLog WITH "gnScadereStoc=" + TRANSFORM(gnScadereStoc)
* gridextras.vcx e referit din ofacturare.vcx cu cale relativa, rezolvabila doar din exe/IDE -
* necesar pentru frm_facturare_articole2 (frm_alte_date nu are grid, dar SET-urile sunt ADDITIVE)
SET CLASSLIB TO "D:\ROA\ROAFACTURARE\COMUN\utile\gridextras\gridextras.vcx" ADDITIVE
SET PATH TO "D:\ROA\ROAFACTURARE\COMUN\utile\gridextras" ADDITIVE
SET CLASSLIB TO "D:\ROA\ROAFACTURARE\COMUN\clase\_cb_base.vcx" ADDITIVE
IF USED('crscursuri')
USE IN crscursuri
ENDIF
CREATE CURSOR crscursuri (curs N(12,4), nume_val C(10), multiplicator N(6))
DO creeaza_facturacrs WITH 'crsfactura'
SELECT *, CAST(NULL AS C(100)) AS gestiune FROM crsfactura INTO CURSOR crsfact_tmp READWRITE
USE IN crsfactura
SELECT * FROM crsfact_tmp INTO CURSOR crsfactura READWRITE
USE IN crsfact_tmp
DO ProbaParitate
DO Final
PROCEDURE ProbaParitate
* VARIANTA SECVENTIALA (23.08.2026): nota cerea "acelasi poDate", nu "ambele forme vii in
* acelasi timp" - simultaneitatea era detaliu de implementare, nu cerinta (confirmat de
* team-lead). Motivul schimbarii: frm_alte_date SI frm_facturare_articole2 au fiecare propriul
* cboTipFactura, cu RowSource IDENTIC ("select tip_saftname, cod from saft_tip_facturi into
* cursor cTipFacturaX" - ofacturare.vc2:16157, ferestre_cere_date.vc2:2388), refacut la fiecare
* apel al lui actualizeaza_tipincasare() (Thisform.cboTipFactura.Refresh(), prima linie a
* metodei pe ambele forme). Cu ambele forme vii simultan, in aceeasi sesiune de date (fara
* DataSession propriu pe niciuna), doua comboboxuri concureaza pe acelasi nume de cursor tinta -
* suspiciunea unei asteptari de lacat la nivel de tabel, care nu trece prin ON ERROR (nu e o
* exceptie aruncata). Aici: loVechi e creata, testata COMPLET si eliberata inainte sa existe
* loNou - niciodata doua forme vii simultan.
*
* poDate ramane ACELASI obiect intre cele doua faze (nu se recreeaza) - dar cele cinci campuri
* se retin la start si se restaureaza explicit intre faze, ca a doua forma sa porneasca de la
* aceeasi stare ca prima, nu de la ce a lasat prima in urma.
PRIVATE poDate, poGeneratorNumere, loVechi, loNou, i
LOCAL laTip[4], laNume[4], laRezVechi[4,5]
laTip[1] = 1
laTip[2] = 2
laTip[3] = 3
laTip[4] = 4
laNume[1] = "Fara incasare"
laNume[2] = "Chitanta"
laNume[3] = "Bon fiscal"
laNume[4] = "POS Card"
poDate = CREATEOBJECT("oDateFactura", 25000, 1)
poDate.nIdTipDoc = 5
poDate.totalctva = 1000
DO AfLog WITH "poDate.tip=" + TRANSFORM(poDate.tip) + " poDate.eProforma=" + TRANSFORM(poDate.eProforma) + " poDate.incasat=" + TRANSFORM(poDate.incasat)
poGeneratorNumere = CREATEOBJECT("oGeneratorNumere")
poGeneratorNumere.ResetNumere()
DO ProbaSerii WITH poDate.nIdTipDoc
poDate.rezultat_serii = poGeneratorNumere.creeaza_cursor_serii(poDate.nIdTipDoc)
* starea de start a celor cinci campuri, INAINTE de orice forma - se restaureaza intre faze
LOCAL lnStartIncasat, lnStartCard, lnStartTichete, lnStartCasa, lnStartTipInc
lnStartIncasat = poDate.incasat
lnStartCard = poDate.incasatCARD
lnStartTichete = poDate.incasatTichete
lnStartCasa = poDate.id_casa
lnStartTipInc = poDate.ntip_incasare
DO AfLog WITH "stare start poDate: incasat=" + TRANSFORM(lnStartIncasat) + " incasatCARD=" + TRANSFORM(lnStartCard) + ;
" incasatTichete=" + TRANSFORM(lnStartTichete) + " id_casa=" + TRANSFORM(lnStartCasa) + " ntip_incasare=" + TRANSFORM(lnStartTipInc)
LOCAL lnTip, lcNumeTip
* ---------- FAZA 1: doar frm_alte_date (calea veche), complet, apoi Release() ----------
DO AsiguraSaftTipFacturi
DO AfLog WITH "inainte de Createobject frm_alte_date: USED('saft_tip_facturi')=" + TRANSFORM(USED('saft_tip_facturi')) + ;
" USED('cTipFacturaX')=" + TRANSFORM(USED('cTipFacturaX'))
loVechi = CREATEOBJECT('frm_alte_date')
DO Assert WITH VARTYPE(loVechi) = 'O', "Createobject frm_alte_date (calea veche)"
IF VARTYPE(loVechi) <> 'O'
RETURN
ENDIF
loVechi.Visible = .F.
DO AfLog WITH "dupa Createobject frm_alte_date: USED('cTipFacturaX')=" + TRANSFORM(USED('cTipFacturaX'))
FOR i = 1 TO 4
lnTip = laTip[i]
lcNumeTip = laNume[i]
DO AfLog WITH "vechi [" + lcNumeTip + "]: inainte de opt_incasat.Value=, USED('cTipFacturaX')=" + TRANSFORM(USED('cTipFacturaX'))
loVechi.opt_incasat.Value = lnTip
DO AfLog WITH "vechi [" + lcNumeTip + "]: dupa opt_incasat.Value=, USED('cTipFacturaX')=" + TRANSFORM(USED('cTipFacturaX'))
laRezVechi[i,1] = poDate.incasat
laRezVechi[i,2] = poDate.incasatCARD
laRezVechi[i,3] = poDate.incasatTichete
laRezVechi[i,4] = poDate.id_casa
laRezVechi[i,5] = poDate.ntip_incasare
DO AfLog WITH "vechi [" + lcNumeTip + "]: incasat=" + TRANSFORM(laRezVechi[i,1]) + " incasatCARD=" + TRANSFORM(laRezVechi[i,2]) + ;
" incasatTichete=" + TRANSFORM(laRezVechi[i,3]) + " id_casa=" + TRANSFORM(laRezVechi[i,4]) + " ntip_incasare=" + TRANSFORM(laRezVechi[i,5])
DO AfLog WITH "vechi [" + lcNumeTip + "]: stare numere=" + StareToate()
loVechi.opt_incasat.Value = 1
DO AfLog WITH "vechi [" + lcNumeTip + "]: dezalocat, stare numere=" + StareToate()
ENDFOR
loVechi.Release()
RELEASE loVechi
DO AfLog WITH "dupa Release loVechi: USED('saft_tip_facturi')=" + TRANSFORM(USED('saft_tip_facturi')) + ;
" USED('cTipFacturaX')=" + TRANSFORM(USED('cTipFacturaX'))
* readuce poDate la starea de start, ca a doua forma sa porneasca identic cu prima
poDate.incasat = lnStartIncasat
poDate.incasatCARD = lnStartCard
poDate.incasatTichete = lnStartTichete
poDate.id_casa = lnStartCasa
poDate.ntip_incasare = lnStartTipInc
DO AfLog WITH "poDate resetat inainte de a doua forma: incasat=" + TRANSFORM(poDate.incasat) + " id_casa=" + TRANSFORM(poDate.id_casa)
* ---------- FAZA 2: doar frm_facturare_articole2 (calea noua) ----------
DO AsiguraSaftTipFacturi
DO AfLog WITH "inainte de Createobject frm_facturare_articole2: USED('saft_tip_facturi')=" + TRANSFORM(USED('saft_tip_facturi')) + ;
" USED('cTipFacturaX')=" + TRANSFORM(USED('cTipFacturaX'))
loNou = CREATEOBJECT('frm_facturare_articole2')
DO Assert WITH VARTYPE(loNou) = 'O', "Createobject frm_facturare_articole2 (calea noua)"
IF VARTYPE(loNou) <> 'O'
RETURN
ENDIF
loNou.Visible = .F.
DO AfLog WITH "dupa Createobject frm_facturare_articole2: USED('cTipFacturaX')=" + TRANSFORM(USED('cTipFacturaX'))
FOR i = 1 TO 4
lnTip = laTip[i]
lcNumeTip = laNume[i]
DO AfLog WITH "nou [" + lcNumeTip + "]: inainte de opt_incasat.Value=, USED('cTipFacturaX')=" + TRANSFORM(USED('cTipFacturaX'))
loNou.seteaza_mod_incasare(lnTip)
DO Assert WITH loNou.nmod_incasare() = lnTip, "[" + lcNumeTip + "] nmod_incasare() reflecta seteaza_mod_incasare(" + TRANSFORM(lnTip) + ")"
DO AfLog WITH "nou [" + lcNumeTip + "]: dupa opt_incasat.Value=, USED('cTipFacturaX')=" + TRANSFORM(USED('cTipFacturaX'))
DO AfLog WITH "nou [" + lcNumeTip + "]: incasat=" + TRANSFORM(poDate.incasat) + " incasatCARD=" + TRANSFORM(poDate.incasatCARD) + ;
" incasatTichete=" + TRANSFORM(poDate.incasatTichete) + " id_casa=" + TRANSFORM(poDate.id_casa) + " ntip_incasare=" + TRANSFORM(poDate.ntip_incasare)
DO Assert WITH poDate.incasat = laRezVechi[i,1], "[" + lcNumeTip + "] poDate.incasat identic (vechi=" + TRANSFORM(laRezVechi[i,1]) + " nou=" + TRANSFORM(poDate.incasat) + ")"
DO Assert WITH poDate.incasatCARD = laRezVechi[i,2], "[" + lcNumeTip + "] poDate.incasatCARD identic"
DO Assert WITH poDate.incasatTichete = laRezVechi[i,3], "[" + lcNumeTip + "] poDate.incasatTichete identic"
DO Assert WITH poDate.id_casa = laRezVechi[i,4], "[" + lcNumeTip + "] poDate.id_casa identic"
DO Assert WITH poDate.ntip_incasare = laRezVechi[i,5], "[" + lcNumeTip + "] poDate.ntip_incasare identic"
loNou.seteaza_mod_incasare(1)
DO Assert WITH loNou.nmod_incasare() = 1, "[" + lcNumeTip + "] nmod_incasare() reflecta seteaza_mod_incasare(1) (dezalocare)"
DO AfLog WITH "nou [" + lcNumeTip + "]: dezalocat, stare numere=" + StareToate()
ENDFOR
DO AfLog WITH "stare finala numere (asteptat nimic alocat): " + StareToate()
DO Assert WITH !EsteAlocat(3) AND !EsteAlocat(16) AND !EsteAlocat(26), "nimic ramas alocat la finalul rularii"
loNou.Release()
RELEASE loNou
DO AfLog WITH "dupa Release loNou: USED('saft_tip_facturi')=" + TRANSFORM(USED('saft_tip_facturi')) + ;
" USED('cTipFacturaX')=" + TRANSFORM(USED('cTipFacturaX'))
ENDPROC
PROCEDURE AsiguraSaftTipFacturi
* cboTipFactura (RowSourceType=3) citeste cursorul local saft_tip_facturi ca pe un tabel la
* instantiere (ofacturare.vc2:16157 - frm_facturare_articole2, ferestre_cere_date.vc2:2388 -
* frm_alte_date). Structura copiata din update_saft_tip_facturi (updateserver.prg:669-691),
* fara apel la server - cursor local, dummy, cu randul gol si indexul pe cod ca in original.
IF !USED('saft_tip_facturi')
CREATE CURSOR saft_tip_facturi (cod N(3) NULL, tip_saftname C(200) NULL)
INSERT INTO saft_tip_facturi (cod, tip_saftname) VALUES (NULL, '')
INDEX ON cod TAG cod
ENDIF
ENDPROC
FUNCTION EsteAlocat
LPARAMETERS tnTip
LOCAL lcCursor
IF poGeneratorNumere.paPlaje(tnTip, 6)
lcCursor = poGeneratorNumere.paPlaje(tnTip, 8)
IF EMPTY(NVL(lcCursor, [])) OR !USED(lcCursor)
RETURN .F.
ENDIF
RETURN RECCOUNT(lcCursor) > 0
ELSE
RETURN poGeneratorNumere.paPlaje(tnTip, 1) <> 0
ENDIF
ENDFUNC
FUNCTION StareNumar
LPARAMETERS tnTip
LOCAL lcCursor, lnCount
IF poGeneratorNumere.paPlaje(tnTip, 6)
lcCursor = poGeneratorNumere.paPlaje(tnTip, 8)
IF EMPTY(NVL(lcCursor, [])) OR !USED(lcCursor)
lnCount = 0
ELSE
lnCount = RECCOUNT(lcCursor)
ENDIF
RETURN "buffer:" + TRANSFORM(lnCount)
ELSE
RETURN "array:" + TRANSFORM(poGeneratorNumere.paPlaje(tnTip, 1))
ENDIF
ENDFUNC
FUNCTION StareToate
RETURN "3=" + StareNumar(3) + "|16=" + StareNumar(16) + "|26=" + StareNumar(26)
ENDFUNC
PROCEDURE ProbaSerii
LPARAMETERS tnIdTipDoc
LOCAL lnOk, laErr[1], i, lcSql
PRIVATE pnIdTipDoc, pnRezultat
pnIdTipDoc = tnIdTipDoc
pnRezultat = 0
lcSql = "{call " + gcS + ".pack_serii_numere.verifica_cursor_serii(?pnIdTipDoc,?gnIdUtil,?gnIdSucursala,?@pnRezultat)}"
FOR i = 1 TO 3
lnOk = SQLEXEC(gnHandle, lcSql, "crsprobaserii")
IF lnOk > 0
DO AfLog WITH "proba serii OK la incercarea " + TRANSFORM(i) + ", pnRezultat=" + TRANSFORM(pnRezultat) + " randuri=" + TRANSFORM(RECCOUNT("crsprobaserii"))
USE IN (SELECT("crsprobaserii"))
EXIT
ELSE
AERROR(laErr)
DO AfLog WITH "proba serii ESEC la incercarea " + TRANSFORM(i) + ": " + TRANSFORM(laErr[1]) + " / " + TRANSFORM(laErr[2]) + " / " + TRANSFORM(laErr[5])
ENDIF
ENDFOR
ENDPROC
PROCEDURE Assert
LPARAMETERS tlCond, tcMsg
IF tlCond
gnPass = gnPass + 1
DO AfLog WITH "PASS: " + tcMsg
ELSE
gnFail = gnFail + 1
DO AfLog WITH "FAIL: " + tcMsg
ENDIF
ENDPROC
PROCEDURE AfLog
LPARAMETERS tcMsg
STRTOFILE(tcMsg + CHR(13) + CHR(10), gcLog, 1)
ENDPROC
PROCEDURE AfErr
LPARAMETERS tnErr, tcMsg, tcProg, tnLine
gnFail = gnFail + 1
DO AfLog WITH "ERROR " + TRANSFORM(tnErr) + " [" + tcProg + ":" + TRANSFORM(tnLine) + "] " + tcMsg
ENDPROC
PROCEDURE Final
DO AfLog WITH "TOTAL pass=" + TRANSFORM(gnPass) + " fail=" + TRANSFORM(gnFail)
DO AfLog WITH "END " + TTOC(DATETIME())
QUIT
ENDPROC