# Rapoarte VFP (.frx/.frt): citire, creare, verificare Un `.frx` este un DBF cu 75 de campuri fixe (identice la toate rapoartele) + memo-ul `.frt`. `goExport.export2frx(cursor, "nume", ...)` il lanseaza; `getRepPath` (oexport.prg) cauta `nume.frx` in `SET PATH` (`Rapoarte\`) sau in `USERREPORTS\\USR_nume.frx`. Cursorul selectat inainte de `Report Form` este sursa expresiilor din raport. ## Campuri cheie - `OBJTYPE`: 1=raport (OBJCODE=53), 9=banda, 5=eticheta, 8=expresie/camp, 6=linie, 7=dreptunghi (OBJCODE=4), 18=variabila de raport, 25=dataenvironment. - `OBJCODE` pe `OBJTYPE=9`: 0=Title, 1=Page Header, 2=Column Header, 3=Group Header, 4=Detail, 5=Group Footer, 6=Column Footer, 7=Page Footer, 8=Summary. - `EXPR`: textul (intre ghilimele) la etichete, expresia la campuri, **expresia de grupare la banda OBJCODE=3**. `PAGEBREAK=".T."` pe OBJCODE=3 => pagina noua per grup. - `FONTFACE`/`FONTSIZE`/`FONTSTYLE` (1=bold); obiectele au `MODE=1`. - Aliniere: la **etichete** (OBJTYPE=5) `PICTURE` = `""` stanga, `"@I"` centrat, `"@J"` dreapta; la **campuri** (OBJTYPE=8) `OFFSET` = 0 stanga, 1 dreapta, 2 centrat. - Numere: `EXPR = transform(camp, get_mask(14, gnpa))` (ca rapoartele existente). `_PAGENO`, `goFirma.Antet`, `get_mask` sunt disponibile la randare. ## Asocierea obiect -> banda (capcana centrala) VFP NU asociaza obiectele dupa ordinea inregistrarilor si NU foloseste VPOS relativ la banda. `VPOS` este **absolut pe pagina**, iar banda fiecarui obiect se determina cu intervalele calculate de `FFC\_FRXCursor.vcx`: fiecarei benzi i se adauga un **separator de 2083.333 FRU**: ``` band_START = suma(inaltimilor benzilor precedente) + 2083.333 * (numarul de benzi precedente + 1) band_STOP = band_START + HEIGHT ``` Obiectul apartine primei benzi cu `band_START <= VPOS <= band_STOP` si se deseneaza la `VPOS` absolut. Deci, ca sa pui un obiect intr-o banda, calculeaza `VPOS = band_START + offset` (vezi exemplu mai jos). Verificarea exacta: ruleaza `_FRXCursor` si citeste `BANDS.START/STOP` + `OBJECTS.BANDLABEL` (vezi scriptul de mai jos). **Capcana: continutul benzii Group Header nu se randeaza** (nici cu `PAGEBREAK` pe ea, nici fara; obiectele sunt asociate corect dar nu apar). Solutia care merge: pune continutul per-grup (antet, tabel document, texte, cap de tabel) in **Page Header**, cu `VPOS` in intervalul benzii Page Header, si lasa banda Group Header **goala (HEIGHT=0) doar cu `PAGEBREAK=.T.`** ca sa declanseze pagina noua per grup. Campurile de grup (`nrdoc` etc.) se evalueaza corect in Page Header, pentru ca pagina noua incepe cu primul rand al grupului. ## Crearea unui raport nou programatic (fara IDE) `COPY STRUCTURE` NU e suficient: produce un `.frx` pe care motorul il raporteaza "is invalid" (lipseste formatul de raport). Corect: 1. `COPY FILE .frx TO .frx` si `COPY FILE .frt TO .frt` (pastreaza antetul/memo-ul exact). 2. `USE .frx EXCLUSIVE` apoi `ZAP`. 3. `APPEND BLANK` + `REPLACE` campurile, per obiect (incepe cu un `FUNCTION addrec` cu valorile implicite, suprascrie per tip). 4. Benzile: `HEIGHT` si `OBJCODE`; Title/PageFooter pot avea HEIGHT=0. Exemplu de calcul VPOS pentru benzi Title(0), PageHeader(24000), GroupHeader(0), Detail(1800), GroupFooter(15000), PageFooter(0): `PH_START=2083.333`, `GH_START=28166.666`, `DETAIL_START=30250`, `GF_START=34133.333`. Obiectele din Page Header: `VPOS=2083.333+offset`. ## Rulare headless (obligatoriu .FXP) `vfp9.exe -A ""` deschide des editorul si nu scrie log (proces viu, log gol). Corect: precompileaza intai (`COMUN\utile\Teste\_precompile.ps1 -Prg `), apoi `vfp9.exe -A ""` (fara `-T`). Prima linie: `SET SAFETY OFF`. Pune `ON ERROR DO ... WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()` care scrie in log si `QUIT`, altfel orice eroare deschide un dialog nativ si blocheaza pana la timeout. ## Verificarea ca raportul e valid si arata corect - Validitate: `FoxBin2Prg.EXE ".frx" "" "" "" 1 0 1` trebuie sa produca `.fr2`. - Continut: `SELECT ` + `REPORT FORM TO FILE ASCII NOCONSOLE` si cauta in `` antetul, coloanele, totalurile (`TO FILE` fara `ASCII` scrie binar). - Aspect: `REPORT FORM PREVIEW NOWAIT`, apoi muta fereastra copil "Print Preview" (MoveWindow) ca sa nu acopere pagina si fa screenshot pe fereastra copil cu titlul raportului (`PrintWindow`). Fara mutarea barei, jumatatea de sus a paginii e mascata de umbra ei. ## Capcane - **`COPY STRUCTURE` da un `.frx` invalid**; foloseste `COPY FILE` + `ZAP` (punctul de mai sus). - **Continutul benzii Group Header nu se randeaza**; muta-l in Page Header (punctul de mai sus). - `LOCAL laFields` + `AFIELDS(laFields, ...)` da eroarea 232 "not an array"; declara `LOCAL ARRAY laFields[1,1]`. - Fara `ON ERROR ... QUIT`, o eroare intr-un script headless deschide un dialog nativ si pare "agatat" (proces viu, CPU ~0, log gol). - `vfp9.exe -A "