diff --git a/docs/README.md b/docs/README.md index df3fc73..ebd5e1a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,6 +21,7 @@ atingi zona X, citeste fisierul Y"). Restul se deschid doar la declansator. | **VFP** | | | `cautare_vcx_vct.md` | cauti cod in `.vcx`/`.scx`/`.frx`/`.mnx` -> skill `roa-vfp-text-edit` | | `flux-editare-vfp-text.md` | editezi `.vc2`/`.sc2` + write-back; invariantele si `*p:`/`*m:` -> skill `roa-vfp-text-edit` | +| `creare-editare-rapoarte-frx.md` | creezi/editezi un raport `.frx`/`.frt` sau verifici unul nou (structura DBF, band-uri, grupare, totaluri) -> skill `roa-vfp-frx-report` | | `conventie_encoding_cp1252.md` | fisierul editat are diacritice (cp1250, nu cp1252) -> skill `roa-vfp-text-edit` | | `inventar-comun.md` | inainte de cod nou: exista deja o functie/clasa comuna? | | `conventie_ux_formulare.md` | adaugi/rearanjezi controale pe formular | diff --git a/docs/cercetare/rec_skills.md b/docs/cercetare/rec_skills.md index 70cac8f..9875641 100644 --- a/docs/cercetare/rec_skills.md +++ b/docs/cercetare/rec_skills.md @@ -1,6 +1,6 @@ # rec_skills - skill-uri de agent pentru suita ROA -Data: 2026-09-16. Status: aplicat (10 skill-uri create, rutare + backstop puse in docs). +Data: 2026-09-16. Status: aplicat (11 skill-uri create, rutare + backstop puse in docs). ## Decizie @@ -25,6 +25,7 @@ Data: 2026-09-16. Status: aplicat (10 skill-uri create, rutare + backstop puse i |---|---| | `roa-vfp-text-edit` | editare `.vcx/.scx` pe text (`.vc2/.sc2`), cautare in binare, encoding cp1250, write-back | | `roa-vfp-headless-test` | rulare/depanare teste VFP headless, harness UI + screenshots | +| `roa-vfp-frx-report` | creezi/editezi/verifici un raport `.frx`/`.frt` (layout, benzi, grupare, totaluri, preview) | | `roa-git-svn-commit` | commit / `svn update` / `roa_sync` in COMUN | | `roa-oracle-migration` | scriere + publicare scripturi de migrare, re-export pachet PL/SQL | | `roa-oracle-diagnostic` | update ROA blocat la client, tablespace/disc plin | @@ -47,7 +48,7 @@ Data: 2026-09-16. Status: aplicat (10 skill-uri create, rutare + backstop puse i ## Verificari la data aplicarii -- 10/10 skill-uri: ASCII pur, fara BOM, `name` = folder, descriere <= 1024, exact 1 bullet sub +- 11/11 skill-uri: ASCII pur, fara BOM, `name` = folder, descriere <= 1024, exact 1 bullet sub `## Referinta (doar la nevoie)`. - 0 rute reziduale zona -> doc in `CLAUDE.md`, `AGENTS.md`, `reguli_lucru.md`, `README.md`. - `leaga_skills.ps1`: 4 create apoi idempotent (0 create, 9 ok); director real cu acelasi nume diff --git a/docs/creare-editare-rapoarte-frx.md b/docs/creare-editare-rapoarte-frx.md new file mode 100644 index 0000000..9ef3c78 --- /dev/null +++ b/docs/creare-editare-rapoarte-frx.md @@ -0,0 +1,95 @@ +# 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 "