raport VENITURI SI CHELTUIELI - REG JURNAL + RULAJE: documentare + index docs

This commit is contained in:
2026-08-21 21:37:13 +03:00
parent 72e8058b51
commit afd640b48a
2 changed files with 114 additions and 0 deletions

View File

@@ -6,6 +6,7 @@ Notite concise despre structura interna a proiectului (fluxuri, pachete, tabele)
- [CLAUDE.md](CLAUDE.md) — modul de lucru Claude ↔ Marius (propuneri de cod pentru VFP IDE, acces Oracle direct).
- [flux-achizitie-import.md](flux-achizitie-import.md) — lantul achizitie import: gestiuni.vcx → achizitie_import → import_nota → import_nir → PACK_CONTAFIN; capcane (ptva bruta vs proc_tva, import_nota_original mort, 4427/401).
- [rapoarte-sql-predefinite.md](rapoarte-sql-predefinite.md) — meniul „Rapoarte SQL": tabelele RAPOARTE/_FILTRE/_UTILIZATORI, parametrii `<%=AN%>`, sablonul de script de instalare; capcane (drepturi lipsa, `commit` lipsa).
- [git-svn-crlf.md](git-svn-crlf.md) — modificari fantoma in git dupa svn update (CRLF/mtime); fix cu `.gitattributes` (`* -text`) la radacina fiecarui repo.
- Credentialele Oracle stau in `COMUN\docs\local\oracle.md` (neversionat in git, exista in SVN).

View File

