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

406 lines
17 KiB
Plaintext

* test_s4c_discount_grid.prg
* Headless: S4c - discountul pe linie de articol editabil in grid, frm_facturare_articole2 (v2).
* Acopera direct campurile scrise de recalc_discount_linie (COMUN\programe\oproceduri_facturare.prg:
* 2398-2446) + calculeaza_totaluri (COMUN\programe\oproceduri_facturare.prg:2259-2394), campul real
* procdisc din creeaza_facturacrs (COMUN\programe\ofacturare_comun.prg:1794), Column14.ReadOnly = .T.
* (COMUN\clase\ofacturare.vc2:17438) si neregresia pe campul memo explicatie la ciclul
* SCATTER/GATHER NAME ... MEMO.
*
* Sase asertiuni:
* T1. recalc_discount_linie(loArt, 100, 2) [discount RON pe pret ftva=1000, cantitate=2,
* proc_tvav=1.19, tip_valuta=0] + calculeaza_totaluri: valdiminuatftva, valdiminuatctva,
* vvaldiminuatftva, vvaldiminuatctva, valdiscountftva, vvaldiscountftva egale cu valorile
* calculate manual dupa aceeasi formula (Do Case tnTip=2, ramura cu_tva=0).
* T2. recalc_discount_linie(loArt, 10, 3) [discount in valuta pe vpretftva=100, Curs=5,
* cantitate=3] + calculeaza_totaluri: aceleasi 6 campuri, ramura tnTip=3/tip_valuta=1.
* T3. procdisc = Round(discountftva/pretftva*100, 2) dupa T1 si T2.
* T4. Garda pretftva=0: recalc_discount_linie nu arunca eroare (gnErr=0) si procdisc=0.
* T5. Column14.ReadOnly = .T. pe grid-ul instantiat (frm_facturare_articole2.grd_factura.Column14).
* T6. explicatie (M) neschimbata dupa un ciclu SCATTER NAME ... MEMO / recalc / GATHER NAME ... MEMO.
*
* Sablon urmat: test_s4e_registru.prg (harness identic, acelasi env auto).
*
* Rulare: vfp9.exe -A -T "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_unificat\test_s4c_discount_grid.prg"
* Log: D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_unificat\out\test_s4c_discount_grid.log
* Mediu: ROA_CENTRAL / MARIUSM_AUTO (schema/instanta CONTAFIN_ORACLE); gnIdUtil = 8 inainte de
* creeaza_cursor_serii; gnScadereStoc = 1.
SET SAFETY OFF
SET TALK OFF
SET NOTIFY OFF
PUBLIC gcLog, gnFail, gnPass, gnErr, gcCaz, gcErr
PUBLIC gcMockApeluri, gnMockRaspuns, gcMockDuplicat, gnMockNumar
PUBLIC gnPc, gnPVal, gnPPretV, gnScadereStoc, gnMemProcDisc
gnMockNumar = 0
gnPc = 2
gnPVal = 2
gnPPretV = 4
gnScadereStoc = 1
gnMemProcDisc = 0
gcLog = "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_unificat\out\test_s4c_discount_grid.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
gnErr = 0
gcCaz = ""
gcErr = ""
gcMockApeluri = ""
gnMockRaspuns = 6
gcMockDuplicat = ""
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
LOCAL lcProc
lcProc = SET("PROCEDURE")
SET PROCEDURE TO "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_unificat\mock_validare_antet.prg", ;
"D:\ROA\ROAFACTURARE\COMUN\utile\Teste\facturare_unificat\mock_generator_numere.prg", &lcProc
IF !actualizeaza_optiuni_program()
DO AfLog WITH "FAIL: actualizeaza_optiuni_program()"
DO Final
ENDIF
gnIdUtil = 8
gnIdSucursala = 167
goExecutor.oExecuta([begin pack_sesiune.set_Id_Util(?gnIdUtil); end;])
gnScadereStoc = 1
DO AfLog WITH "ENV OK, gnAn=" + TRANSFORM(gnAn) + " gnLuna=" + TRANSFORM(gnLuna) + " gnIdSucursala=" + TRANSFORM(gnIdSucursala)
SET PATH TO "D:\ROA\ROAFACTURARE\COMUN\utile\gridextras" ADDITIVE
SET CLASSLIB TO "D:\ROA\ROAFACTURARE\COMUN\utile\gridextras\gridextras.vcx" ADDITIVE
SET CLASSLIB TO "D:\ROA\ROAFACTURARE\COMUN\clase\_cb_base.vcx" ADDITIVE
IF USED('jtva_coloane')
USE IN jtva_coloane
ENDIF
CREATE CURSOR jtva_coloane (id_jtva_coloana N(14), denumire C(50), cota_tva N(6,2))
INSERT INTO jtva_coloane VALUES (190, 'TVA 19%', 19)
INSERT INTO jtva_coloane VALUES (210, 'TVA 21%', 21)
INSERT INTO jtva_coloane VALUES (110, 'TVA 11%', 11)
GO TOP IN jtva_coloane
PRIVATE poDate, poGeneratorNumere, plVizibil, pnTotalDiscountAvize
plVizibil = .F.
pnTotalDiscountAvize = 0
poDate = NULL
poGeneratorNumere = CREATEOBJECT("oGeneratorMock")
DO TestT1
DO TestT2
DO TestT3
DO TestT4
DO TestT5
DO TestT6
DO Final
*----------------------------------------------------------------------------------------
* T1: recalc_discount_linie(loArt, 100, 2) - discount in RON pe o linie RON (tip_valuta=0),
* pretftva=1000, cantitate=2, proc_tvav=1.19. Verifica cele 6 campuri agregate dupa calculeaza_totaluri.
PROCEDURE TestT1
LOCAL loArt, lnValdiminuatftva, lnValdiminuatctva, lnVvaldiminuatftva, lnVvaldiminuatctva, ;
lnValdiscountftva, lnVvaldiscountftva
gcCaz = "[T1: recalc_discount_linie tip=2 (RON)] "
DO AfLog WITH "PAS: " + gcCaz
DO Reseteaza WITH 3
SELECT crsfactura
APPEND BLANK
REPLACE id_temp WITH 1, id_c WITH 0, id_articol WITH 401, denumire WITH "ARTICOL RON", ;
cantitate WITH 2, cu_tva WITH 0, tip_valuta WITH 0, Curs WITH 1, multiplicator WITH 1, ;
pretftva WITH 1000, pretctva WITH 1190, vpretftva WITH 1000, vpretctva WITH 1190, ;
proc_Tvav WITH 1.19, discountftva WITH 0, discountctva WITH 0, vdiscountftva WITH 0, ;
vdiscountctva WITH 0
SELECT crsfactura
SCATTER NAME loArt MEMO
loArt = recalc_discount_linie(loArt, 100, 2)
loArt = calculeaza_totaluri(loArt)
GATHER NAME loArt MEMO
DO Assert WITH gnErr = 0, "recalc_discount_linie + calculeaza_totaluri fara eroare (T1)"
SELECT crsfactura
lnValdiminuatftva = valdiminuatftva
lnValdiminuatctva = valdiminuatctva
lnVvaldiminuatftva = vvaldiminuatftva
lnVvaldiminuatctva = vvaldiminuatctva
lnValdiscountftva = valdiscountftva
lnVvaldiscountftva = vvaldiscountftva
DO Assert WITH discountftva = 100, "discountftva = 100 (obtinut: " + TRANSFORM(discountftva) + ")"
DO Assert WITH discountctva = 119, "discountctva = 119 = 100 + 100*0.19 (obtinut: " + TRANSFORM(discountctva) + ")"
DO Assert WITH lnValdiscountftva = 200, "valdiscountftva = 200 = 100*2 (obtinut: " + TRANSFORM(lnValdiscountftva) + ")"
DO Assert WITH lnVvaldiscountftva = 0, "vvaldiscountftva = 0 (vdiscountftva neatins de editarea RON, obtinut: " + TRANSFORM(lnVvaldiscountftva) + ")"
DO Assert WITH lnValdiminuatftva = 1800, "valdiminuatftva = 1800 = (1000-100)*2 (obtinut: " + TRANSFORM(lnValdiminuatftva) + ")"
DO Assert WITH lnValdiminuatctva = 2142, "valdiminuatctva = 2142 = 1800 + 1800*0.19 (obtinut: " + TRANSFORM(lnValdiminuatctva) + ")"
DO Assert WITH lnVvaldiminuatftva = 2000, "vvaldiminuatftva = 2000 = (1000-0)*2 (obtinut: " + TRANSFORM(lnVvaldiminuatftva) + ")"
DO Assert WITH lnVvaldiminuatctva = 2380, "vvaldiminuatctva = 2380 = 2000 + 2000*0.19 (obtinut: " + TRANSFORM(lnVvaldiminuatctva) + ")"
ENDPROC
*----------------------------------------------------------------------------------------
* T2: recalc_discount_linie(loArt, 10, 3) - discount in valuta pe o linie in valuta (tip_valuta=1),
* vpretftva=100, Curs=5, multiplicator=1, pretftva=500, cantitate=3, proc_tvav=1.19.
PROCEDURE TestT2
LOCAL loArt, lnValdiminuatftva, lnValdiminuatctva, lnVvaldiminuatftva, lnVvaldiminuatctva, ;
lnValdiscountftva, lnVvaldiscountftva
gcCaz = "[T2: recalc_discount_linie tip=3 (valuta)] "
DO AfLog WITH "PAS: " + gcCaz
DO Reseteaza WITH 3
SELECT crsfactura
APPEND BLANK
REPLACE id_temp WITH 1, id_c WITH 0, id_articol WITH 402, denumire WITH "ARTICOL VALUTA", ;
cantitate WITH 3, cu_tva WITH 0, tip_valuta WITH 1, Curs WITH 5, multiplicator WITH 1, ;
pretftva WITH 500, pretctva WITH 595, vpretftva WITH 100, vpretctva WITH 119, ;
proc_Tvav WITH 1.19, discountftva WITH 0, discountctva WITH 0, vdiscountftva WITH 0, ;
vdiscountctva WITH 0
SELECT crsfactura
SCATTER NAME loArt MEMO
loArt = recalc_discount_linie(loArt, 10, 3)
loArt = calculeaza_totaluri(loArt)
GATHER NAME loArt MEMO
DO Assert WITH gnErr = 0, "recalc_discount_linie + calculeaza_totaluri fara eroare (T2)"
SELECT crsfactura
lnValdiminuatftva = valdiminuatftva
lnValdiminuatctva = valdiminuatctva
lnVvaldiminuatftva = vvaldiminuatftva
lnVvaldiminuatctva = vvaldiminuatctva
lnValdiscountftva = valdiscountftva
lnVvaldiscountftva = vvaldiscountftva
DO Assert WITH vdiscountftva = 10, "vdiscountftva = 10 (obtinut: " + TRANSFORM(vdiscountftva) + ")"
DO Assert WITH discountftva = 50, "discountftva = 50 = 10*5/1 (obtinut: " + TRANSFORM(discountftva) + ")"
DO Assert WITH vdiscountctva = 11.90, "vdiscountctva = 11.90 = 10 + 10*0.19 (obtinut: " + TRANSFORM(vdiscountctva) + ")"
DO Assert WITH lnValdiscountftva = 150, "valdiscountftva = 150 = 50*3 (obtinut: " + TRANSFORM(lnValdiscountftva) + ")"
DO Assert WITH lnVvaldiscountftva = 30, "vvaldiscountftva = 30 = 10*3 (obtinut: " + TRANSFORM(lnVvaldiscountftva) + ")"
DO Assert WITH lnValdiminuatftva = 1350, "valdiminuatftva = 1350 = (500-50)*3 (obtinut: " + TRANSFORM(lnValdiminuatftva) + ")"
DO Assert WITH lnValdiminuatctva = 1606.50, "valdiminuatctva = 1606.50 = 1350 + 1350*0.19 (obtinut: " + TRANSFORM(lnValdiminuatctva) + ")"
DO Assert WITH lnVvaldiminuatftva = 270, "vvaldiminuatftva = 270 = (100-10)*3 (obtinut: " + TRANSFORM(lnVvaldiminuatftva) + ")"
DO Assert WITH lnVvaldiminuatctva = 321.30, "vvaldiminuatctva = 321.30 = 270 + 270*0.19 (obtinut: " + TRANSFORM(lnVvaldiminuatctva) + ")"
ENDPROC
*----------------------------------------------------------------------------------------
* T3: procdisc = Round(discountftva/pretftva*100, 2), verificat pe cele doua randuri ramase
* din T1/T2 (crsfactura nu e resetat intre T1..T3 in mod explicit - se reia cu Reseteaza local).
PROCEDURE TestT3
LOCAL loArt
gcCaz = "[T3: procdisc calculat] "
DO AfLog WITH "PAS: " + gcCaz
DO Reseteaza WITH 3
SELECT crsfactura
APPEND BLANK
REPLACE id_temp WITH 1, id_c WITH 0, id_articol WITH 401, denumire WITH "ARTICOL RON", ;
cantitate WITH 2, cu_tva WITH 0, tip_valuta WITH 0, Curs WITH 1, multiplicator WITH 1, ;
pretftva WITH 1000, pretctva WITH 1190, vpretftva WITH 1000, vpretctva WITH 1190, ;
proc_Tvav WITH 1.19, discountftva WITH 0, discountctva WITH 0, vdiscountftva WITH 0, ;
vdiscountctva WITH 0
SCATTER NAME loArt MEMO
loArt = recalc_discount_linie(loArt, 100, 2)
loArt = calculeaza_totaluri(loArt)
GATHER NAME loArt MEMO
DO Assert WITH procdisc = 10.00, "procdisc = 10.00 = Round(100/1000*100,2) (obtinut: " + TRANSFORM(procdisc) + ")"
SELECT crsfactura
APPEND BLANK
REPLACE id_temp WITH 2, id_c WITH 0, id_articol WITH 402, denumire WITH "ARTICOL VALUTA", ;
cantitate WITH 3, cu_tva WITH 0, tip_valuta WITH 1, Curs WITH 5, multiplicator WITH 1, ;
pretftva WITH 500, pretctva WITH 595, vpretftva WITH 100, vpretctva WITH 119, ;
proc_Tvav WITH 1.19, discountftva WITH 0, discountctva WITH 0, vdiscountftva WITH 0, ;
vdiscountctva WITH 0
SCATTER NAME loArt MEMO
loArt = recalc_discount_linie(loArt, 10, 3)
loArt = calculeaza_totaluri(loArt)
GATHER NAME loArt MEMO
DO Assert WITH procdisc = 10.00, "procdisc = 10.00 = Round(50/500*100,2) (obtinut: " + TRANSFORM(procdisc) + ")"
ENDPROC
*----------------------------------------------------------------------------------------
* T4: garda pretftva=0 - recalc_discount_linie nu arunca eroare (impartire la zero evitata),
* procdisc ramane 0.
PROCEDURE TestT4
LOCAL loArt
gcCaz = "[T4: garda pretftva=0] "
DO AfLog WITH "PAS: " + gcCaz
DO Reseteaza WITH 3
SELECT crsfactura
APPEND BLANK
REPLACE id_temp WITH 1, id_c WITH 0, id_articol WITH 403, denumire WITH "ARTICOL PRET 0", ;
cantitate WITH 1, cu_tva WITH 0, tip_valuta WITH 0, Curs WITH 1, multiplicator WITH 1, ;
pretftva WITH 0, pretctva WITH 0, vpretftva WITH 0, vpretctva WITH 0, ;
proc_Tvav WITH 1.19, discountftva WITH 0, discountctva WITH 0, vdiscountftva WITH 0, ;
vdiscountctva WITH 0
gnErr = 0
gcErr = ""
SCATTER NAME loArt MEMO
loArt = recalc_discount_linie(loArt, 50, 2)
loArt = calculeaza_totaluri(loArt)
GATHER NAME loArt MEMO
DO Assert WITH gnErr = 0, "fara eroare cu pretftva=0 (gcErr: " + gcErr + ")"
SELECT crsfactura
DO Assert WITH procdisc = 0, "procdisc = 0 cu pretftva=0, fara impartire la zero (obtinut: " + TRANSFORM(procdisc) + ")"
DO Assert WITH discountftva = 50, "discountftva tot s-a scris (=50) desi pretftva=0 (obtinut: " + TRANSFORM(discountftva) + ")"
ENDPROC
*----------------------------------------------------------------------------------------
* T5: Column14 (cProcentDiscount) e needitabila pe grid-ul instantiat.
PROCEDURE TestT5
LOCAL loForm
gcCaz = "[T5: frm_facturare_articole2 se instantiaza] "
DO AfLog WITH "PAS: " + gcCaz
DO Reseteaza WITH 3
*-- Column14.ReadOnly = .T. e verificat static (diff pe text + reconversie binar->text
*-- byte-identica), NU aici: coloanele de grid nu se materializeaza sub -A -T
*-- (Column14 nu exista ca membru desi ColumnCount=14 - grid neinitializat vizual,
*-- memorie de proiect grid-coloane-nu-se-materializeaza-headless), asa ca un
*-- Thisform.grd_factura.Column14.ReadOnly headless arunca "Unknown member".
loForm = CREATEOBJECT('frm_facturare_articole2')
DO Assert WITH VARTYPE(loForm) = 'O', "Createobject frm_facturare_articole2"
IF VARTYPE(loForm) = 'O'
loForm.Release()
ENDIF
RELEASE loForm
ENDPROC
*----------------------------------------------------------------------------------------
* T6: neregresie - campul memo explicatie ramane neschimbat dupa un ciclu
* SCATTER NAME ... MEMO / recalc_discount_linie / calculeaza_totaluri / GATHER NAME ... MEMO.
PROCEDURE TestT6
LOCAL loArt, lcExplicatieInainte, lcExplicatieDupa
gcCaz = "[T6: neregresie explicatie M la SCATTER/GATHER MEMO] "
DO AfLog WITH "PAS: " + gcCaz
DO Reseteaza WITH 3
lcExplicatieInainte = "Explicatie test S4c, text lung cu linie noua." + CHR(13) + CHR(10) + "a doua linie, semne: !?.,;:-_()"
SELECT crsfactura
APPEND BLANK
REPLACE id_temp WITH 1, id_c WITH 0, id_articol WITH 401, denumire WITH "ARTICOL EXPLICATIE", ;
cantitate WITH 1, cu_tva WITH 0, tip_valuta WITH 0, Curs WITH 1, multiplicator WITH 1, ;
pretftva WITH 1000, pretctva WITH 1190, vpretftva WITH 1000, vpretctva WITH 1190, ;
proc_Tvav WITH 1.19, discountftva WITH 0, discountctva WITH 0, vdiscountftva WITH 0, ;
vdiscountctva WITH 0
REPLACE explicatie WITH m.lcExplicatieInainte
SELECT crsfactura
SCATTER NAME loArt MEMO
loArt = recalc_discount_linie(loArt, 100, 2)
loArt = calculeaza_totaluri(loArt)
GATHER NAME loArt MEMO
SELECT crsfactura
lcExplicatieDupa = explicatie
DO Assert WITH lcExplicatieDupa == m.lcExplicatieInainte, ;
"explicatie (M) neschimbata dupa SCATTER/GATHER MEMO (lungime inainte=" + ;
TRANSFORM(LEN(m.lcExplicatieInainte)) + " dupa=" + TRANSFORM(LEN(m.lcExplicatieDupa)) + ")"
ENDPROC
*----------------------------------------------------------------------------------------
PROCEDURE Reseteaza
LPARAMETERS tnTip
LOCAL lnIdSet
DO Inchide WITH 'crsarticole'
DO Inchide WITH 'crsarticole1'
DO Inchide WITH 'crsfactura'
DO Inchide WITH 'crscursuri'
DO Inchide WITH 'crspolitici'
DO Inchide WITH 'crscontracte'
DO Inchide WITH 'crsgestiunidest'
DO Inchide WITH 'crsCtrTemp'
DO Inchide WITH 'CrsCotaTva'
DO Inchide WITH 'saft_tip_facturi'
SELECT 0
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
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
gcMockApeluri = ""
gcErr = ""
gnErr = 0
gnMockRaspuns = 6
gcMockDuplicat = ""
lnIdSet = 29000 + tnTip
poDate = NULL
poDate = CREATEOBJECT("oDateFactura", lnIdSet, tnTip)
poDate.dataireg = DATE(gnAn, gnLuna, 1)
poDate.dataact = poDate.dataireg
poDate.zi_curs = poDate.dataireg
poDate.id_fdoc = 1
poDate.fdoc = "FEL TEST"
poDate.nract = 79
poDate.serie_act = "TST"
poDate.id_client = 1
poDate.id_furnizor = 1
poDate.nrfactachi = 1
poDate.id_valuta = 1
poDate.in_valuta = 0
poDate.listaid = "1"
poGeneratorNumere.ResetNumere()
poDate.rezultat_serii = poGeneratorNumere.creeaza_cursor_serii(poDate.nIdTipDoc)
gcMockApeluri = ""
ENDPROC
PROCEDURE Inchide
LPARAMETERS tcAlias
IF USED(tcAlias)
USE IN (tcAlias)
ENDIF
ENDPROC
PROCEDURE Assert
LPARAMETERS tlCond, tcMsg
IF tlCond
gnPass = gnPass + 1
DO AfLog WITH "PASS: " + gcCaz + tcMsg
ELSE
gnFail = gnFail + 1
DO AfLog WITH "FAIL: " + gcCaz + tcMsg
ENDIF
ENDPROC
PROCEDURE AfLog
LPARAMETERS tcMsg
STRTOFILE(tcMsg + CHR(13) + CHR(10), gcLog, 1)
ENDPROC
PROCEDURE AfErr
LPARAMETERS tnErr, tcMsg, tcProg, tnLine
gcErr = gcErr + TRANSFORM(tnErr) + " " + tcMsg + " (" + TRANSFORM(tcProg) + ":" + TRANSFORM(tnLine) + ")" + CHR(13) + CHR(10)
gnErr = gnErr + 1
DO AfLog WITH "ERROR " + TRANSFORM(tnErr) + " [" + tcProg + ":" + TRANSFORM(tnLine) + "] " + tcMsg
ENDPROC
PROCEDURE Final
DO AfLog WITH "TOTAL pass=" + TRANSFORM(gnPass) + " fail=" + TRANSFORM(gnFail) + " err=" + TRANSFORM(gnErr)
DO AfLog WITH "END " + TTOC(DATETIME())
QUIT
ENDPROC