@@ -0,0 +1,113 @@
# Rapoarte SQL (meniu Rapoarte → „Rapoarte SQL")
Mecanism de raportare **fără `.frx`**: SQL-ul stă în baza de date, aplicația îl execută și afișează
rezultatul într-un grid (cu grupare/ordonare/export Excel). Se instalează printr-un script de
migrare, nu prin VFP IDE.
## Lansare și drepturi
- `Meniuri\rapoarte.mn2:36-37` → `DO alege_raport WITH 2, .T. IN orapoarte_dinamice.prg`.
- `alege_raport` (`COMUN\programe\orapoarte_dinamice.prg:5-79`): al doilea parametru `tlDrepturi=.T.`
⇒ lista se face cu **`join rapoarte_utilizatori ru on ... and ru.id_utilizator = gnIdUtil`**.
**Un raport fără linii în `RAPOARTE_UTILIZATORI` nu apare deloc în meniu**, oricât de corect ar fi.
- `executa_raport(tnIdFormularRaport, tnIdRaport)` (`:85-107`) deschide direct un raport după id,
fără lista de alegere.
`ID_FORMULAR_RAPORT` alege formularul:
| valoare | formular | ce e |
|---|---|---|
| 1 | `frm_date_rapoarte_rulaje` | rapoarte bazate pe rulaje |
| **2** | **`frm_date_rapoarte_sql`** (`COMUN\clase\orapoarte.vc2:4076`) | **rapoarte SQL** |
| 3 | `frm_date_rapoarte_balpart` | balanță parteneri |
## Tabele
- **`RAPOARTE`** — `CSQL` (CLOB, textul SQL), `CSQL_PARAMETRI` (XML, definiția parametrilor),
`DENUMIRE` (numele din listă, VARCHAR2(1000)), `TITLU` (titlul listării, 150), `ID_FORMULAR_RAPORT`,
`STERS`. Secvență: `SEQ_RAPOARTE`. View de listare: `VRAPOARTE`.
- **`RAPOARTE_FILTRE`** — o linie per raport, `VALOARE` = șir concatenat
`titlu;camp;pozitie_semn;;valoare|` (ex. `AN;AN;1;;0|LUNA;LUNA;1;;0|`). Generat de
`parametri_rapoarte_sql` (`orapoarte_dinamice.prg:186-206`), citit la deschidere
(`orapoarte.vc2:2709`). Marcajul `luna_curenta|` e înlocuit la citire cu luna/anul de lucru.
- **`RAPOARTE_UTILIZATORI`** — `(ID_RAPORT, ID_UTILIZATOR)`, drepturile. FK-uri către `RAPOARTE`:
doar `RAPOARTE_FILTRE` și `RAPOARTE_UTILIZATORI`.
## Parametri `<%=NUME%>`
În `CSQL` parametrii se scriu `<%=AN%>`, `<%=LUNA%>`. La rulare,
**`ct_selectie_sql.do_instructiune_sql`** (`COMUN\clase\orapoarte.vc2:1552-1637`) înlocuiește
**textual** (`STUFFC`) fiecare marcaj cu valoarea din criteriile de selecție — **nu sunt bind
variables**, deci valoarea intră brut în SQL.
Cuvinte rezervate, completate automat din globale (`orapoarte.vc2:1578-1586`):
| parametru | sursă |
|---|---|
| `AN` | `gnAn` |
| `LUNA` | `gnLuna` |
| `SUCURSALA` | `gcCondSucursala` |
Acestea **trebuie declarate cu `tipcamp = 'E'`**, iar `campid` = numele parametrului; altfel valoarea
nu se rezolvă și apare „Nu este completata valoarea parametrului X!".
`CSQL_PARAMETRI` = XML `VFPData` (encoding `Windows-1252`), câte un nod `crsparametri` cu
`parametru / titlu / camp / tipcamp / campid` (+ opțional `campcautare`); citit cu `XMLTOCURSOR` în
`criterii_rapoarte_sql` și `parametri_rapoarte_sql` (`orapoarte_dinamice.prg:109-251`).
`tipcamp`: `N` numeric, `C` caracter, `D` dată, `D1` perioadă (se traduce în `AN*12+LUNA`),
`E` cuvânt rezervat.
## Instalare printr-un script de migrare
Șablon de urmat: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\07\ff_2026_07_23_01_GESTIUNE_RAPOARTE.sql`
(raportul `CHELTUIELI CUMULAT - REG JURNAL + RULAJE`, peste view-ul `VRUL_ACT_CHELTUIELI`) și
`...\2026\08\ff_2026_08_21_01_GESTIUNE_RAPOARTE.sql` (`VENITURI SI CHELTUIELI - REG JURNAL +
RULAJE`, view `VRUL_ACT_VEN_CHELT`). Structura:
1. `CREATE OR REPLACE VIEW` cu logica raportului (SQL-ul din `CSQL` rămâne un `select` simplu peste
view — mai ușor de depanat și de refolosit).
2. Bloc anonim idempotent: `IF (select count(*) from rapoarte where upper(denumire) = '...') = 0`
→ `SEQ_RAPOARTE.nextval` + `MERGE` în `RAPOARTE` + `MERGE` în `RAPOARTE_FILTRE` + `INSERT` în
`RAPOARTE_UTILIZATORI` din `syn_vutilizatori` ⋈ `syn_vdef_util_firme` ⋈
`syn_nom_firme where schema = user and nvl(sters,0) = 0`, cu `inactiv = 0`.
3. `exec pack_migrare.UpdateVersiune('<nume_script>'); commit;`
### Capcane
- **Commit.** Blocurile anonime nu comit singure. Rulat dintr-un client care nu comite la ieșire,
view-urile rămân create (DDL = commit implicit) dar raportul lipsește din `RAPOARTE` — arată exact
ca o problemă de drepturi. Verificare rapidă: `SEQ_RAPOARTE.last_number` a avansat, dar
`select * from rapoarte` nu are linia ⇒ lipsește `commit`.
- Drepturile nu sunt opționale (vezi mai sus).
- Ordinea coloanelor din `select`-ul din `CSQL` = ordinea coloanelor din grid.
- `ORDER BY` se scrie în `CSQL`; coloanele tehnice de sortare pot fi selectate sau nu, dar trebuie să
existe în view.
### Linii de total în același raport
Pentru totaluri la finalul listării (fără al doilea raport): `UNION ALL` cu rânduri sintetice care au
coloana de grupare **`NULL`** (Oracle sortează `NULLS LAST` la `ASC`, deci ajung ultimele) și un
`R_TIP` mai mare decât cele de detaliu; eticheta se pune într-o coloană text lată (`EXPLICATIA`),
valoarea în coloana de sumă. Exemplu: `VRUL_ACT_VEN_CHELT`, `R_TIP` 9-15.
### Performanță: `WITH` materializat blochează filtrul de perioadă
Într-un view de raport filtrat pe `an`/`luna`, o subinterogare `WITH` **referită de două ori** e
materializată de Oracle într-un tabel temporar (`TEMP TABLE TRANSFORMATION` în plan). O subinterogare
materializată **nu mai primește predicatul exterior**: se construiește tot istoricul și abia la final
se aplică `an = ... and luna = ...`. Pe date de producție asta a însemnat 7.4M rânduri și un plan de
3h15m pentru o lună (`VRUL_ACT_VEN_CHELT`, versiunea inițială).
- `/*+ INLINE */` în CTE **nu** a rezolvat-o când CTE-ul e un `UNION ALL`.
- Ce funcționează: **view-uri separate în loc de CTE-uri referite de mai multe ori** — view-urile se
îmbină (view merging) și primesc predicatul. Vezi `VRUL_ACT_VEN_CHELT_DET` (detaliul) +
`VRUL_ACT_VEN_CHELT` (detaliu `UNION ALL` totaluri, referă `_DET` de două ori) în
`SCRIPTURI_CLAR\2026\08\ff_2026_08_21_01_GESTIUNE_RAPOARTE.sql`.
- Subinterogările auxiliare (ancore de dată, teste de existență, totaluri de control) citesc
**tabelele de bază `ACT` / `RUL`**, nu `VACT_TOT` / `VRUL_TOT`: view-urile astea nu filtrează
rânduri (doar left join-uri de nomenclator), dar `VRUL_TOT` are `FDOC`/`ID_FDOC` ca **subinterogări
scalare pe `ACT` per rând**. Indecși utili: `ACT` `IDX_ACT_006 (AN,LUNA,STERS,…)`,
`IDX_ACT_002 (LUNA,AN,SCD,SCC,STERS,…)`; `RUL` `IDX_RUL_003 (AN,LUNA,COD)`.
- Verificare rapidă înainte de livrare: `EXPLAIN PLAN` pe interogarea din `CSQL` cu an/luna
concrete — dacă apare `TEMP TABLE TRANSFORMATION` sau predicatul `AN=`/`LUNA=` nu se vede la
accesele pe `ACT`/`RUL`, raportul va scana tot istoricul.