verificare partener: garda pe cont NULL, hook-uri de disciplina, docs compactate

- ooperatii_comune: verific_partener nu mai construieste SQL NULL cand contul
  primit e NULL (EMPTY(.NULL.) e .F. in VFP)
- utile\context_watch.ps1 si utile\docs_revizie_check.ps1: masurarea contextului
  sesiunii si cadenta reviziei de documentatie, prin hook-uri Claude Code
  (instalare in docs\monitorizare-context.md)
- reguli_lucru: delegare la subagenti, modificari minime si scoped, scrierea si
  revizuirea documentatiei, changelog strictul necesar (regulile 3, 6, 9, 11, 12)
- scripturi-migrare-db: continutul unui script (scoped, fara select, idempotent)
- teste noi pentru cele doua erori din achizitia de import
- restul documentatiei compactata, fara pierdere de reguli

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYbiinqXxdEqXi53x4Ro7K
This commit is contained in:
2026-08-02 22:30:44 +03:00
parent 20323d22b3
commit c4d869921d
28 changed files with 1788 additions and 867 deletions

1
docs/.ultima_revizie Normal file
View File

@@ -0,0 +1 @@
2026-08-02

View File

@@ -1,127 +1,127 @@
# Prompt: căutare și editare în cod VFP (foxbin2prg) — reutilizabil în orice proiect Visual FoxPro
Acest fișier conține un **prompt gata de copiat** pentru Claude Code (sau alt agent), care
configurează și folosește sistemul `foxbin2prg` ca să poată **căuta** cod-sursă aflat **în interiorul
fișierelor binare VFP** (`.vcx/.vct`, `.scx/.sct`, `.frx/.frt`, `.mnx/.mnt`, `.dbc/.dct`) într-un
proiect nou — și, pentru `.vcx`/`.scx`, să poată și **modifica** acel cod direct pe text, cu
write-back în binar (`txt2vcx.ps1`), fără trecere prin IDE-ul VFP.
Unealta e partajată și stă la `D:\ROA\UTIL\foxbin2prg\` — nu trebuie copiată per proiect. Doar
spui agentului care e proiectul curent (folderul + fișierul `.pjx`).
---
## Cum se folosește
1. Deschide proiectul VFP în Claude Code.
2. Copiază blocul de mai jos în prompt.
3. Înlocuiește cele **3 valori** marcate `<<...>>` cu datele proiectului tău:
- `<<RADACINA_PROIECT>>` = folderul rădăcină al proiectului (ex. `D:\ROA\ROAGEST`)
- `<<FISIER_PJX>>` = calea către `.pjx` (ex. `D:\ROA\ROAGEST\roagest.pjx`)
- `<<NUME_PROIECT>>` = etichetă scurtă pentru folderul de cache (ex. `roagest`)
---
## ▼▼▼ PROMPT DE COPIAT ▼▼▼
```
Acest proiect este o aplicație Visual FoxPro 9. O mare parte din cod (proceduri, metode,
parametri) NU stă în fișiere .prg, ci în interiorul fișierelor binare VFP: librării de clase
(.vcx+.vct), forme (.scx+.sct), rapoarte (.frx+.frt), meniuri (.mnx+.mnt). Un grep direct pe
acestea nu e lizibil (sunt tabele DBF cu memo binar).
Ca să poți căuta în acel cod, folosește unealta partajată foxbin2prg, care convertește binarele
în reprezentarea lor TEXT (.vc2/.sc2/.fr2/.mn2/.dc2) într-un cache, și apoi caută în cache.
PARAMETRII PROIECTULUI CURENT:
- Rădăcină proiect: <<RADACINA_PROIECT>>
- Fișier proiect (.pjx): <<FISIER_PJX>>
- Cache text: D:\ROA\_vfp_textcache\<<NUME_PROIECT>>
REGULA DE AUR: cache-ul text e sursa pentru CĂUTARE (toate tipurile de binar) și, DOAR pentru
.vcx/.scx, și pentru EDITARE cu write-back (txt2vcx.ps1, vezi PAS 3). Pentru .frx/.mnx/.dbc
textul rămâne doar pentru citire — modificările la ele se fac în IDE-ul VFP, pe binar.
PAS 1 — populează cache-ul text (la începutul sesiunii, sau după ce s-a modificat ceva în IDE).
Rulează în PowerShell (e incremental — sare peste ce e deja la zi):
& 'D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1' -Project '<<FISIER_PJX>>' -ProjectRoot '<<RADACINA_PROIECT>>' -CacheRoot 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>'
(Folosește un -CacheRoot distinct per proiect ca să nu amesteci cache-urile. Implicit scriptul
convertește doar .vcx și .scx; pentru a include și rapoarte/meniuri adaugă: -Types vcx,scx,frx,mnx)
Dacă scriptul se plânge că lipsește FoxBin2Prg.EXE, trebuie compilat o singură dată: deschide
'D:\ROA\UTIL\foxbin2prg\foxbin2prg.pj2' în VFP 9 și Build > Build Executable. Anunță-mă să fac asta.
PAS 2 — caută în cache cu unealta Grep (NU în binarele originale):
Grep pe folderul 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>' pentru numele de metodă/procedură/variabilă căutat.
Ex.: caută "PROCEDURE do_salvare" sau numele tabelei/cursorului implicat.
CONVERSIE PUNCTUALĂ (un fișier sau folder care NU e în proiect, ex. o librărie din COMUN):
& 'D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1' -Source 'CALE\catre\librarie.vcx' -CacheRoot 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>'
ALTE OPȚIUNI: -Force (reconvertește tot), -Clean (șterge cache-ul întâi).
PAS 3 — modificare de cod în .vcx/.scx (flux write-back pe text). Ordinea e obligatorie:
a. Investighează pe cache, propune modificarea și AȘTEAPTĂ ACORDUL pe abordare înainte să
editezi ceva.
b. Refresh cache (PAS 1) dacă a rulat vreo sesiune de IDE de la ultimul refresh (staleness-ul
se verifică pe mtime și txt2vcx refuză corect scrierea peste modificări nevăzute). Înainte
de write-back închide COMPLET VFP IDE și exe-ul aplicației — procesele reziduale țin lock
pe binare.
c. Editează .vc2/.sc2 BYTE-SAFE: formatul e position-sensitive (nu reformata/reflow linii),
proprietățile sunt alfabetizate (una nouă se inserează la locul ei alfabetic). Headerul
CPID="1252" poate minți despre codepage-ul real al diacriticelor — citește/scrie fișierul
ca bytes (PowerShell), conținutul NOU doar ASCII; nu folosi unelte care re-encodează.
d. Write-back:
& 'D:\ROA\UTIL\foxbin2prg\txt2vcx.ps1' -TextFile 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>\Clase\lib.vc2' -ProjectRoot '<<RADACINA_PROIECT>>' -CacheRoot 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>'
Regenerează + compilează binarul în staging, verifică fidelitatea (roundtrip byte-identic
față de textul editat) și abia apoi copiază binarul în proiect; la orice eșec proiectul
rămâne neatins. Ținte sub COMUN\ cer flag-ul -AllowComun ȘI aprobare explicită — o
modificare acolo afectează toate aplicațiile ROA.
e. Diff lizibil pentru review: extrage binarul vechi din git (git show HEAD:cale > temp, atât
.vcx cât și .vct), regenerează-i textul cu vcx2txt.ps1 -Source într-un folder temporar și
compară cu cache-ul editat: git diff --no-index. COMMIT DOAR după ce omul confirmă pe diff
și testează în IDE.
EXCEPȚII: pentru .mnx (GENMENU) și .frx (fragile la round-trip) nu există write-back — scrie
propunerea de modificare într-un fișier docs/propuneri_<subiect>.md (cod + unde se inserează),
iar aplicarea se face manual în IDE-ul VFP.
FLUX TIPIC: la prima sesiune rulează PAS 1 o dată, apoi caută cu Grep în cache (PAS 2). La
sesiunile următoare rescrie doar ce s-a schimbat. Când citești codul unei metode, dă referințe
fișier:linie din cache.
```
## ▲▲▲ SFÂRȘIT PROMPT ▲▲▲
---
## Note pentru adaptare
- `<<NUME_PROIECT>>` îl poți pune orice etichetă scurtă (ex. `roagest`), doar ca numele
folderului de cache să fie unic per proiect.
- Ține cache-ul în `D:\ROA\_vfp_textcache\`, adică **în afara** folderului `foxbin2prg`. Motiv:
`ReCreate_FoxBin2Prg.prg` face `Prg2Bin` recursiv pe tot folderul tool-ului și ar reconverti
`.??2`-urile din orice cache aflat sub el înapoi în binare parazitare.
- Scriptul citește lista de fișiere direct din `.pjx`, deci convertește **doar** ce folosește
efectiv proiectul (rapid), nu tot `COMUN\`.
- Cache-ul (`D:\ROA\_vfp_textcache\<proiect>`) e regenerabil și e în afara arborelui de versionare
al proiectului (și în afara clonei foxbin2prg) — poate fi șters oricând.
- Conversia NU necesită IDE-ul VFP deschis (folosește `FoxBin2Prg.EXE` compilat).
- Fără backup-uri `.bak` lângă binarele din proiect — git e mecanismul de restore; `txt2vcx.ps1`
ține o copie de siguranță doar în folderul temp al rulării.
- Editările de volum se pot delega la subagenți (Sonnet, în background) — sesiunea principală
orchestrează, verifică diff/fidelity și intervine doar la deblocări și decizii.
- Detalii complete despre write-back (guard-uri, encoding, dialoguri VFP modale la text corupt,
testul de regresie `test_roundtrip.ps1`): `D:\ROA\UTIL\foxbin2prg\CLAUDE.md`.
- Exemplu funcțional, rodat pe ROAGEST: `D:\ROA\ROAGEST\docs\flux-editare-vfp-text.md` și
`D:\ROA\ROAGEST\docs\CLAUDE.md` (modul de lucru complet, cu review pe diff înainte de commit).
- Ghid complet doar-căutare (varianta ROAACNPRO, cu exemple): `D:\ROA\ROAACNPRO\docs\cautare_vcx_vct.md`.
- Tabel corespondență binar → text: `.vcx``.vc2`, `.scx``.sc2`, `.frx``.fr2`, `.mnx``.mn2`,
`.dbc``.dc2`, `.lbx``.lb2`.
# Prompt: căutare și editare în cod VFP (foxbin2prg) — reutilizabil în orice proiect Visual FoxPro
**Prompt gata de copiat** pentru Claude Code (sau alt agent), care configurează și folosește
sistemul `foxbin2prg` ca să poată **căuta** cod-sursă aflat **în interiorul fișierelor binare VFP**
(`.vcx/.vct`, `.scx/.sct`, `.frx/.frt`, `.mnx/.mnt`, `.dbc/.dct`) într-un proiect nou — și, pentru
`.vcx`/`.scx`, să poată și **modifica** acel cod direct pe text, cu write-back în binar
(`txt2vcx.ps1`), fără trecere prin IDE-ul VFP.
Unealta e partajată, la `D:\ROA\UTIL\foxbin2prg\` — nu se copiază per proiect. Doar spui agentului
care e proiectul curent (folderul + fișierul `.pjx`).
---
## Cum se folosește
1. Deschide proiectul VFP în Claude Code.
2. Copiază blocul de mai jos în prompt.
3. Înlocuiește cele **3 valori** marcate `<<...>>`:
- `<<RADACINA_PROIECT>>` = folderul rădăcină al proiectului (ex. `D:\ROA\ROAGEST`)
- `<<FISIER_PJX>>` = calea către `.pjx` (ex. `D:\ROA\ROAGEST\roagest.pjx`)
- `<<NUME_PROIECT>>` = etichetă scurtă pentru folderul de cache (ex. `roagest`)
---
## ▼▼▼ PROMPT DE COPIAT ▼▼▼
```
Acest proiect este o aplicație Visual FoxPro 9. O mare parte din cod (proceduri, metode,
parametri) NU stă în fișiere .prg, ci în interiorul fișierelor binare VFP: librării de clase
(.vcx+.vct), forme (.scx+.sct), rapoarte (.frx+.frt), meniuri (.mnx+.mnt). Un grep direct pe
acestea nu e lizibil (sunt tabele DBF cu memo binar).
Ca să poți căuta în acel cod, folosește unealta partajată foxbin2prg, care convertește binarele
în reprezentarea lor TEXT (.vc2/.sc2/.fr2/.mn2/.dc2) într-un cache, și apoi caută în cache.
PARAMETRII PROIECTULUI CURENT:
- Rădăcină proiect: <<RADACINA_PROIECT>>
- Fișier proiect (.pjx): <<FISIER_PJX>>
- Cache text: D:\ROA\_vfp_textcache\<<NUME_PROIECT>>
REGULA DE AUR: cache-ul text e sursa pentru CĂUTARE (toate tipurile de binar) și, DOAR pentru
.vcx/.scx, și pentru EDITARE cu write-back (txt2vcx.ps1, vezi PAS 3). Pentru .frx/.mnx/.dbc
textul rămâne doar pentru citire — modificările la ele se fac în IDE-ul VFP, pe binar.
PAS 1 — populează cache-ul text (la începutul sesiunii, sau după ce s-a modificat ceva în IDE).
Rulează în PowerShell (e incremental — sare peste ce e deja la zi):
& 'D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1' -Project '<<FISIER_PJX>>' -ProjectRoot '<<RADACINA_PROIECT>>' -CacheRoot 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>'
(Folosește un -CacheRoot distinct per proiect ca să nu amesteci cache-urile. Implicit scriptul
convertește doar .vcx și .scx; pentru a include și rapoarte/meniuri adaugă: -Types vcx,scx,frx,mnx)
Dacă scriptul se plânge că lipsește FoxBin2Prg.EXE, trebuie compilat o singură dată: deschide
'D:\ROA\UTIL\foxbin2prg\foxbin2prg.pj2' în VFP 9 și Build > Build Executable. Anunță-mă să fac asta.
PAS 2 — caută în cache cu unealta Grep (NU în binarele originale):
Grep pe folderul 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>' pentru numele de metodă/procedură/variabilă căutat.
Ex.: caută "PROCEDURE do_salvare" sau numele tabelei/cursorului implicat.
CONVERSIE PUNCTUALĂ (un fișier sau folder care NU e în proiect, ex. o librărie din COMUN):
& 'D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1' -Source 'CALE\catre\librarie.vcx' -CacheRoot 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>'
ALTE OPȚIUNI: -Force (reconvertește tot), -Clean (șterge cache-ul întâi).
PAS 3 — modificare de cod în .vcx/.scx (flux write-back pe text). Ordinea e obligatorie:
a. Investighează pe cache, propune modificarea și AȘTEAPTĂ ACORDUL pe abordare înainte să
editezi ceva.
b. Refresh cache (PAS 1) dacă a rulat vreo sesiune de IDE de la ultimul refresh (staleness-ul
se verifică pe mtime și txt2vcx refuză corect scrierea peste modificări nevăzute). Înainte
de write-back închide COMPLET VFP IDE și exe-ul aplicației — procesele reziduale țin lock
pe binare.
c. Editează .vc2/.sc2 BYTE-SAFE: formatul e position-sensitive (nu reformata/reflow linii),
proprietățile sunt alfabetizate (una nouă se inserează la locul ei alfabetic). Headerul
CPID="1252" poate minți despre codepage-ul real al diacriticelor — citește/scrie fișierul
ca bytes (PowerShell), conținutul NOU doar ASCII; nu folosi unelte care re-encodează.
d. Write-back:
& 'D:\ROA\UTIL\foxbin2prg\txt2vcx.ps1' -TextFile 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>\Clase\lib.vc2' -ProjectRoot '<<RADACINA_PROIECT>>' -CacheRoot 'D:\ROA\_vfp_textcache\<<NUME_PROIECT>>'
Regenerează + compilează binarul în staging, verifică fidelitatea (roundtrip byte-identic
față de textul editat) și abia apoi copiază binarul în proiect; la orice eșec proiectul
rămâne neatins. Ținte sub COMUN\ cer flag-ul -AllowComun ȘI aprobare explicită — o
modificare acolo afectează toate aplicațiile ROA.
e. Diff lizibil pentru review: extrage binarul vechi din git (git show HEAD:cale > temp, atât
.vcx cât și .vct), regenerează-i textul cu vcx2txt.ps1 -Source într-un folder temporar și
compară cu cache-ul editat: git diff --no-index. COMMIT DOAR după ce omul confirmă pe diff
și testează în IDE.
EXCEPȚII: pentru .mnx (GENMENU) și .frx (fragile la round-trip) nu există write-back — scrie
propunerea de modificare într-un fișier docs/propuneri_<subiect>.md (cod + unde se inserează),
iar aplicarea se face manual în IDE-ul VFP.
FLUX TIPIC: la prima sesiune rulează PAS 1 o dată, apoi caută cu Grep în cache (PAS 2). La
sesiunile următoare rescrie doar ce s-a schimbat. Când citești codul unei metode, dă referințe
fișier:linie din cache.
```
## ▲▲▲ SFÂRȘIT PROMPT ▲▲▲
---
## Note pentru adaptare
- `<<NUME_PROIECT>>` poate fi orice etichetă scurtă (ex. `roagest`), unică per proiect (numele
folderului de cache).
- Ține cache-ul în `D:\ROA\_vfp_textcache\`, adică **în afara** folderului `foxbin2prg`. Motiv:
`ReCreate_FoxBin2Prg.prg` face `Prg2Bin` recursiv pe tot folderul tool-ului și ar reconverti
`.??2`-urile din orice cache aflat sub el înapoi în binare parazitare.
- Scriptul citește lista de fișiere direct din `.pjx`, deci convertește doar ce folosește efectiv
proiectul (rapid), nu tot `COMUN\`.
- Cache-ul e regenerabil, în afara arborelui de versionare al proiectului (și al clonei
foxbin2prg) — poate fi șters oricând.
- Conversia NU necesită IDE-ul VFP deschis (folosește `FoxBin2Prg.EXE` compilat).
- Fără backup-uri `.bak` lângă binarele din proiect — git e mecanismul de restore; `txt2vcx.ps1`
ține o copie de siguranță doar în folderul temp al rulării.
- Editările de volum se pot delega la subagenți (Sonnet, în background) — sesiunea principală
orchestrează, verifică diff/fidelity și intervine doar la deblocări și decizii.
- Detalii complete despre write-back (guard-uri, encoding, dialoguri VFP modale la text corupt,
testul de regresie `test_roundtrip.ps1`): `D:\ROA\UTIL\foxbin2prg\CLAUDE.md`.
- Exemplu funcțional, rodat pe ROAGEST: `D:\ROA\ROAGEST\docs\flux-editare-vfp-text.md` și
`D:\ROA\ROAGEST\docs\CLAUDE.md` (modul de lucru complet, cu review pe diff înainte de commit).
- Ghid complet doar-căutare (varianta ROAACNPRO, cu exemple): `D:\ROA\ROAACNPRO\docs\cautare_vcx_vct.md`.
- Tabel corespondență binar → text: `.vcx``.vc2`, `.scx``.sc2`, `.frx``.fr2`, `.mnx``.mn2`,
`.dbc``.dc2`, `.lbx``.lb2`.

View File

@@ -1,139 +1,131 @@
# Căutare în codul din librăriile/formele VFP (`.vcx`/`.vct`, `.scx`/`.sct`, ...)
Partajat între proiectele ROA* (companion narativ la `PROMPT_cautare_vfp.md` din acest folder,
care e varianta "prompt de copiat" — acest fișier e ghidul de referință complet, cu exemple).
Cum se caută cod-sursă (proceduri, metode, parametri) care **nu** stă în fișiere `.prg`, ci
în interiorul fișierelor binare VFP: librării de clase (`.vcx`+`.vct`), forme (`.scx`+`.sct`),
rapoarte (`.frx`+`.frt`), meniuri (`.mnx`+`.mnt`), baze de date (`.dbc`+`.dct`).
## De ce e nevoie de asta
Un `.vcx` este de fapt o **tabelă DBF**: codul metodelor stă în câmpuri memo în `.vct`. Un
`grep` direct pe `.vct` *găsește* textul, dar îl vede ca fișier binar (octeți `\0` între linii),
fără numere de linie utile și greu de citit. Soluția: convertim binarul în reprezentarea lui
**TEXT** (`.vc2`, `.sc2`, …) — un PRG-style lizibil, cu metode sortate alfabetic — și căutăm
în text cu `grep`/`Grep`.
> **Regula de aur:** textul generat e **doar pentru citire/căutare**, CU O EXCEPȚIE: pentru
> `.vcx`/`.scx` se poate și edita pe text, cu write-back în binar (`txt2vcx.ps1`) — vezi
> `PROMPT_cautare_vfp.md` pasul 3 pentru fluxul complet (ordine obligatorie, encoding,
> fidelity check). Pentru `.frx`/`.mnx`/`.dbc` nu există write-back — modificările se fac tot
> în **IDE-ul VFP**.
## Unelte disponibile (verificate)
| Unealtă | Cale | Rol | Recomandare |
|---|---|---|---|
| **FoxBin2Prg** | `D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE` | Binar VFP ⇄ text bidirecțional (`.vc2/.sc2/.fr2/.mn2/.dc2/.lb2`) | **De folosit.** Complet, fidel, include corpul metodelor, parametri, comentarii |
| vcx2prg | `D:\ROA\UTIL\vcx2prg\x2prg.prg` | Doar `.vcx``.prg` *compilabil* | Alternativă; mai vechi, doar clase, necesită IDE VFP deschis pentru a rula forma |
| prgtovcx | `D:\ROA\UTIL\prgtovcx\prgtovcx.PRG` | Invers: `.prg``.vcx` | **Nu** pentru căutare (e direcția opusă) |
FoxBin2Prg e prima alegere: rulează din linia de comandă fără IDE deschis (EXE compilat), acoperă
toate tipurile de container, și produce text mult mai fidel decât vcx2prg.
> Dacă `FoxBin2Prg.EXE` lipsește, se compilează o singură dată: deschide
> `D:\ROA\UTIL\foxbin2prg\foxbin2prg.pj2` în VFP 9 și *Build > Build Executable*. Lângă EXE trebuie
> să existe `filename_caps.exe` și fișierele `props*.txt` (sunt deja în folder).
## Mod recomandat: scriptul `vcx2txt.ps1`
`D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1` automatizează tot: copiază binarul + memo-ul într-un
**cache** care oglindește structura proiectului (ca să nu murdărească arborele SVN), rulează
FoxBin2Prg, păstrează doar fișierul text. E **incremental** (sare peste ce e deja la zi).
Parametrizează scriptul cu proiectul curent și un cache separat per proiect (nu amesteca
cache-urile mai multor proiecte ROA):
```powershell
# DOAR fișierele proiectului curent (recomandat, rapid) -> cache text propriu
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
-Project '<RADACINA_PROIECT>\<proiect>.pjx' -ProjectRoot '<RADACINA_PROIECT>' `
-CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>'
# include și rapoartele (.frx) și meniurile (.mnx)
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
-Project '<RADACINA_PROIECT>\<proiect>.pjx' -ProjectRoot '<RADACINA_PROIECT>' `
-CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>' -Types vcx,scx,frx,mnx
# conversie punctuală a unui fișier sau folder (chiar dacă NU e în proiect, ex. o clasă din COMUN)
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source '<RADACINA_PROIECT>\COMUN\clase\caut.vcx'
# rebuild curat (șterge cache-ul întâi) / forțează reconversia
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
-Project '<RADACINA_PROIECT>\<proiect>.pjx' -ProjectRoot '<RADACINA_PROIECT>' `
-CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>' -Clean
```
Exemplu concret (ROAAUTO):
```powershell
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
-Project D:\ROA\ROAAUTO\roaauto.pjx -ProjectRoot D:\ROA\ROAAUTO `
-CacheRoot D:\ROA\UTIL\foxbin2prg\_textcache_roaauto
```
Rezultatul ajunge în cache-ul indicat, cu aceeași structură de directoare ca proiectul (ex.:
`_textcache_roaauto\Clase\odevize.vc2`, `_textcache_roaauto\comun\clase\_frm_base.vc2`). Apoi:
```bash
# cu unealta Grep (preferat) sau grep:
grep -rn "PROCEDURE do_calcul_tarife" "D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>"
grep -rln "factura_salvare" "D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>" # ce clase ating subiectul
```
Flux tipic pentru o problemă: rulează scriptul cu parametrii de mai sus o dată (populează
cache-ul), apoi caută cu `Grep` în cache. La sesiuni următoare rescrie doar ce s-a schimbat
(incremental). Dacă ai nevoie de o librărie din `COMUN\` care nu e în proiect, convertește-o
punctual cu `-Source`.
## Alternativă manuală (fără script)
FoxBin2Prg scrie textul **lângă sursă**. Ca să nu murdărești folderul de clase al proiectului,
copiază perechea binar+memo într-un folder temporar și convertește acolo:
```powershell
# .vcx -> .vc2 (cType gol = extensia decide direcția BIN2PRG)
Copy-Item D:\ROA\<proiect>\Clase\odevize.vcx, D:\ROA\<proiect>\Clase\odevize.vct D:\tmp\
& 'D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE' 'D:\tmp\odevize.vcx' '' '' '' '1' '0' '1'
# => D:\tmp\odevize.vc2
```
Pozițiile parametrilor folosite: `fișier, cType, cTextName, lGenText, cDontShowErrors=1,
cDebug=0, cDontShowProgress=1`. **Lasă `cType` gol** — extensia (`.vcx`) determină direcția.
(Nu da explicit `"BIN2PRG"` pentru un singur fișier: în acel mod EXE-ul așteaptă un *director*.)
Detalii complete de parametri: `D:\ROA\UTIL\foxbin2prg\docs\FoxBin2Prg_Run.md`.
## Soluție rapidă „murdară" (un singur fișier, fără conversie)
Pentru o verificare rapidă „există metoda X undeva în librărie?", `grep` merge direct pe `.vct`
(o vede ca binar, dar găsește potrivirile):
```bash
grep -c "PROCEDURE" "D:\ROA\<proiect>\Clase\odevize.VCT"
grep -a -o "PROCEDURE [a-zA-Z0-9_]*" "D:\ROA\<proiect>\Clase\odevize.VCT"
```
Bun pentru „da/nu" și nume de metode; pentru citit corpul/contextul, folosește conversia în text.
## Corespondență extensii binar → text
| Container | Binar (+memo) | Text |
|---|---|---|
| Librărie clase | `.vcx` + `.vct` | `.vc2` |
| Formă | `.scx` + `.sct` | `.sc2` |
| Raport | `.frx` + `.frt` | `.fr2` |
| Etichetă | `.lbx` + `.lbt` | `.lb2` |
| Meniu | `.mnx` + `.mnt` | `.mn2` |
| Bază de date | `.dbc` + `.dct` | `.dc2` |
## Note
- Codul aplicației stă mai ales în `Clase\*.vcx`; o mare parte din `.vcx`-uri sunt în
`COMUN\` (framework partajat între toate aplicațiile ROA — vezi `CLAUDE.md` per proiect).
- Cache-ul text e regenerabil și e în afara arborelui SVN/git al proiectului — poate fi șters
oricând.
- Conversia **nu** necesită IDE-ul VFP deschis (folosește EXE-ul compilat).
- Vezi și [conventie_encoding_cp1252.md](conventie_encoding_cp1252.md) — capcană de encoding la
editarea `.sc2`/`.vc2` (nu doar la căutare).
# Căutare în codul din librăriile/formele VFP (`.vcx`/`.vct`, `.scx`/`.sct`, ...)
Partajat între proiectele ROA* (companion narativ la `PROMPT_cautare_vfp.md` din acest folder
varianta "prompt de copiat" — acest fișier e ghidul de referință complet, cu exemple).
Căutare de cod-sursă (proceduri, metode, parametri) care **nu** stă în `.prg`, ci în interiorul
binarelor VFP: librării de clase (`.vcx`+`.vct`), forme (`.scx`+`.sct`), rapoarte (`.frx`+`.frt`),
meniuri (`.mnx`+`.mnt`), baze de date (`.dbc`+`.dct`).
## De ce e nevoie de asta
Un `.vcx` e o **tabelă DBF**: codul metodelor stă în câmpuri memo în `.vct`. `grep` direct pe
`.vct` găsește textul dar ca binar (octeți `\0` între linii), fără numere de linie și greu de
citit. Soluția: convertim binarul în reprezentarea lui **TEXT** (`.vc2`, `.sc2`, …) — PRG-style
lizibil, metode sortate alfabetic — și căutăm în text cu `grep`/`Grep`.
> **Regula de aur:** textul generat e **doar pentru citire/căutare**, CU O EXCEPȚIE: pentru
> `.vcx`/`.scx` se poate și edita pe text, cu write-back în binar (`txt2vcx.ps1`) — vezi
> `PROMPT_cautare_vfp.md` pasul 3 (ordine obligatorie, encoding, fidelity check). Pentru
> `.frx`/`.mnx`/`.dbc` nu există write-back — modificările se fac tot în **IDE-ul VFP**.
## Unelte disponibile (verificate)
| Unealtă | Cale | Rol | Recomandare |
|---|---|---|---|
| **FoxBin2Prg** | `D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE` | Binar VFP ⇄ text bidirecțional (`.vc2/.sc2/.fr2/.mn2/.dc2/.lb2`) | **De folosit.** Fidel, include corpul metodelor, parametri, comentarii |
| vcx2prg | `D:\ROA\UTIL\vcx2prg\x2prg.prg` | Doar `.vcx``.prg` compilabil | Alternativă mai veche, doar clase, necesită IDE VFP deschis |
| prgtovcx | `D:\ROA\UTIL\prgtovcx\prgtovcx.PRG` | Invers: `.prg``.vcx` | **Nu** pentru căutare (direcție opusă) |
FoxBin2Prg e prima alegere: rulează din linia de comandă fără IDE deschis (EXE compilat), acoperă
toate tipurile de container, text mai fidel decât vcx2prg.
> Dacă `FoxBin2Prg.EXE` lipsește: deschide `D:\ROA\UTIL\foxbin2prg\foxbin2prg.pj2` în VFP 9 și
> *Build > Build Executable*. Lângă EXE trebuie să existe `filename_caps.exe` și `props*.txt`
> (deja în folder).
## Mod recomandat: scriptul `vcx2txt.ps1`
`D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1` copiază binarul + memo-ul într-un **cache** care oglindește
structura proiectului (nu murdărește arborele SVN), rulează FoxBin2Prg, păstrează doar textul.
**Incremental** (sare peste ce e deja la zi).
```powershell
# DOAR fișierele proiectului curent (recomandat, rapid) -> cache text propriu
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
-Project '<RADACINA_PROIECT>\<proiect>.pjx' -ProjectRoot '<RADACINA_PROIECT>' `
-CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>'
# include și rapoartele (.frx) și meniurile (.mnx)
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
-Project '<RADACINA_PROIECT>\<proiect>.pjx' -ProjectRoot '<RADACINA_PROIECT>' `
-CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>' -Types vcx,scx,frx,mnx
# conversie punctuală a unui fișier/folder (chiar dacă NU e în proiect, ex. o clasă din COMUN)
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source '<RADACINA_PROIECT>\COMUN\clase\caut.vcx'
# rebuild curat (șterge cache-ul întâi) / forțează reconversia
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
-Project '<RADACINA_PROIECT>\<proiect>.pjx' -ProjectRoot '<RADACINA_PROIECT>' `
-CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>' -Clean
```
Exemplu (ROAAUTO):
```powershell
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
-Project D:\ROA\ROAAUTO\roaauto.pjx -ProjectRoot D:\ROA\ROAAUTO `
-CacheRoot D:\ROA\UTIL\foxbin2prg\_textcache_roaauto
```
Rezultatul ajunge în cache, cu aceeași structură de directoare ca proiectul (ex.:
`_textcache_roaauto\Clase\odevize.vc2`, `_textcache_roaauto\comun\clase\_frm_base.vc2`). Apoi:
```bash
grep -rn "PROCEDURE do_calcul_tarife" "D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>"
grep -rln "factura_salvare" "D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>" # ce clase ating subiectul
```
Flux tipic: rulează scriptul o dată (populează cache-ul), apoi caută cu `Grep` în cache. La
sesiuni următoare rescrie doar ce s-a schimbat (incremental). Pentru o librărie din `COMUN\` care
nu e în proiect, convertește-o punctual cu `-Source`.
## Alternativă manuală (fără script)
FoxBin2Prg scrie textul **lângă sursă**. Ca să nu murdărești folderul de clase al proiectului,
copiază perechea binar+memo într-un folder temporar și convertește acolo:
```powershell
# .vcx -> .vc2 (cType gol = extensia decide direcția BIN2PRG)
Copy-Item D:\ROA\<proiect>\Clase\odevize.vcx, D:\ROA\<proiect>\Clase\odevize.vct D:\tmp\
& 'D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE' 'D:\tmp\odevize.vcx' '' '' '' '1' '0' '1'
# => D:\tmp\odevize.vc2
```
Poziții parametri: `fișier, cType, cTextName, lGenText, cDontShowErrors=1, cDebug=0,
cDontShowProgress=1`. **Lasă `cType` gol** extensia (`.vcx`) determină direcția. (Nu da explicit
`"BIN2PRG"` pentru un singur fișier: în acel mod EXE-ul așteaptă un *director*.)
Detalii complete de parametri: `D:\ROA\UTIL\foxbin2prg\docs\FoxBin2Prg_Run.md`.
## Soluție rapidă „murdară" (un singur fișier, fără conversie)
Pentru „există metoda X undeva în librărie?", `grep` merge direct pe `.vct` (îl vede ca binar, dar
găsește potrivirile):
```bash
grep -c "PROCEDURE" "D:\ROA\<proiect>\Clase\odevize.VCT"
grep -a -o "PROCEDURE [a-zA-Z0-9_]*" "D:\ROA\<proiect>\Clase\odevize.VCT"
```
Bun pentru „da/nu" și nume de metode; pentru corp/context, folosește conversia în text.
## Corespondență extensii binar → text
| Container | Binar (+memo) | Text |
|---|---|---|
| Librărie clase | `.vcx` + `.vct` | `.vc2` |
| Formă | `.scx` + `.sct` | `.sc2` |
| Raport | `.frx` + `.frt` | `.fr2` |
| Etichetă | `.lbx` + `.lbt` | `.lb2` |
| Meniu | `.mnx` + `.mnt` | `.mn2` |
| Bază de date | `.dbc` + `.dct` | `.dc2` |
## Note
- Codul aplicației stă mai ales în `Clase\*.vcx`; multe `.vcx`-uri sunt în `COMUN\` (framework
partajat între toate aplicațiile ROA — vezi `CLAUDE.md` per proiect).
- Cache-ul text e regenerabil, în afara arborelui SVN/git al proiectului — poate fi șters oricând.
- Conversia **nu** necesită IDE-ul VFP deschis (folosește EXE-ul compilat).
- Vezi și [conventie_encoding_cp1252.md](conventie_encoding_cp1252.md) — capcană de encoding la
editarea `.sc2`/`.vc2` (nu doar la căutare).

View File

@@ -1,82 +1,71 @@
# Capcană: corupere diacritice la editarea `.sc2`/`.vc2` (encoding cp1252)
Partajat între proiectele ROA* (similar cu `PROMPT_cautare_vfp.md` din acest folder) — capcana
ține de formatul `.sc2`/`.vc2` produs de FoxBin2Prg, nu de un proiect anume.
Descoperit de 2 ori în aceeași sesiune (2026-07-10, în ROAAUTO): odată în
`COMUN/clase/cmd_butoane.vc2` (clasa `cmd_select_adv`), odată în `Clase/ofundal_dev.vc2`
(meniul principal) — de fiecare dată un agent anterior a editat text-cache-ul cu un tool care
nu scrie cp1252 nativ, și a corupt TOATE caracterele cu diacritice din fișier, nu doar linia
pe care voia s-o schimbe.
## De ce se întâmplă
Fișierele `.sc2`/`.vc2` generate de FoxBin2Prg sunt **cp1252 (Windows-1252)**, nu UTF-8
(vezi antetul fiecărui fișier: `CPID="1252"`). Dacă un editor/tool citește fișierul ca UTF-8
(sau alt encoding), fiecare byte >= 0x80 (diacritic) devine invalid ca secvență UTF-8 și e
înlocuit cu caracterul de replacement U+FFFD. Dacă apoi tool-ul **salvează rezultatul tot ca
UTF-8**, acel U+FFFD e scris ca 3 octeți UTF-8 (`0xEF 0xBF 0xBD`) — care, citiți înapoi ca
cp1252 (cum face FoxBin2Prg la write-back), apar ca `�`. Rezultatul: caracterul original e
**ireversibil pierdut** (nu mai există în fișier sub nicio formă) — recuperabil DOAR din altă
sursă (git history, backup).
Codebase-ul ROA folosește un hack vechi de "reciclare" a unor caractere cp1252 needependente
de Ș/ă/ț (care nu au echivalent direct în cp1252) pentru diacritice românești:
| Literă românească | Caracter folosit (cp1252) | Byte |
|---|---|---|
| ă | ã (a-tilde) | `0xE3` |
| Ă | Ã | `0xC3` |
| ț | þ (thorn minuscul) | `0xFE` |
| Ș (majusculă) | ª (ordinal masculin) | `0xAA` |
| ș (minusculă) | º (ordinal feminin) | `0xBA` |
| î, â | î, â (existente nativ în cp1252) | `0xEE`, `0xE2` |
Aceste caractere par "gunoi"/typo la prima vedere într-un editor UTF-8 (`ã`, `þ`, `ª`, `º`) —
**sunt corecte, nu le "corecta" fără să verifici encoding-ul.**
## Cum se verifică dacă un fișier `.sc2`/`.vc2` e corupt
```powershell
$bytes = [System.IO.File]::ReadAllBytes("<path>.vc2")
$text = [System.Text.Encoding]::GetEncoding(1252).GetString($bytes)
$text -split "`r`n" | Select-String ([char]0xFFFD) # cauta caracterul de replacement
```
Dacă apare `�` (sau `$text` conține U+FFFD) în output — fișierul are corupere de encoding.
## Cum se repară
1. **Nu edita orbește peste corupere** — caracterul original e deja pierdut din fișierul
curent.
2. Dacă fișierul e sub control de versiune (git) și corupera s-a întâmplat **într-o sesiune
anterioară necomisă** (deci HEAD-ul git încă are versiunea curată): recuperează originalul
convertind binarul din HEAD în text și comparând:
```bash
git show HEAD:<cale>.vcx > /tmp/head.vcx
git show HEAD:<cale>.vct > /tmp/head.vct # (sau .VCT, dupa caz)
powershell -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source /tmp/head.vcx -CacheRoot /tmp/head_out
```
apoi decodează ambele fișiere (HEAD curat + curent corupt) ca cp1252 și compară linie cu
linie (PowerShell, nu `diff` direct — `diff`/Bash nu decodează cp1252 corect pentru afișare,
deși detectează totuși diferența de octeți).
3. Reconstruiește fișierul text pornind de la versiunea HEAD (curată), și reaplică DOAR
modificările intenționate din sesiunea curentă peste ea (nu invers — nu încerca să "cârpești"
fișierul corupt caracter cu caracter, e mai sigur să repornești de la baza curată).
4. Scrie rezultatul înapoi ca bytes cp1252 (`[System.Text.Encoding]::GetEncoding(1252).GetBytes(...)`),
NU ca string UTF-8/`Out-File` implicit (care scrie UTF-8 sau UTF-16 după caz).
5. Rulează write-back (`txt2vcx.ps1 -Force`) și verifică fidelity check = zero diferențe.
## Cum se evită pe viitor
Când editezi `.sc2`/`.vc2` cu tool-uri text (Read/Edit/Write), verifică întâi dacă fișierul
conține diacritice (`ã`, `þ`, `ª`, `º`, `î`, `â` etc.) — dacă da, **orice rescrie completă a
fișierului trebuie făcută la nivel de octeți cu encoding cp1252 explicit**, nu presupunând
UTF-8 implicit. Editările punctuale (Edit tool, string replace) sunt sigure DOAR dacă tool-ul
păstrează restul fișierului byte-identic (nu rescrie tot fișierul reîncodat).
## Vezi și
`PROMPT_cautare_vfp.md` din acest folder, pasul 3.c — menționează deja riscul ("Headerul
CPID="1252" poate minți...") pe scurt; acest fișier e detalierea completă (tabel de caractere,
pași de recuperare din git).
# Capcană: corupere diacritice la editarea `.sc2`/`.vc2` (encoding cp1252)
Partajat între proiectele ROA* — capcana ține de formatul `.sc2`/`.vc2` produs de FoxBin2Prg,
nu de un proiect anume.
## De ce se întâmplă
Fișierele `.sc2`/`.vc2` sunt **cp1252** (Windows-1252), nu UTF-8 (vezi antetul: `CPID="1252"`).
Dacă un editor/tool citește fișierul ca UTF-8, fiecare byte >= 0x80 (diacritic) devine invalid
ca secvență UTF-8 și e înlocuit cu U+FFFD. Dacă tool-ul apoi **salvează tot ca UTF-8**, acel
U+FFFD e scris ca 3 octeți (`0xEF 0xBF 0xBD`) — care, citiți înapoi ca cp1252 (cum face
FoxBin2Prg la write-back), apar ca `�`. Caracterul original e **ireversibil pierdut**
(recuperabil DOAR din altă sursă: git history, backup).
Codebase-ul ROA "reciclează" caractere cp1252 fără echivalent direct pentru Ș/ă/ț:
| Literă românească | Caracter folosit (cp1252) | Byte |
|---|---|---|
| ă | ã (a-tilde) | `0xE3` |
| Ă | Ã | `0xC3` |
| ț | þ (thorn minuscul) | `0xFE` |
| Ș (majusculă) | ª (ordinal masculin) | `0xAA` |
| ș (minusculă) | º (ordinal feminin) | `0xBA` |
| î, â | î, â (native cp1252) | `0xEE`, `0xE2` |
Par "gunoi"/typo într-un editor UTF-8 (`ã`, `þ`, `ª`, `º`) — **sunt corecte, nu le "corecta"
fără să verifici encoding-ul.**
## Cum se verifică dacă un fișier `.sc2`/`.vc2` e corupt
```powershell
$bytes = [System.IO.File]::ReadAllBytes("<path>.vc2")
$text = [System.Text.Encoding]::GetEncoding(1252).GetString($bytes)
$text -split "`r`n" | Select-String ([char]0xFFFD) # cauta caracterul de replacement
```
Dacă apare `�` (sau `$text` conține U+FFFD) — fișierul are corupere de encoding.
## Cum se repară
1. **Nu edita orbește peste corupere** — caracterul original e deja pierdut din fișierul curent.
2. Dacă corupera s-a întâmplat într-o sesiune anterioară necomisă (HEAD-ul git încă e curat):
recuperează originalul convertind binarul din HEAD în text:
```bash
git show HEAD:<cale>.vcx > /tmp/head.vcx
git show HEAD:<cale>.vct > /tmp/head.vct # (sau .VCT, dupa caz)
powershell -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source /tmp/head.vcx -CacheRoot /tmp/head_out
```
apoi decodează ambele fișiere (HEAD curat + curent corupt) ca cp1252 și compară linie cu
linie (PowerShell, nu `diff`/Bash direct — nu decodează cp1252 corect la afișare, deși
detectează totuși diferența de octeți).
3. Reconstruiește fișierul text pornind de la versiunea HEAD (curată), reaplicând DOAR
modificările intenționate din sesiunea curentă (nu invers — nu cârpi fișierul corupt
caracter cu caracter).
4. Scrie rezultatul înapoi ca bytes cp1252
(`[System.Text.Encoding]::GetEncoding(1252).GetBytes(...)`), NU ca string UTF-8/`Out-File`
implicit.
5. Rulează write-back (`txt2vcx.ps1 -Force`) și verifică fidelity check = zero diferențe.
## Cum se evită pe viitor
Când editezi `.sc2`/`.vc2` cu tool-uri text (Read/Edit/Write), verifică întâi dacă fișierul
conține diacritice (`ã`, `þ`, `ª`, `º`, `î`, `â` etc.) — dacă da, **orice rescrie completă
trebuie făcută la nivel de octeți cu encoding cp1252 explicit**, nu presupunând UTF-8.
Editările punctuale (Edit tool, string replace) sunt sigure DOAR dacă tool-ul păstrează restul
fișierului byte-identic (nu rescrie tot fișierul reîncodat).
## Vezi și
`PROMPT_cautare_vfp.md` din acest folder, pasul 3.c — menționează riscul pe scurt; acest fișier
e detalierea completă (tabel de caractere, pași de recuperare din git).

View File

@@ -1,65 +1,55 @@
# Capcană: `ALTER TABLE` pe cursorul întors de `goExecutor.oExecute()`
Partajat între proiectele ROA* — `goExecutor` (clasa `oExecutor`, definită în
`COMUN/programe/oproceduri_comune.prg`, metoda `oExecute`) e utilitarul standard pentru
interogări SQL pass-through (`SQLExec`) către Oracle, folosit peste tot în codul ROA*.
## Ce nu funcționează
```foxpro
lnSucces = goExecutor.oExecute(lcSql, lcCursor)
...
ALTER TABLE (lcCursor) ADD COLUMN coloananoua L && <- pică
```
Cursorul întors de `oExecute()` (rezultatul unui `SQLExec`) poate refuza comenzi DDL
ulterioare, cu erori în lanț (descoperite empiric, în această ordine, în ROAAUTO
`autopass_cursor_comenzi`/`autopass_cursor_operatii`):
1. `Function is not supported on remote tables.` — pe `ALTER TABLE` direct pe cursorul
original.
2. Chiar și după o încercare de rematerializare (`SELECT * FROM (cursor) INTO CURSOR
(acelasi_nume) READWRITE`) → `Alias name is already in use.` (sursa și ținta nu pot
avea același nume într-un `SELECT...INTO CURSOR`).
3. Cu un alias scratch diferit ca țintă (`SELECT * FROM (cursor) INTO CURSOR
(nume_final_diferit_de_sursa) READWRITE`) → tot `Invalid operation for the cursor.` pe
`ALTER TABLE`, chiar dacă acum cursorul final teoretic ar trebui să fie unul local
obișnuit.
Nu există niciun alt loc în codul ROA* care să facă `ALTER TABLE` imediat după
`goExecutor.oExecute()` — deci acest pattern nu avea niciun precedent testat înainte de
funcțiile AUTOPASS.
## Ce funcționează
**Nu folosi `ALTER TABLE` deloc pe rezultatul unui `oExecute()`.** Include coloanele
suplimentare direct în `SELECT`-ul de rematerializare, ca expresii literale alături de `*`
(VFP suportă `SELECT *, expr AS coloana FROM ...`):
```foxpro
lcCursorRaw = lcCursor + '_raw'
IF USED(lcCursorRaw)
USE IN (lcCursorRaw)
ENDIF
lnSucces = goExecutor.oExecute(lcSql, lcCursorRaw)
IF lnSucces < 0
* tratare eroare, RETURN
ENDIF
SELECT *, .F. AS coloananoua, SPACE(100) AS altacoloana ;
FROM (lcCursorRaw) INTO CURSOR (lcCursor) READWRITE
USE IN (lcCursorRaw)
* de-aici incolo doar REPLACE (date), NICIODATA ALTER TABLE (structura) pe (lcCursor)
```
După acest pas, cursorul (`lcCursor`) e un cursor local obișnuit — `ALTER TABLE` funcționează
normal pe el DUPĂ ACEEA (ex. dintr-o altă funcție care primește cursorul deja gata construit,
nu direct rezultatul unui `oExecute`), doar comanda imediat următoare unui `oExecute()` e
restricționată.
## Vezi și
Exemplu complet aplicat: ROAAUTO, `Programe/oproceduri_autopass.prg`,
`autopass_cursor_comenzi()`/`autopass_cursor_operatii()`.
# Capcană: `ALTER TABLE` pe cursorul întors de `goExecutor.oExecute()`
Partajat între proiectele ROA* — `goExecutor` (clasa `oExecutor`, definită în
`COMUN/programe/oproceduri_comune.prg`, metoda `oExecute`) e utilitarul standard pentru
interogări SQL pass-through (`SQLExec`) către Oracle, folosit peste tot în codul ROA*.
## Ce nu funcționează
```foxpro
lnSucces = goExecutor.oExecute(lcSql, lcCursor)
...
ALTER TABLE (lcCursor) ADD COLUMN coloananoua L && <- pică
```
Cursorul întors de `oExecute()` poate refuza comenzi DDL ulterioare, cu erori în lanț
(descoperite empiric, în această ordine):
1. `Function is not supported on remote tables.` — pe `ALTER TABLE` direct pe cursorul original.
2. Chiar și după rematerializare (`SELECT * FROM (cursor) INTO CURSOR (acelasi_nume) READWRITE`)
`Alias name is already in use.` (sursa și ținta nu pot avea același nume).
3. Cu alias scratch diferit ca țintă → tot `Invalid operation for the cursor.` pe `ALTER TABLE`,
chiar dacă țintă ar trebui să fie deja un cursor local obișnuit.
## Ce funcționează
**Nu folosi `ALTER TABLE` deloc pe rezultatul unui `oExecute()`.** Include coloanele
suplimentare direct în `SELECT`-ul de rematerializare, ca expresii literale alături de `*`
(VFP suportă `SELECT *, expr AS coloana FROM ...`):
```foxpro
lcCursorRaw = lcCursor + '_raw'
IF USED(lcCursorRaw)
USE IN (lcCursorRaw)
ENDIF
lnSucces = goExecutor.oExecute(lcSql, lcCursorRaw)
IF lnSucces < 0
* tratare eroare, RETURN
ENDIF
SELECT *, .F. AS coloananoua, SPACE(100) AS altacoloana ;
FROM (lcCursorRaw) INTO CURSOR (lcCursor) READWRITE
USE IN (lcCursorRaw)
* de-aici incolo doar REPLACE (date), NICIODATA ALTER TABLE (structura) pe (lcCursor)
```
După acest pas, cursorul (`lcCursor`) e un cursor local obișnuit — `ALTER TABLE` funcționează
normal pe el DUPĂ ACEEA (ex. într-o altă funcție care primește cursorul deja gata construit),
doar comanda imediat următoare unui `oExecute()` e restricționată.
## Vezi și
Exemplu complet aplicat: ROAAUTO, `Programe/oproceduri_autopass.prg`,
`autopass_cursor_comenzi()`/`autopass_cursor_operatii()`.

View File

@@ -0,0 +1,21 @@
# Garzi pe valori NULL (VFP)
Campurile din cursoarele intoarse de Oracle pot fi `.NULL.`. In VFP `EMPTY(.NULL.)` intoarce
`.F.`, deci o garda scrisa doar cu `EMPTY()` **nu prinde NULL**, iar concatenarea cu NULL face
tot sirul NULL (inclusiv un SQL construit prin `+`).
Forma corecta, cu tipul evaluat primul ca sa opreasca acolo:
```foxpro
If Type('tcCont') # 'C' Or Empty(Nvl(tcCont, ''))
Return
Endif
```
- `Nvl(x, '')` in interiorul lui `Empty()`, nu `Isnull(x) Or Empty(x)`.
- `TYPE()` pe o variabila cu NULL de tip caracter intoarce tot `'C'` - nu tine loc de `Nvl`.
- Acelasi tratament la orice text construit prin `+` din campuri de cursor
(SQL, mesaje, chei): un singur camp NULL anuleaza tot sirul.
Simptom tipic cand lipseste garda: `SQL statement parameter is required for non-prepared
SQLEXEC() calls` in `OEXECUTOR.OEXECUTE` - SQL-ul ajuns la `SQLEXEC` era `.NULL.`.

View File

@@ -1,64 +1,53 @@
# Convenție UX pentru formulare VFP (preferința lui Marius, valabilă pe toate proiectele ROA*)
Partajat între proiectele ROA* (similar cu `PROMPT_cautare_vfp.md`, `prompt_project_insights_docs.md`
din acest folder) — pentru că `COMUN\` e clonat/sincronizat în fiecare aplicație ROA, e locul
corect pentru o convenție de design care nu ține de un singur proiect.
Origine: confirmat de Marius pe `frm_autopass.scx` (ROAAUTO) după o rundă de regrupare vizuală
(2026-07-10) — "imi place designul acesta" pe layout-ul cu rânduri clar separate pe funcție,
butoane grupate la margini, fără elemente lipite unele de altele.
## Ce înseamnă in practică, pe proprietăți VFP
- **Fiecare grup funcțional pe rândul lui** — nu înghesui controale fără legătură directă pe
același `Top`. Ex: rândul de perioadă (date + Actualizează) separat de rândul de
statistici (Declarabile/Transmise/Blocate), separat de panoul de configurare.
- **Spațiere vizibilă între grupuri, strânsă în interiorul unui grup** — butoane din
aceeași acțiune (ex. Validează dry-run → Transmite → Renunță) la 6-10px unele de altele;
gap de 20-30px față de următorul grup funcțional (ex. Selectează tot vs. grupul
Validare/Transmitere vs. Actualizează statusuri).
- **Butoanele secundare/de configurare aliniate la marginea din dreapta a containerului**,
nu lipite imediat după textbox-ul pe care îl controlează — altfel nu se disting vizual ca
acțiune separată de câmpul de input.
- **Acțiunea principală + oprirea ei alăturate** — un buton de tip "Renunță/Oprește" trebuie
poziționat lângă acțiunea pe care o anulează (ex. Transmite + Renunță), nu împrăștiat în
altă parte a rândului.
- **Un singur rând de acțiuni cât se poate** — dacă mai multe grupuri de butoane încap pe
lățimea formei, preferă un singur rând orizontal în loc să adaugi rânduri noi dedesubt;
păstrează formele compacte pe verticală.
- **Caption-uri scurte, sentence case, nu ALL CAPS** — ex. "Transmite" nu "TRANSMITE";
"Dashboard AutoPass" nu "Deschide dashboard AUTOPASS". ALL CAPS/text lung pe un buton
citește ca zgomot, nu ca ierarhie.
- **Culoare = semnal, nu decor** — folosește culoare distinctă doar pentru acțiuni cu
semnificație clară (verde = acțiune pozitivă/transmite, roșu = oprire/pericol, albastru =
navigare/deschidere link extern); restul butoanelor rămân stilul implicit din `_baza.vcx`.
## Clase de controale (confirmat de Marius, 24.07.2026, pe frm_verif_partener_anaf ROACONT)
- **Intotdeauna controale din `_baza.vcx`, nu controale native VFP** — orice grid, label,
textbox, checkbox etc. dintr-un formular nou se bazeaza pe clasa corespunzatoare din
`COMUN\clase\_baza.vcx`, nu pe clasa nativa Visual FoxPro. Clasele din `_baza.vcx` au
fontul default **Arial 10** — nu se suprascrie FontName pe controale (explicit: fara
Arial Narrow).
- **Butoanele de inchidere/confirmare stau in bara de titlu**, din `cmd_butoane.vcx`
modelul Renunt/Termin (clasa de forma `frm_termin_renunt` din `_frm_child.vcx` le aduce
deja). Nu se dubleaza aceste actiuni cu butoane in corpul formei.
- **Actiunile care au corespondent `but_*` in `cmd_butoane.vcx`** (Nou/Adauga, Modifica,
Salveaza, Sterge, Verifica etc.) folosesc CU PREDILECTIE clasa dedicata `but_*`
respectiva — nu se improvizeaza un buton generic pentru o actiune care are deja clasa ei.
- **Doar actiunile FARA corespondent `but_*`** primesc butoane pe clasele `cmd_*` din
`cmd_butoane.vcx` (ex. `cmd_executa`) — nu clase improvizate si nu CommandButton nativ.
## Vocabular
Funcțional, compact, aerisit, minimalist, grupat, ușor de înțeles de utilizatori, aer aerisit,
modern — asta e reperul calitativ pentru orice formular nou sau refacere de layout, dincolo de
regulile mecanice de mai sus, pe orice aplicație ROA*.
## Vezi și
- `PROMPT_cautare_vfp.md` din acest folder — cum se caută/editează cod în binarele VFP text-cache
(relevant când aplici aceste reguli prin fluxul `.sc2`/`.vc2` + write-back).
- `conventie_encoding_cp1252.md` din acest folder — capcana de corupere a diacriticelor la
editarea `.sc2`/`.vc2`; relevantă ori de câte ori editezi text-cache-ul unui formular/librărie
pentru a aplica aceste reguli de UX.
# Convenție UX pentru formulare VFP (preferința lui Marius, valabilă pe toate proiectele ROA*)
Partajat între proiectele ROA* `COMUN\` e clonat/sincronizat în fiecare aplicație ROA, e locul
corect pentru o convenție de design care nu ține de un singur proiect.
## Ce înseamnă in practică, pe proprietăți VFP
- **Fiecare grup funcțional pe rândul lui**, nu înghesuit pe același `Top` cu altul fără
legătură (ex: perioadă / statistici / configurare, pe rânduri separate).
- **Spațiere vizibilă între grupuri, strânsă în interiorul unui grup** — butoane din aceeași
acțiune la 6-10px unele de altele; gap de 20-30px față de următorul grup funcțional.
- **Butoanele secundare/de configurare aliniate la marginea din dreapta a containerului**, nu
lipite imediat după textbox-ul pe care îl controlează — altfel nu se disting ca acțiune
separată de câmpul de input.
- **Acțiunea principală + oprirea ei alăturate** (ex. Transmite + Renunță), nu împrăștiate în
altă parte a rândului.
- **Un singur rând de acțiuni cât se poate** — un rând orizontal in loc de rânduri noi
dedesubt; formele rămân compacte pe verticală.
- **Caption-uri scurte, sentence case, nu ALL CAPS** — ex. "Transmite" nu "TRANSMITE". ALL
CAPS/text lung pe un buton citește ca zgomot, nu ca ierarhie.
- **Culoare = semnal, nu decor** — doar pentru acțiuni cu semnificație clară (verde =
pozitiv/transmite, roșu = oprire/pericol, albastru = navigare/link extern); restul butoanelor
rămân stilul implicit din `_baza.vcx`.
## Clase de controale (confirmat de Marius, 24.07.2026, pe frm_verif_partener_anaf ROACONT)
- **Intotdeauna controale din `_baza.vcx`, nu controale native VFP** — orice grid, label,
textbox, checkbox etc. dintr-un formular nou se bazeaza pe clasa corespunzatoare din
`COMUN\clase\_baza.vcx`, nu pe clasa nativa Visual FoxPro. Clasele din `_baza.vcx` au
fontul default **Arial 10** — nu se suprascrie FontName pe controale (explicit: fara
Arial Narrow).
- **Butoanele de inchidere/confirmare stau in bara de titlu**, din `cmd_butoane.vcx`
modelul Renunt/Termin (clasa de forma `frm_termin_renunt` din `_frm_child.vcx` le aduce
deja). Nu se dubleaza aceste actiuni cu butoane in corpul formei.
- **Actiunile care au corespondent `but_*` in `cmd_butoane.vcx`** (Nou/Adauga, Modifica,
Salveaza, Sterge, Verifica etc.) folosesc CU PREDILECTIE clasa dedicata `but_*`
respectiva — nu se improvizeaza un buton generic pentru o actiune care are deja clasa ei.
- **Doar actiunile FARA corespondent `but_*`** primesc butoane pe clasele `cmd_*` din
`cmd_butoane.vcx` (ex. `cmd_executa`) — nu clase improvizate si nu CommandButton nativ.
## Vocabular
Funcțional, compact, aerisit, minimalist, grupat, ușor de înțeles de utilizatori, modern
asta e reperul calitativ pentru orice formular nou sau refacere de layout, pe orice
aplicație ROA*.
## Vezi și
- `PROMPT_cautare_vfp.md` din acest folder — cum se caută/editează cod în binarele VFP text-cache
(relevant când aplici aceste reguli prin fluxul `.sc2`/`.vc2` + write-back).
- `conventie_encoding_cp1252.md` din acest folder — capcana de corupere a diacriticelor la
editarea `.sc2`/`.vc2`; relevantă ori de câte ori editezi text-cache-ul unui formular/librărie
pentru a aplica aceste reguli de UX.

View File

@@ -26,22 +26,20 @@ $p = Start-Process 'C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe' -
$p.WaitForExit(120000); if (!$p.HasExited) { $p.Kill() }
```
- `-A` ignora config.fpw implicit, `-T` sare peste splash; **ambele obligatorii** - fara `-T`
procesul ramane pe ecranul de intampinare (simptom identic cu o eroare de compilare).
Un `-c<cale>` explicit (lipit de flag) e preluat chiar si impreuna cu `-A`.
- **SAFETY**: sub `-A` porneste ON, deci primul `STRTOFILE` peste un log existent (sau
`COMPILE` peste un `.err`/`.fxp` existent) scoate dialogul modal "overwrite?" si procesul
pare agatat. Pune `SET SAFETY OFF` ca PRIMA linie din script si/sau `SAFETY=OFF` +
`RESOURCE=OFF` intr-un config.fpw propriu pasat cu `-c`. Verificare: logheaza
`SET("SAFETY")`/`SET("RESOURCE")` la start.
procesul ramane pe ecranul de intampinare (simptom identic cu o eroare de compilare). `-c<cale>`
explicit (lipit de flag) e preluat si cu `-A`.
- **SAFETY**: sub `-A` porneste ON - primul `STRTOFILE` peste un log existent (sau `COMPILE` peste
un `.err`/`.fxp` existent) scoate dialogul modal "overwrite?" si procesul pare agatat. Pune
`SET SAFETY OFF` ca PRIMA linie din script si/sau `SAFETY=OFF`+`RESOURCE=OFF` intr-un config.fpw
propriu pasat cu `-c`. Verificare: logheaza `SET("SAFETY")`/`SET("RESOURCE")` la start.
- In script: logare cu STRTOFILE (nu WAIT WINDOW / debugger - nu exista consola);
`ON ERROR DO <handler> WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()` care logheaza si
continua (mimeaza ErrorHandler); `QUIT` obligatoriu la final.
- `LINENO()` din handler e relativ la inceputul metodei: linia in `.vc2` = linia raportata +
linia `PROCEDURE`.
- Nu rula cu IDE-ul sau exe-ul aplicatiei deschis (lock pe binare); sterge `.fxp`-ul vechi
daca ai editat scriptul intre rulari. Daca nu-l stergi, VFP ruleaza codul vechi din `.fxp`
fara niciun semn - testul poate trece si raportul poate parea valid, desi modificarea nu a
fost executata; se prinde doar dupa ce lipseste din log o linie pe care o scrie doar codul nou.
- Nu rula cu IDE-ul sau exe-ul aplicatiei deschis (lock pe binare); sterge `.fxp`-ul vechi dupa
editarea scriptului - altfel VFP ruleaza codul vechi din `.fxp` fara niciun semn (testul poate
trece fals; se prinde doar cand lipseste din log o linie scrisa doar de codul nou).
- Forme modale: `Show(1)` blocheaza. Replica in script doar liniile relevante din Show, sau
seteaza `WindowType = 0`.
@@ -69,7 +67,7 @@ Cel mai ieftin test dupa o modificare: `COMPILE` headless, fara aplicatie si far
## 5. Bisectia versiunilor de clase (regresii)
Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN:
Cand un bug apare "de azi", compara cu clasa veche fara sa atingi SVN:
1. `git show <rev>:clase\fisier.vcx > temp\fisier.vcx` (+ `.vct`); pentru diff lizibil,
`vcx2txt.ps1 -Source temp\fisier.vcx -CacheRoot temp\txt`.
2. In harness incarca DOAR copia (`SET CLASSLIB TO temp\fisier.vcx`), **nu ADDITIVE peste cea
@@ -89,8 +87,8 @@ Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN:
pe copie crapa; recreeaza indexul dupa copiere. Acelasi lucru pentru cursorii creati intr-un
test: trebuie sa aiba EXACT indecsii pe care ii creeaza fluxul real inainte de instantiere,
altfel ordinea/logica difera si testul da rezultat fals.
- **Un grid isi pierde TOATE coloanele** (`ColumnCount` devine 0, fara eroare in log) daca un
ControlSource crapa la re-evaluare in timp ce coloanele sunt atinse programatic (ex. font per
- **Un grid isi pierde TOATE coloanele** (`ColumnCount` devine 0, fara eroare in log) daca
ControlSource crapa la re-evaluare cat timp coloanele sunt atinse programatic (ex. font per
coloana la Init). Simptome in aval: `attachtogrid` copiaza 0 coloane, apoi `calctotal` da
"Property <cColWithLabel> is not found". Similar, un cursor legat la grid recreat de Init
lasa grid-ul fara coloane (eroare 1925).
@@ -100,25 +98,24 @@ Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN:
- **Coloana de grid cu ControlSource EXPRESIE (nu camp) cere `Bound = .F.`** Fara el: eroare 9
"Data type mismatch" la `CREATEOBJECT`-ul formei (faza de constructie, raportata la linia
apelanta, Details gol).
- **Erorile de instantiere sunt raportate la linia `CREATEOBJECT`, nu la `.Init`**: daca
- **Erorile de instantiere se raporteaza la linia `CREATEOBJECT`, nu la `.Init`**: daca
`Procedure` = scriptul apelant, eroarea vine din evaluarea definitiei clasei (`ADD OBJECT ...
WITH RowSource`, ControlSource-expresie), pentru ca bind-ul controalelor native se rezolva la
WITH RowSource`, ControlSource-expresie) - bind-ul controalelor native se rezolva la
CONSTRUCTIE, inainte de `Init`.
- **Literal string > 255 caractere = eroare de COMPILARE, nu de runtime** (masurat 24.07.2026:
255 trece, 256 pica). Mesaj: `Unrecognized command verb` daca linia incepe cu un apel de
metoda, `Command contains unrecognized phrase/keyword` la o atribuire. Insidios: restul
programului ruleaza, doar linia aceea lipseste din `.fxp` si da eroare 16 cand se ajunge la
ea. De aceea SQL-ul lung se scrie cu `TEXT TO <var> [TEXTMERGE] NOSHOW ... ENDTEXT` sau
concatenat. Verificare: `awk 'length($0) > 260 {print NR": "length($0)}' fisier.prg`.
- **Linie de COD (nu doar literal string) prea lunga intr-o metoda de clasa `.vc2` poate
arunca eroarea 11 ("Function argument value, type, or count is invalid") pe PRIMA
instructiune a metodei, nu pe linia vinovata** - simptom complet derutant. Se exclude prin
diagnostic: aceeasi expresie merge normal la nivel de program, in alta clasa, intr-o
subclasa cu metoda noua, si pe instanta virgina - deci nu tine de tipul datelor, de context
sau de clasa parinte. Reper practic: linii preexistente >200 caractere intr-o clasa mare
functioneaza pana la ~250; pragul real e in jur de 255, ca la literalii de string. Remediu:
sparge expresia in pasi cu variabile locale. Verificare (comparat intre fisierul curent si
un backup anterior):
- **Literal string > 255 caractere = eroare de COMPILARE, nu runtime** (255 trece, 256 pica).
Mesaj: `Unrecognized command verb` daca linia incepe cu un apel de metoda,
`Command contains unrecognized phrase/keyword` la o atribuire. Insidios: restul programului
ruleaza, doar linia lipseste din `.fxp` si da eroare 16 cand se ajunge la ea. De aceea SQL-ul
lung se scrie cu `TEXT TO <var> [TEXTMERGE] NOSHOW ... ENDTEXT` sau concatenat. Verificare:
`awk 'length($0) > 260 {print NR": "length($0)}' fisier.prg`.
- **Linie de COD (nu doar literal string) prea lunga intr-o metoda de clasa `.vc2` poate arunca
eroarea 11 ("Function argument value, type, or count is invalid") pe PRIMA instructiune a
metodei, nu pe linia vinovata** - simptom derutant. Se exclude prin diagnostic: aceeasi
expresie merge normal la nivel de program, in alta clasa, intr-o subclasa cu metoda noua, si
pe instanta virgina - deci nu tine de tipul datelor, de context sau de clasa parinte. Reper
practic: linii preexistente >200 caractere intr-o clasa mare functioneaza pana la ~250; pragul
real e in jur de 255, ca la literalii de string. Remediu: sparge expresia in pasi cu variabile
locale. Verificare (comparat intre fisierul curent si un backup anterior):
```powershell
$l=[IO.File]::ReadAllLines($p,[Text.Encoding]::GetEncoding(28591))
for($i=0;$i -lt $l.Length;$i++){ if($l[$i].Length -gt 200){ "{0}: len={1}" -f ($i+1), $l[$i].Length } }
@@ -126,27 +123,31 @@ Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN:
- **Un UDF care citeste campul curent (`Nvl(camp,0)=1` sau similar) nu e de incredere intr-o
clauza de filtrare** (`SELECT ... WHERE`, `LOCATE FOR`, `SCAN FOR`, `DELETE FOR`) - pointerul
nu e garantat pe randul evaluat la fiecare apel, deci filtrul devine practic o valoare
constanta (fie nu se declanseaza niciodata, fie loveste tot). Simptome vazute: o comasare de
randuri care nu se mai producea deloc; un test agatat. Remediu: in clauze de filtrare
foloseste expresia INLINE pe camp (`Nvl(camp,0) <> 1`); pastreaza helper-ul doar in cod
procedural (`If`, `Replace` pe randul curent), unde pointerul e garantat pozitionat.
constanta (nu se declanseaza deloc, sau loveste tot). Simptome vazute: comasare de randuri
care nu se mai producea deloc; test agatat. Remediu: in clauze de filtrare foloseste expresia
INLINE pe camp (`Nvl(camp,0) <> 1`); pastreaza helper-ul doar in cod procedural (`If`,
`Replace` pe randul curent), unde pointerul e garantat pozitionat.
- **`SET PROCEDURE TO x.prg`**: in `.exe` se rezolva din modulele compilate (orice `.prg` din
`.pjx`), din IDE doar prin `SET PATH`. O cale lipsa din `SET PATH` se vede deci doar necompilat,
iar in `Try` trece tacut.
## 7. Capcane la SCRIEREA scriptului de test
- **`SET SAFETY OFF` in primele linii, INAINTE de orice `STRTOFILE`/`CREATE CURSOR`** (plus
`SET TALK OFF`). Fara el VFP deschide dialogul de confirmare la suprascrierea fisierului de
log, iar headless dialogul blocheaza procesul pana la timeout. Suitele existente il au deja -
capcana apare la scripturile ad-hoc, scrise repede pentru o masuratoare.
`SET TALK OFF`). Fara el VFP deschide dialogul de confirmare la suprascriere, iar headless
dialogul blocheaza procesul pana la timeout. Suitele existente il au deja - capcana apare la
scripturile ad-hoc, scrise repede pentru o masuratoare.
- **`DEFINE CLASS ... ENDDEFINE` nu poate sta la mijlocul programului principal.** Toate liniile
de DUPA `ENDDEFINE` dau "Statement is not in a procedure" (vezi `<script>.ERR`); scriptul
ruleaza doar pana acolo si se opreste silentios, fara sa ajunga la `QUIT` - simptom: vfp9.exe
pare agatat la nesfarsit. Pune orice `DEFINE CLASS` auxiliar la FINALUL fisierului.
de DUPA `ENDDEFINE` dau "Statement is not in a procedure" (vezi `<script>.ERR`); scriptul se
opreste silentios, fara sa ajunga la `QUIT` - simptom: vfp9.exe pare agatat la nesfarsit. Pune
orice `DEFINE CLASS` auxiliar la FINALUL fisierului.
- **Dummy-uri cu metode**: `CREATEOBJECT('Custom')` + `AddProperty()` adauga doar PROPRIETATI.
Daca clasa testata apeleaza `goExecutor.oExecute(...)`, dummy-ul trebuie sa fie
`DEFINE CLASS dummyexecutor AS Custom` cu `PROCEDURE oExecute` reala.
- **Diagnostic "script agatat"**, in ordine: (1) exista `<script>.ERR` langa `.prg`? => s-a
oprit la compilare; (2) CPU-ul procesului ~0 dupa cateva secunde (`Get-Process | select CPU`)
=> asteapta un dialog modal, nu proceseaza; confirma enumerand ferestrele procesului cu
=> asteapta un dialog modal; confirma enumerand ferestrele procesului cu
`EnumWindows`/`GetWindowText`/`GetWindowThreadProcessId` (`Add-Type`, user32) filtrat pe PID -
daca vezi doar fereastra principala + "Command", nu e dialog, cauta alta cauza (tipic `-T`
lipsa). Confirma mereu cauza inainte de a schimba scriptul.

View File

@@ -72,7 +72,7 @@ fals `roundtrip text1 != text2`. Ruleaza atunci cu lista rebazata:
Override-urile de metode de baza (Init, Show, hook-uri) nu au nevoie de `*m:`.
- Salvarea din VFP IDE peste un binar scris de txt2vcx poate PIERDE si definitii `*m:` deja
existente, desi corpurile PROCEDURE raman (patit pe ROAGEST: `import_adauga_factura.recalc_tva`,
`import_nota.do_adauga/do_copie/do_reface`, 07.2026); simptom: crash la Createobject cu
`import_nota.do_adauga/do_copie/do_reface`); simptom: crash la Createobject cu
"Data type mismatch" raportat la linia apelanta. Dupa orice sesiune IDE pe clasa: refresh
cache + compara lista `*m:` cu starea de dinainte.
- Nu folosi *Project > Build* ca sa recompilezi un binar vizat: rebuild-ul recompileaza toate

View File

@@ -1,65 +1,46 @@
# Flux SVN + git pentru COMUN
**SVN = șeful** (munca reală circulă prin el). **git = oglindă** pentru unelte (Claude, căutare).
git primește de la SVN, niciodată invers.
## Reguli
1. **Munca reală se comite DOAR în SVN.** Nu face `git commit` cu o modificare nouă care n-a trecut prin SVN.
2. **git se împrospătează DIN svn**, într-o singură direcție.
3. **COMUN se publică pe git dintr-UN SINGUR folder** (publisher, ex. `ROAAUTO\COMUN`). Celelalte doar se aliniază la origin.
## Lucrat în paralel în 2 proiecte (ex. roagest + roaauto), fișiere diferite
### 1. Împaci în SVN
```
# ROAGEST\COMUN
svn commit -m "modificari roagest"
# ROAAUTO\COMUN
svn update # aduce fisierele din roagest (alte fisiere -> fara conflict)
svn commit -m "modificari roaauto"
# ROAGEST\COMUN
svn update # aduce fisierele din roaauto
```
Acum ambele copii SVN au tot. E sursa de adevăr.
### 2. Oglindești în git (doar din folderul publisher)
```
cd ROAAUTO\COMUN
git add -A
git commit -m "sync svn"
git push
```
### 3. Celălalt folder: aliniere, NU commit
```
cd ROAGEST\COMUN
git fetch origin
git reset --hard origin/main
```
Sigur: fișierele sunt deja identice cu origin (le-a făcut svn), `reset` doar mută pointerul.
## Când te muți dintr-un proiect în altul
```
svn update # in proiectul unde intri
git reset --hard origin/main # in COMUN, ca git-ul sa fie curat
```
## Regula care rezumă tot
> Un singur folder publică în git (commit+push). Celelalte doar `git reset --hard origin/main`.
> Munca circulă prin SVN; git fotografiază rezultatul.
## Model de branching (git urmareste text .??2)
git urmareste versiunile text FoxBin2Prg (.vc2/.sc2/…), improspatate in-arbore cu
`git_sync.ps1` la inceput de sesiune si inainte de orice commit; nu comite cat timp
`git_sync` raporteaza esecuri (exit nenul). Doua benzi:
- **`main` = oglinda SVN**: primeste DOAR commit-uri `sync SVN rN`, facute din stare curata
(imediat dupa `svn update`, inainte de lucru local).
- **Claude lucreaza pe branch** `claude/<subiect>` si comite doar acolo;
`git diff main..claude/<subiect>` arata exact si numai munca lui.
- Dupa ce modificarile intra in SVN (`svn commit` facut de utilizator), branch-ul se inchide
(merge in `main` la urmatorul sync sau stergere).
- Igiena: sync pe `main` doar din stare curata — `svn update` in mijlocul lucrului amesteca
binarele pe disc.
# Flux SVN + git pentru COMUN
**SVN = șeful** (munca reală circulă prin el). **git = oglindă** pentru unelte (Claude, căutare).
git primește de la SVN, niciodată invers.
## Reguli
1. **Munca reală se comite DOAR în SVN.** Nu face `git commit` cu o modificare noua care n-a
trecut prin SVN.
2. **git se împrospătează DIN svn**, într-o singură direcție.
3. **COMUN se publică pe git dintr-UN SINGUR folder** (publisher, ex. `ROAAUTO\COMUN`). Celelalte
doar se aliniază la origin.
## Lucrat în paralel în 2 proiecte (ex. roagest + roaauto), fișiere diferite
1. **Împaci în SVN**: `svn commit` in ROAGEST\COMUN -> `svn update` in ROAAUTO\COMUN (aduce
fisierele din roagest, fara conflict pe fisiere diferite) -> `svn commit` acolo -> `svn update`
inapoi in ROAGEST\COMUN. Acum ambele copii SVN au tot — e sursa de adevăr.
2. **Oglindești în git, doar din folderul publisher**: `git add -A` + `git commit` + `git push`
in ROAAUTO\COMUN.
3. **Celălalt folder: aliniere, NU commit** — in ROAGEST\COMUN: `git fetch origin` +
`git reset --hard origin/main`. Sigur: fișierele sunt deja identice cu origin (le-a făcut svn),
`reset` doar mută pointerul.
Când te muți dintr-un proiect în altul: `svn update` in proiectul unde intri, apoi
`git reset --hard origin/main` in COMUN, ca git-ul sa fie curat.
## Regula care rezumă tot
> Un singur folder publică în git (commit+push). Celelalte doar `git reset --hard origin/main`.
> Munca circulă prin SVN; git fotografiază rezultatul.
## Model de branching (git urmareste text .??2)
git urmareste versiunile text FoxBin2Prg (.vc2/.sc2/…), improspatate in-arbore cu `git_sync.ps1`
la inceput de sesiune si inainte de orice commit; nu comite cat timp `git_sync` raporteaza esecuri
(exit nenul). Doua benzi:
- **`main` = oglinda SVN**: primeste DOAR commit-uri `sync SVN rN`, facute din stare curata
(imediat dupa `svn update`, inainte de lucru local).
- **Claude lucreaza pe branch** `claude/<subiect>` si comite doar acolo;
`git diff main..claude/<subiect>` arata exact si numai munca lui.
- Dupa ce modificarile intra in SVN (`svn commit` facut de utilizator), branch-ul se inchide
(merge in `main` la urmatorul sync sau stergere).
- Igiena: sync pe `main` doar din stare curata — `svn update` in mijlocul lucrului amesteca
binarele pe disc.

View File

@@ -1,48 +1,46 @@
# Inrolarea unui proiect ROA (Visual FoxPro) in fluxul git-text FoxBin2Prg
Instructiuni pas cu pas pentru o sesiune Claude Code care inroleaza un proiect ROA
in fluxul in care git urmareste DOAR versiunile text FoxBin2Prg (.vc2/.sc2/.fr2/.mn2/
.lb2/.pj2/.dc2/.db2) generate in arbore, langa binarele VFP. SVN ramane sursa de
adevar si nu se atinge (niciun svn commit fara acordul explicit al utilizatorului).
Pasi pentru o sesiune Claude Code care inroleaza un proiect ROA in fluxul in care git urmareste
DOAR versiunile text FoxBin2Prg (.vc2/.sc2/.fr2/.mn2/.lb2/.pj2/.dc2/.db2) generate in arbore,
langa binarele VFP. SVN ramane sursa de adevar si nu se atinge (niciun svn commit fara acordul
explicit al utilizatorului).
Proiecte deja inrolate (16.07.2026): ROACONT, ROAGEST, ROAAUTO, ROAIMOB, ROAACNPRO,
ROAFACTURARE + COMUN (romfast/comun.git). Modelul de referinta este ROACONT.
Proiecte deja inrolate: ROACONT, ROAGEST, ROAAUTO, ROAIMOB, ROAACNPRO, ROAFACTURARE + COMUN
(romfast/comun.git). Modelul de referinta e ROACONT.
## Reguli pentru sesiunea care executa
- Foloseste EXCLUSIV PowerShell pentru comenzi (NU tool-ul Bash — bash.exe crapa pe
aceste masini si lasa stackdump-uri).
- NU face niciun `svn commit`. NU modifica binarele VFP. La final binarele trebuie sa
fie byte-identice (verificabil cu `svn status`: niciun binar M).
- Rularile de conversie dureaza zeci de minute pe proiecte mari: sunt incrementale,
daca expira timeout-ul tool-ului se reiau pana la capat.
- Foloseste EXCLUSIV PowerShell (NU Bash — bash.exe crapa pe aceste masini si lasa stackdump-uri).
- NU face niciun `svn commit`. NU modifica binarele VFP. La final binarele trebuie sa fie
byte-identice (`svn status`: niciun binar M).
- Rularile de conversie dureaza zeci de minute pe proiecte mari: sunt incrementale, daca expira
timeout-ul tool-ului se reiau pana la capat.
- Nu rula doua conversii git_sync in paralel pe acelasi arbore.
## Preconditii
1. Tooling-ul partajat exista in `D:\ROA\UTIL\foxbin2prg\`: `git_sync.ps1`,
`vfp_filemap.ps1`, `txt2vcx.ps1`, `test_git_sync.ps1`,
`test_roundtrip.ps1`. Citeste-le inainte (macar help-ul din git_sync.ps1).
`roa_sync.ps1` (+ `test_roa_sync.ps1`) traieste in `COMUN\scripts\` si vine
singur cu svn update; in foxbin2prg a ramas doar un stub de compatibilitate.
2. Proiectul e working copy SVN valid (`svn info D:\ROA\<PROIECT>`), cu `COMUN\`
inauntru (external SVN).
3. Repo-ul gitea exista: `git ls-remote git@gitea.romfast.ro:romfast/<proiect>.git`.
Daca nu exista, cere utilizatorului sa-l creeze din interfata gitea (NU crea
repo-uri prin API din proprie initiativa).
4. SVN global-ignores pe masina contine `*.vc2 *.sc2 *.fr2 *.mn2 *.lb2 *.pj2 *.dc2
*.db2 *.dbf.cfg` (in `%APPDATA%\Subversion\config`, sectiunea [miscellany]).
Fara asta, textele apar ca `?` in svn status si risca svn add accidental.
5. Daca proiectul ARE deja git cu istoric si urmeaza reset: confirmarea utilizatorului
ca nu exista clone active pe alte masini (force-push rescrie istoria).
1. Tooling partajat in `D:\ROA\UTIL\foxbin2prg\`: `git_sync.ps1`, `vfp_filemap.ps1`,
`txt2vcx.ps1`, `test_git_sync.ps1`, `test_roundtrip.ps1`. Citeste-le inainte (macar help-ul
din git_sync.ps1). `roa_sync.ps1` (+ `test_roa_sync.ps1`) traieste in `COMUN\scripts\` si
vine singur cu svn update; in foxbin2prg a ramas doar un stub de compatibilitate.
2. Proiectul e working copy SVN valid (`svn info D:\ROA\<PROIECT>`), cu `COMUN\` inauntru
(external SVN).
3. Repo-ul gitea exista: `git ls-remote git@gitea.romfast.ro:romfast/<proiect>.git`. Daca nu
exista, cere utilizatorului sa-l creeze din interfata gitea (NU crea repo-uri prin API din
proprie initiativa).
4. SVN global-ignores pe masina contine `*.vc2 *.sc2 *.fr2 *.mn2 *.lb2 *.pj2 *.dc2 *.db2
*.dbf.cfg` (in `%APPDATA%\Subversion\config`, sectiunea [miscellany]). Fara asta, textele apar
ca `?` in svn status si risca svn add accidental.
5. Daca proiectul ARE deja git cu istoric si urmeaza reset: confirmarea utilizatorului ca nu
exista clone active pe alte masini (force-push rescrie istoria).
## Pasi
### 1. Inventar prealabil (inainte de orice stergere)
- Exista `.git`? Noteaza `git remote -v` si branch-ul. Exista `COMUN\.git`?
- `git ls-files *.dbf` (daca exista repo vechi): tabelele urmarite azi ca binare sunt
candidate la conversie .db2 (cerinta: tot ce e convertibil trece pe text).
- `git ls-files *.dbf` (daca exista repo vechi): tabelele urmarite azi ca binare sunt candidate
la conversie .db2 (cerinta: tot ce e convertibil trece pe text).
### 2. Conversia completa
@@ -50,25 +48,25 @@ ROAFACTURARE + COMUN (romfast/comun.git). Modelul de referinta este ROACONT.
& D:\ROA\UTIL\foxbin2prg\git_sync.ps1 -ProjectRoot D:\ROA\<PROIECT>
```
- DbfList implicit acopera `Locale\locale*.dbf`, `Help\*.dbf`, `DATE\Optiuni_*.dbf`
si toate dbf-urile COMUN. Tabele de configurare specifice proiectului se adauga cu
`-DbfList` explicit (ATENTIE: parametrii array NU se pot pasa prin
`powershell -File` — invoca scriptul in-process cu `&`, altfel array-ul se
colapseaza). Tabele operationale mari nu se adauga; un .db2 peste 5 MB ramane binar.
- DbfList implicit acopera `Locale\locale*.dbf`, `Help\*.dbf`, `DATE\Optiuni_*.dbf` si toate
dbf-urile COMUN. Tabele de configurare specifice proiectului se adauga cu `-DbfList` explicit
(ATENTIE: parametrii array NU se pot pasa prin `powershell -File` — invoca scriptul in-process
cu `&`, altfel array-ul se colapseaza). Tabele operationale mari nu se adauga; un .db2 peste
5 MB ramane binar.
- Esecuri de conversie — se investigheaza fiecare:
- meniuri pre-VFP9 ("NOT in VFP 9 Format"): raman binare, cu exceptii negate `!` in
.gitignore; intra in flux doar dupa re-salvare in VFP9 (MODIFY MENU -> save);
- clase FFC/third-party cu roundtrip fals-negativ (#INCLUDE lipsa in staging izolat,
ex. cele 6 din COMUN deja scutite implicit): se adauga la `-RoundtripExempt`;
- clase FFC/third-party cu roundtrip fals-negativ (#INCLUDE lipsa in staging izolat, ex. cele
6 din COMUN deja scutite implicit): se adauga la `-RoundtripExempt`;
- alte esecuri reale: fisierul ramane binar urmarit (exceptie `!`) si se raporteaza.
- Regula: nu se trece mai departe cu esecuri neexplicate (exit code nenul).
### 3. .gitignore si .gitattributes
- Copiaza `D:\ROA\ROACONT\.gitignore` ca model si adapteaza: sectiunea machine-local
(exe-ul proiectului, <proiect>_ref.DBF/FPT/CDX, FOXUSER, .ini/.ARM, log-uri) si
sectiunea dbf: fiecare .dbf care are .db2 se ignora INDIVIDUAL (plus .fpt-ul lui).
NU ignora: `*.??2`, `*.dbf.cfg`, grafica (bmp/ico/jpg/png), ocx, tmpl.
- Copiaza `D:\ROA\ROACONT\.gitignore` ca model si adapteaza: sectiunea machine-local (exe-ul
proiectului, <proiect>_ref.DBF/FPT/CDX, FOXUSER, .ini/.ARM, log-uri) si sectiunea dbf: fiecare
.dbf care are .db2 se ignora INDIVIDUAL (plus .fpt-ul lui). NU ignora: `*.??2`, `*.dbf.cfg`,
grafica (bmp/ico/jpg/png), ocx, tmpl.
- `.gitattributes` cu `* -text` (SVN ramane autoritatea EOL; git nu normalizeaza).
### 4. Init/reset repo proiect
@@ -81,13 +79,12 @@ git -C D:\ROA\<PROIECT> add -A
```
VERIFICARE OBLIGATORIE inainte de commit (`git ls-files` pe staged):
- 0 binare convertibile urmarite (vcx/vct/scx/sct/frx/frt/mnx/mnt/lbx/lbt/pjx/pjt/
dbc/dct/cdx/dcx), cu exceptia celor cu `!` justificate;
- 0 binare convertibile urmarite (vcx/vct/scx/sct/frx/frt/mnx/mnt/lbx/lbt/pjx/pjt/dbc/dct/cdx/dcx),
cu exceptia celor cu `!` justificate;
- textele .??2 prezente; 0 fisiere din COMUN/ (are repo-ul lui).
Commit: `Initial: flux text FoxBin2Prg (git urmareste .??2 in-arbore, binarele VFP
git-ignored)` + linia Co-Authored-By a sesiunii. Push: `git push -u origin main`
(`--force` doar la reset).
Commit: `Initial: flux text FoxBin2Prg (git urmareste .??2 in-arbore, binarele VFP git-ignored)`
+ linia Co-Authored-By a sesiunii. Push: `git push -u origin main` (`--force` doar la reset).
### 5. Clona COMUN a proiectului
@@ -100,35 +97,34 @@ git -C D:\ROA\<PROIECT>\COMUN reset origin/main # mixed: pastreaza disc
git -C D:\ROA\<PROIECT>\COMUN checkout origin/main -- .gitignore
```
Diferentele ramase in `git status` = revizii SVN diferite ale clonei (normal).
NU comite nimic in comun.git dintr-o clona decalata — comun se comite doar din clona
in care s-a lucrat efectiv, dupa svn update.
Diferentele ramase in `git status` = revizii SVN diferite ale clonei (normal). NU comite nimic in
comun.git dintr-o clona decalata — comun se comite doar din clona in care s-a lucrat efectiv,
dupa svn update.
### 6. roa_sync.bat
Copiaza `D:\ROA\ROAFACTURARE\roa_sync.bat` in radacina proiectului (e generic,
foloseste `%~dp0` si cheama `COMUN\scripts\roa_sync.ps1`) si include-l in commit.
Utilizatorul il ruleaza la inceput de sesiune: svn update -> git_sync -> commit
"sync SVN rN" pe main (proiect + COMUN) -> reconciliere cu origin + push (doar
commit-uri de sync) -> inchide branch-urile claude/* cu diff gol.
Copiaza `D:\ROA\ROAFACTURARE\roa_sync.bat` in radacina proiectului (generic, foloseste `%~dp0` si
cheama `COMUN\scripts\roa_sync.ps1`) si include-l in commit. Utilizatorul il ruleaza la inceput de
sesiune: svn update -> git_sync -> commit "sync SVN rN" pe main (proiect + COMUN) -> reconciliere
cu origin + push (doar commit-uri de sync) -> inchide branch-urile claude/* cu diff gol.
### 7. Verificari finale
- Acoperire: fiecare binar convertibil din arbore (inclusiv COMUN) are text .??2
langa el (exceptiile `!` enumerate si justificate).
- Acoperire: fiecare binar convertibil din arbore (inclusiv COMUN) are text .??2 langa el
(exceptiile `!` enumerate si justificate).
- `svn status`: niciun binar modificat, niciun .??2 adaugat in SVN.
- `git ls-remote origin main` = HEAD-ul local.
- Raport final: numar texte per tip, esecuri/scutiri, commit hash, push status.
## Note operationale
- Dialogurile modale FoxBin2Prg sunt suprimate de scripturi printr-un `foxbin2prg.cfg`
cu `DontShowErrors: 1` scris per-director de staging (cfg-ul global de langa exe NU
e fiabil). Daca utilizatorul vede totusi un MessageBox, e un dialog nativ VFP —
watchdog-ul din Invoke-FoxBin2PrgSafe il omoara la timeout.
- Dialogurile modale FoxBin2Prg sunt suprimate de scripturi printr-un `foxbin2prg.cfg` cu
`DontShowErrors: 1` scris per-director de staging (cfg-ul global de langa exe NU e fiabil).
Daca utilizatorul vede totusi un MessageBox, e un dialog nativ VFP — watchdog-ul din
Invoke-FoxBin2PrgSafe il omoara la timeout.
- Tabelele legate de un DBC au nevoie de .dbc/.dct/.dcx si .cdx langa ele la conversie
(git_sync face asta automat in staging).
- `DBF_Conversion_Support: 4` (scris de git_sync in cfg-ul de staging) exporta DATELE
in .db2, nu doar structura.
- Fisierele doar-git (docs, .bat, .gitignore) se comit separat, inainte de sync-ul
"sync SVN rN", altfel nimeresc in commit-ul de sincronizare.
- `DBF_Conversion_Support: 4` (scris de git_sync in cfg-ul de staging) exporta DATELE in .db2, nu
doar structura.
- Fisierele doar-git (docs, .bat, .gitignore) se comit separat, inainte de sync-ul "sync SVN rN",
altfel nimeresc in commit-ul de sincronizare.

View File

@@ -1,9 +1,8 @@
# Inventar COMUN - functii/clase reutilizabile (ROAGEST)
Scop: referinta rapida pt. plan/code-review, ca sa refoloseasca comunele in loc sa se reinventeze
(ex: Scan manual pt. lista dintr-un cursor, cand exista deja cursor2lista()). Generat prin grep pe
COMUN/programe/*.prg + cache text D:\ROA\_vfp_textcache\roagest (nu presupuneri). Numerele = nr.
aparitii grep in tot proiectul (indiciu de cat de "canonic" e functia).
Scop: reutilizare comune la plan/code-review (ex. cursor2lista() in loc de Scan manual pe cursor).
Generat prin grep pe COMUN/programe/*.prg + cache text D:\ROA\_vfp_textcache\roagest. Numerele =
nr. aparitii grep in proiect (indiciu cat de "canonic" e functia).
## 1. Functii comune - COMUN\programe\oproceduri_comune.prg (clasa Oracle/executor + utilitare)
@@ -90,14 +89,14 @@ aparitii grep in tot proiectul (indiciu de cat de "canonic" e functia).
| GetUserDocPath | - | folder documente utilizator curent | - |
| aleg_document_pereche | (vezi ooperatii_comune) | vezi sectiune 2 | - |
Nota: multe din functiile de mai sus exista **dublat** in `proceduri_comune.prg` (varianta veche,
Nota: multe functii de mai sus exista **dublat** in `proceduri_comune.prg` (varianta veche,
non-obiect) - ex. NEW_ID, SAVE_GRID*, XMENU, cursor2lista*, lista2array/cursor, get_mask, Get_Version,
Get_Hexa, format_msg, C_LUNA/cluna, get_trimestru/semestru, GETCALLSTACK, CloneObj/CopyProps,
ceretitlu_rap. La duplicat castiga fisierul adaugat **cel mai recent** cu SET PROCEDURE ADDITIVE -
in roagest.prg OPROCEDURI_COMUNE.PRG (linia 238) vine dupa proceduri_comune (linia 218), deci
varianta activa e cea din `oproceduri_comune.prg`. Din varianta veche raman folosite doar 2 functii
unice: `extrage_optiuni(cLista,nId)` (valoare dintr-o lista "id::val;id::val", 11 uz) si
`myScatter(tcBlank)` (SCATTER generic in obiect, 3 uz); restul functiilor unice de acolo = moarte.
ceretitlu_rap. La duplicat castiga fisierul incarcat **cel mai recent** cu SET PROCEDURE ADDITIVE -
in roagest.prg OPROCEDURI_COMUNE.PRG (linia 238) vine dupa proceduri_comune (linia 218), deci activa
e varianta din `oproceduri_comune.prg`. Unice din varianta veche: `extrage_optiuni(cLista,nId)`
(valoare din lista "id::val;id::val", 11 uz), `myScatter(tcBlank)` (SCATTER generic in obiect, 3 uz);
restul functiilor unice de acolo = moarte.
## 2. Functii comune - COMUN\programe\ooperatii_comune.prg (contabilitate/analitice/balanta)
@@ -142,12 +141,12 @@ Preview rapoarte: FoxyPreviewer (`gcReportPreviewer = "FoxyPreview"` in roagest.
| PreviewerConfig (clasa) | SetValue/GetValue | property-bag optiuni FoxyPreviewer (param toPreviewerConfig la export2frx) | - |
### Export Excel - 3 mecanisme paralele (atentie la confuzii)
1. `goExport.export2xls/export2xlsx` (mai sus) - preferat pt. cod nou (export2xlsx).
1. `goExport.export2xls/export2xlsx` (mai sus) - preferat pt. cod nou.
2. `export_excel` / `export_excel_grid` / `exportare` / `LIST_EXCEL` (proceduri_excel.prg) - OLE
Automation, scrie celula cu celula, necesita Excel instalat; uz mic (2-12). `get_excel_mask` de
acolo = conversie masca VFP -> format Excel (nu confunda cu `get_mask` din sect. 1).
Automation celula-cu-celula, cere Excel instalat; uz mic (2-12). `get_excel_mask` acolo =
masca VFP -> format Excel (nu confunda cu `get_mask` din sect. 1).
3. Clasa `excelxml` (excelxml.vcx, COMUN\UTILE\excel) - Excel XML direct din `gridobject`, fara
Excel instalat (proprietati: file, sheetname, openaftersaving; metoda `save`); 73 uz.
Excel instalat (proprietati file/sheetname/openaftersaving, metoda `save`); 73 uz.
Plus functiile libere `export_xls`/`ExportToXMLExcel` din oproceduri_comune.prg (sect. 1) - cod
diferit de metoda `goExport.export_xls`, doar nume identic.
@@ -288,28 +287,28 @@ Proprietate cheie comuna: `pcobj` (leaga containerul de camp/proprietate din obi
## 7. Ce am lasat pe dinafara (intentionat)
- `proceduri_comune.prg` (varianta veche) - acoperita acum in nota de la sect. 1 (2 functii unice
folosite, restul dublate sau moarte); functiile ei unice cu 0 aparitii (caut_nume_politica,
- `proceduri_comune.prg` (varianta veche) - acoperita in nota sect. 1 (2 functii unice folosite,
restul dublate/moarte); functiile ei unice cu 0 aparitii (caut_nume_politica,
make_sectii_utilizator, recompune_optiuni, cere*/compara*, debug_*_eventtracking, ...) - omise.
- `oproceduri_comune_imob.prg` - varianta specifica ROAIMOB, nu ROAGEST.
- `xdate.prg` - script procedural (incarca cursoarele xsets/xrequest/xnote la DO), nu expune functii.
- Metoda `getUserRepPath` din oExportConfig - complet comentata (moarta); varianta activa e functia
libera omonima din `proceduri_rapoarte.prg` (cod diferit).
- Clase de nomenclatoare mari (`onomenclatoare.vcx`, `onom_articole.vcx`, `stocuri.vcx`, `rulaje.vcx`,
`ointroduceri*.vcx`, `oinventar.vcx`) - business logic specific gestiune, prea voluminos pt. acest
inventar (candidat pt. un inventar separat, per-flux, daca devine necesar).
`ointroduceri*.vcx`, `oinventar.vcx`) - business logic gestiune, prea voluminos pt. acest inventar
(candidat pt. inventar separat per-flux, daca devine necesar).
- Clasele de configurare/serii (`configurare.vcx`, `serii_numere.vcx`, `ferestre_oracle.vcx`,
`bon_fisc.vcx`) si utilitarele (`GridExtras`, `ctl32`, `hpdf`) - neinventariate, uz mai rar
in fluxurile curente de lucru (`excelxml.vcx` e acoperita la sect. 3).
- Functiile din `COMUN\programe` fara nicio aparitie gasita prin grep in ROAGEST (posibil folosite
doar de alte aplicatii ROA) - omise.
`bon_fisc.vcx`) si utilitarele (`GridExtras`, `ctl32`, `hpdf`) - neinventariate, uz rar in
fluxurile curente (`excelxml.vcx` e acoperita la sect. 3).
- Functiile din `COMUN\programe` fara nicio aparitie prin grep in ROAGEST (posibil doar alte
aplicatii ROA) - omise.
## 8. Cum se foloseste
- **La plan**: inainte de a scrie cod/obiecte noi, scaneaza acest fisier + un grep tintit
- **La plan**: inainte de cod/obiecte noi, scaneaza acest fisier + un grep tintit
(`grep -rn "<nume_functie_candidata>" COMUN/programe D:\ROA\_vfp_textcache\roagest`) ca sa
confirmi ca nu exista deja o comuna echivalenta.
- **La code-review**: daca un diff introduce Scan manual pt. liste, MESSAGEBOX direct, SQLEXEC direct,
un buton cu Click suprascris in loc de `caction`, un export Excel/listare construite manual in loc
de `goExport.export2*`/FoxyPreview, sau un dialog de alegere nomenclator facut din SELECT+grid in
loc de `caut_*` (ocautare.prg), semnaleaza reutilizarea comunei corespunzatoare din tabelele de mai sus.
- **La code-review**: daca un diff introduce Scan manual pt. liste, MESSAGEBOX direct, SQLEXEC
direct, un buton cu Click suprascris in loc de `caction`, export Excel/listare construite manual
in loc de `goExport.export2*`/FoxyPreview, sau un dialog de alegere nomenclator din SELECT+grid
in loc de `caut_*` (ocautare.prg), semnaleaza comuna corespunzatoare din tabelele de mai sus.

View File

@@ -0,0 +1,42 @@
# Hook-uri de disciplina (regulile 9 si 12)
## Monitorizare context sesiune (regula 9)
Agentul nu-si vede singur consumul de context. `COMUN\utile\context_watch.ps1` il citeste din
transcriptul sesiunii (ultimul `usage`: `input_tokens + cache_read + cache_creation`) si avertizeaza
peste prag: 250k = pregateste predarea, 275k = handoff acum.
Instalare, o data per calculator, in `%USERPROFILE%\.claude\settings.json` (nivel utilizator, prinde
toate proiectele):
```json
"hooks": {
"UserPromptSubmit": [
{ "hooks": [ { "type": "command",
"command": "powershell -NoProfile -ExecutionPolicy Bypass -File \"D:\\ROA\\ROAGEST\\COMUN\\utile\\context_watch.ps1\" -Stdout" } ] }
]
}
```
- Ruleaza la fiecare mesaj al utilizatorului (~1s); sub prag nu scrie nimic.
- `-Stdout` e obligatoriu pe `UserPromptSubmit` (mesajul intra in context, exit 0). Fara el scrie pe
stderr si iese cu 2 - forma pentru `PostToolUse`.
- Praguri configurabile: `-Prag`, `-PragMax`.
- Verificare manuala: `powershell -File ...\context_watch.ps1 -Prag 900000 -PragMax 950000 -Intotdeauna`
(afiseaza `CONTEXT <n>k` indiferent de prag).
## Revizuire periodica a docs (regula 12)
`COMUN\utile\docs_revizie_check.ps1` compara data din markerul `COMUN\docs\.ultima_revizie` cu ziua
curenta si, peste 30 de zile, cere o runda de compactare. Se pune ca hook `SessionStart`, in acelasi
`settings.json`, cu `-Stdout`:
```json
"SessionStart": [
{ "hooks": [ { "type": "command",
"command": "powershell -NoProfile -ExecutionPolicy Bypass -File \"D:\\ROA\\ROAGEST\\COMUN\\utile\\docs_revizie_check.ps1\" -Stdout" } ] }
]
```
Dupa o revizie aplicata: `powershell -File ...\docs_revizie_check.ps1 -Marcheaza` (rescrie markerul).
Interval configurabil cu `-Zile`.

View File

@@ -1,61 +1,61 @@
# Export surse Oracle (PACK_CONTAFIN & co.) — cum se face
`PACK_CONTAFIN.pck` din acest folder este exportul sursei pachetului PL/SQL `PACK_CONTAFIN`.
**Claude Code își face singur exportul/reîmprospătarea** — nu mai e nevoie de export manual din
PL/SQL Developer.
## Conexiune
- Client: `D:\ROA\instantclient_19_18\sqlplus.exe` (`TNS_ADMIN` e deja setat spre același folder).
- Alias TNS: `ROA_CENTRAL``10.0.20.121:1521`, `SERVICE_NAME=ROA` (vezi `tnsnames.ora`).
- Schema/utilizator: `MARIUSM_AUTO` (schema de dezvoltare a lui Marius).
- **Parola nu e versionată** — se află local, în `D:\ROA\ROAGEST\docs\local\oracle.md`
(folder ignorat de git), pe mașina de lucru.
`PACK_CONTAFIN` există în schemele `MARIUSM_AUTO` (dev) și `ACN`, plus un sinonim `PUBLIC`.
Exportul de referință se face din `MARIUSM_AUTO`.
## Gotcha sqlplus pe Windows/PowerShell
Nu trimite SQL prin pipe din PowerShell (`'select...' | sqlplus`) — BOM-ul UTF-16 sparge parserul
(`SP2-0734: unknown command beginning "select..."`). Scrie un fișier `.sql` cu encoding **ASCII**
și rulează-l cu `@fisier.sql`.
## Comanda de export (re-generare .pck)
```sql
-- export_pack.sql
set pagesize 0 linesize 400 trimspool on feedback off heading off termout off
spool D:\ROA\ROAGEST\COMUN\docs\PACK_CONTAFIN.pck
select text from all_source where owner='MARIUSM_AUTO' and name='PACK_CONTAFIN' and type='PACKAGE' order by line;
select '/' from dual;
select text from all_source where owner='MARIUSM_AUTO' and name='PACK_CONTAFIN' and type='PACKAGE BODY' order by line;
select '/' from dual;
spool off
exit
```
```powershell
& 'D:\ROA\instantclient_19_18\sqlplus.exe' -L -S 'MARIUSM_AUTO/<parola>@ROA_CENTRAL' '@export_pack.sql'
```
Același tipar merge pentru orice alt pachet/procedură (`PACK_SESIUNE`, `PACK_PRETURI`, …) sau pentru
DDL de tabele/view-uri (`all_tab_columns`, `dbms_metadata.get_ddl`).
## Ce e strict necesar de știut despre PACK_CONTAFIN
Pachetul central de **scriere a documentelor** — clientul VFP populează tabelele temporare
`ACT_TEMP`/`RUL_TEMP` (prin `oscrie_in_fisiere`-ul din COMUN), apoi pachetul distribuie:
- `SCRIE_IN_FISIERE` — orchestratorul (apelat per document).
- `SCRIE_IN_ACT``ACT_TEMP``ACT` (notele contabile).
- `SCRIE_IN_RUL``RUL_TEMP``RUL` (mișcările de stoc); completează `COD`, `DATAORA`, `ID_FACT`
(min. `id_fact` fără conturi 5xx), `ID_SUCURSALA`, `DATAIN`/`DATAOUT` din `dataact`, opțional
`ID_RUL_AUX` pe furnizor (opțiunea de firmă `RULAJFURNIZOR`). **Scrie exact ce e în RUL_TEMP — nu
derivă rulaje din ACT**, deci filtrarea liniilor de rulaj se face în clientul VFP.
- `SCRIE_IN_RUL_OBINV` / `SCRIE_IN_STOC` / `SCRIE_IN_STOC_OBINV` — variantele pentru obiecte de
inventar și actualizarea stocului.
- `VERIFICA_NOTE_CONTABILE`, `SCRIE_JC_2007`/`SCRIE_JV_2007` (jurnale TVA),
`SCRIE_IN_BALANTA(_PARTENERI)`, `sterge_document`, `finalizeaza_document_*`.
- Stare de sesiune prin settere/gettere (`SET_COD`/`GET_COD`, `SET_IDFACT`, `SET_ID_SUCURSALA`, …)
+ `PACK_SESIUNE` (an/lună, opțiuni firmă).
# Export surse Oracle (PACK_CONTAFIN & co.) — cum se face
`PACK_CONTAFIN.pck` din acest folder este exportul sursei pachetului PL/SQL `PACK_CONTAFIN`.
Claude Code își face singur exportul/reîmprospătarea — nu mai e nevoie de export manual din
PL/SQL Developer.
## Conexiune
- Client: `D:\ROA\instantclient_19_18\sqlplus.exe` (`TNS_ADMIN` deja setat spre același folder).
- Alias TNS: `ROA_CENTRAL``10.0.20.121:1521`, `SERVICE_NAME=ROA` (vezi `tnsnames.ora`).
- Schema/utilizator: `MARIUSM_AUTO` (schema de dezvoltare a lui Marius).
- **Schema de lucru pentru verificari: `MARIUSM_AUTO` pe `ROA_CENTRAL`** - nu `ACN` sau altele.
- **Parola nu e versionată** — local, în `D:\ROA\ROAGEST\docs\local\oracle.md` (ignorat de git).
`PACK_CONTAFIN` există în schemele `MARIUSM_AUTO` (dev) și `ACN`, plus sinonim `PUBLIC`.
Exportul de referință se face din `MARIUSM_AUTO`.
## Gotcha sqlplus pe Windows/PowerShell
Nu trimite SQL prin pipe din PowerShell (`'select...' | sqlplus`) — BOM-ul UTF-16 sparge parserul
(`SP2-0734: unknown command beginning "select..."`). Scrie un fișier `.sql` cu encoding **ASCII**
și rulează-l cu `@fisier.sql`.
## Comanda de export (re-generare .pck)
```sql
-- export_pack.sql
set pagesize 0 linesize 400 trimspool on feedback off heading off termout off
spool D:\ROA\ROAGEST\COMUN\docs\PACK_CONTAFIN.pck
select text from all_source where owner='MARIUSM_AUTO' and name='PACK_CONTAFIN' and type='PACKAGE' order by line;
select '/' from dual;
select text from all_source where owner='MARIUSM_AUTO' and name='PACK_CONTAFIN' and type='PACKAGE BODY' order by line;
select '/' from dual;
spool off
exit
```
```powershell
& 'D:\ROA\instantclient_19_18\sqlplus.exe' -L -S 'MARIUSM_AUTO/<parola>@ROA_CENTRAL' '@export_pack.sql'
```
Același tipar merge pentru orice alt pachet/procedură (`PACK_SESIUNE`, `PACK_PRETURI`, …) sau
pentru DDL de tabele/view-uri (`all_tab_columns`, `dbms_metadata.get_ddl`).
## Ce e strict necesar de știut despre PACK_CONTAFIN
Pachetul central de **scriere a documentelor** — clientul VFP populează tabelele temporare
`ACT_TEMP`/`RUL_TEMP` (prin `oscrie_in_fisiere`-ul din COMUN), apoi pachetul distribuie:
- `SCRIE_IN_FISIERE` — orchestratorul (apelat per document).
- `SCRIE_IN_ACT``ACT_TEMP``ACT` (notele contabile).
- `SCRIE_IN_RUL``RUL_TEMP``RUL` (mișcările de stoc); completează `COD`, `DATAORA`, `ID_FACT`
(min. `id_fact` fără conturi 5xx), `ID_SUCURSALA`, `DATAIN`/`DATAOUT` din `dataact`, opțional
`ID_RUL_AUX` pe furnizor (opțiunea de firmă `RULAJFURNIZOR`). **Scrie exact ce e în RUL_TEMP — nu
derivă rulaje din ACT**, deci filtrarea liniilor de rulaj se face în clientul VFP.
- `SCRIE_IN_RUL_OBINV` / `SCRIE_IN_STOC` / `SCRIE_IN_STOC_OBINV` — variantele pentru obiecte de
inventar și actualizarea stocului.
- `VERIFICA_NOTE_CONTABILE`, `SCRIE_JC_2007`/`SCRIE_JV_2007` (jurnale TVA),
`SCRIE_IN_BALANTA(_PARTENERI)`, `sterge_document`, `finalizeaza_document_*`.
- Stare de sesiune prin settere/gettere (`SET_COD`/`GET_COD`, `SET_IDFACT`, `SET_ID_SUCURSALA`, …)
+ `PACK_SESIUNE` (an/lună, opțiuni firmă).

View File

@@ -1,8 +1,8 @@
# Orchestrare cu subagenti: context mic, misiuni descompuse
Regula (valabila in toate proiectele ROA/VFP): un singur subagent care duce o misiune lunga
(iteratii de teste, investigatii, mai multe sarcini inlantuite) acumuleaza context urias
(s-a ajuns la ~800k tokens) — calitate degradata, cost mare. Nu se lucreaza asa.
(iteratii de teste, investigatii, mai multe sarcini inlantuite) acumuleaza context urias
calitate degradata, cost mare. Nu se lucreaza asa.
## Cum se lucreaza
@@ -42,11 +42,10 @@ Regula (valabila in toate proiectele ROA/VFP): un singur subagent care duce o mi
## Disciplina de context a ORCHESTRATORULUI
Pragul de ~200-250k e pentru subagenti, dar orchestratorul se umple la fel de repede daca isi
lasa in sesiune munca de CITIT. Masurat pe o runda reala (implementare + 4 rulari ale unei suite
de 25 de teste): sesiunea principala a ajuns la ~570k desi tot codul fusese scris de subagenti.
Consumul, in ordinea marimii: (1) citirea rezultatelor de test dupa fiecare test terminat, cu tot
cu liniile "OK"; (2) citirea codului ca sa diagnosticheze esecurile; (3) diagnostic si fixuri
aplicate direct in loc de delegate.
lasa in sesiune munca de CITIT (masurat: o runda de implementare + 4 rulari de teste a dus
sesiunea principala la ~570k desi tot codul fusese scris de subagenti). Principalii consumatori:
citirea rezultatelor de test dupa fiecare rulare (cu tot cu liniile "OK"), citirea codului pentru
diagnostic, fixuri aplicate direct in loc de delegate.
- **Nu citi log-uri brute.** Scripturile de raportare afiseaza DOAR esecurile plus un total
("22 OK, 3 FAIL: <nume + linia de esec>"). Tabelul complet se citeste o singura data, la
@@ -97,4 +96,4 @@ Sablon:
Cand un story pica de doua ori la rand, nu-l reincerca a treia oara cu acelasi prompt: semnul e ca
descrierea sau criteriul e gresit, nu executia. Rescrie story-ul (mai mic, sau cu criteriul
corectat) inainte de a mai cheltui un agent.
corectat) inainte de a mai cheltui un agent.

View File

@@ -1,6 +1,6 @@
# Prompt: seteaza conventia docs/ (insight-uri de proiect) intr-un proiect ROA
Template partajat intre proiectele ROA* (similar cu `changelog_template.txt`). Origine: ROAIMOB, 08/07/2026. Copiaza blocul de mai jos (adaptat, daca e nevoie) intr-o sesiune Claude Code din radacina oricarui proiect ROA* pentru a initializa aceeasi conventie.
Template partajat intre proiectele ROA* (similar cu `changelog_template.txt`). Copiaza blocul de mai jos (adaptat, daca e nevoie) intr-o sesiune Claude Code din radacina oricarui proiect ROA* pentru a initializa aceeasi conventie.
---

View File

@@ -1,60 +1,81 @@
# Reguli de lucru agent (comune proiectelor ROA VFP)
1. Modificari de cod: livreaza FISIER de diff `docs\diff_runda<N>_<subiect>.patch`
(`git diff --no-index <baseline.bak> <editat>`), nu diff in terminal.
Write-back in binar (txt2vcx) si commit DOAR dupa aprobarea patch-ului de catre utilizator.
Patch-urile sunt intermediare de review: NU se comit NICIODATA in git (sunt in
.gitignore ca `docs/diff_runda*.patch`); raman doar local, pe disc.
Curatenie: dupa commit se sterg patch-urile de review si backup-urile de lucru
(`*.pre_runda*.bak`).
2. Comentarii in cod: minime si strict functionale - descriu comportamentul CURENT, ca si cum
codul ar fi fost scris asa de la inceput. O linie de regula; 2-3 linii doar pentru o metoda
cu contract nebanal (parametri, cursorul asteptat/lasat deschis, pozitionarea la iesire).
Istoricul modificarilor sta DOAR in ANTETUL fisierului, niciodata inline; se aplica la fel
in `.prg` si in package-urile/procedurile PL/SQL Oracle.
INTERZIS in comentariu: nume de agent ("claude"), referinte la documente de propuneri sau la
decizii/etape (`docs/propuneri_*.md`, "M2", "T3", "dec.6", "runda27", "E7", "D-H2"), istoricul
modificarii ("inlocuieste ...", "nu mai depinde de ...", "mutat din ..."), date si autori pe
cod nou. Comentariile vechi in stil jurnal nu se rescriu din oficiu - doar cand blocul e
oricum atins, sau la cerere explicita.
In ANTETUL fisierului se tine o singura intrare CUMULATIVA per functionalitate, in stilul
existent (`*!* DD.MM.YYYY` / `*!* autor` / `*!* ce face, 1-2 fraze`): la revenirea pe aceeasi
lucrare se rescrie intrarea, nu se adauga alta. Autorul e persoana care semneaza livrarea
(ex. `marius.mutu`) - niciodata "claude" sau alt nume de agent.
Se descrie doar comportamentul final, fara referinte la revizii, runde, patch-uri sau la
corectii facute pe parcurs. La rezolvari de erori NU se adauga comentarii deloc.
Explicatiile merg in docs/ sau in mesajul de commit, nu in cod.
Changelog (`changelog_<aplicatie>.txt`): text minimal, pe limba utilizatorului, nu tehnic,
o fraza scurta per intrare. Cat timp lucrarea nu a ajuns la utilizatori (fara deploy),
erorile introduse si corectate in interiorul ei NU se pomenesc - intrarea descrie
functionalitatea asa cum ajunge la utilizator, `:nou:`/`:modificare:`; `:eroare:` ramane
doar pentru erori care au fost in productie.
3. Modificari minime: doar ce s-a cerut; fara refactorizari sau curatenie din oficiu.
4. Testare headless (fara IDE): `vfp9.exe -A -T "<script.prg>" <param>` din PowerShell.
Mediu, sabloane, capcane si metoda de depanare: `depanare_testare_vfp.md`.
5. Editare .vcx/.scx pe text (cache, cp1252 byte-safe, fidelity-check): `flux-editare-vfp-text.md`.
Cautare in binare: `cautare_vcx_vct.md`.
Versiunile `.??2` sunt instantanee si pot fi mai vechi decat binarul - verifica mtime-ul
inainte de a trage concluzii din ele; continutul real al proiectului se citeste din `.PJX`.
6. Misiuni lungi (teste, investigatii, sarcini inlantuite): NU un singur subagent cu context
acumulat — orchestrator + subagenti proaspeti per sarcina (max ~200-250k tokens/subagent),
handoff compact pe disc: `orchestrare-subagenti.md`.
7. Conventii obligatorii, de citit cand atingi zona respectiva:
- editezi orice fisier cu octeti cp1252 - `.vc2`/`.sc2`, dar si `.prg` (ex. `programe\ocautare.prg`,
unde `s`-urile cu virgula din `masina`/`si contul`/`transa` sunt octetul `0xBA`) ->
`conventie_encoding_cp1252.md`. Orice write cu un tool care nu scrie cp1252 nativ (Edit/Write)
corupe caracterele >= 0x80 din TOT fisierul (`0xBA` -> `EF BF BD`), chiar daca schimbi o singura
linie, si o face din nou la FIECARE scriere. Deci: editezi tot ce ai de editat, si abia DUPA ultima
scriere verifici byte-level si repari o singura data; daca mai editezi dupa reparare, se strica iar.
Verificare: `perl -ne 'print "$.\n" if /[\x80-\xFF]/' <fisier>`; reparare (aici pentru `0xBA`):
`perl -e 'binmode(STDIN);binmode(STDOUT);local $/;$_=<STDIN>;s/\xEF\xBF\xBD/\xBA/g;print' < f > f.tmp`.
ATENTIE: `EF BF BD` nu spune ce caracter s-a pierdut - toate diacriticele devin la fel. Ia octetul
corect per pozitie din `svn cat <fisier>` (SVN are versiunea necorupta) si abia apoi inlocuieste;
o inlocuire oarba cu `0xBA` strica `a`/`t` cu caciula (`0xE3`, `0xFE`) din alte fisiere;
- adaugi/rearanjezi controale pe formulare sau coloane in grid -> `conventie_ux_formulare.md`;
- scrii cod cu `GO` pe un `Recno()` capturat sau primit ca parametru -> `conventie_go_recno.md`;
- `ALTER TABLE` pe cursorul intors de `goExecutor.oExecute()` -> `conventie_goexecutor_alter_table.md`;
- testare UI / prin MCP -> `testare-ui-vfp.md`, `testare-vfp-mcp.md`;
- export date din Oracle -> `oracle_export.md`;
- modifici schema Oracle (tabele/view-uri/pachete) -> `scripturi-migrare-db.md`
(unde stau scripturile de migrare si modelele pentru scripturi noi).
# Reguli de lucru agent (comune proiectelor ROA VFP)
1. Modificari de cod: diff ca FISIER `docs\diff_runda<N>_<subiect>.patch`
(`git diff --no-index <baseline.bak> <editat>`), nu in terminal. Write-back in binar (txt2vcx)
si commit DOAR dupa aprobarea patch-ului. Patch-urile (in .gitignore, `docs/diff_runda*.patch`)
nu se comit niciodata, raman local. Dupa commit: sterge patch-urile si backup-urile
`*.pre_runda*.bak`.
2. Comentarii in cod: minime, strict functionale, descriu comportamentul CURENT (ca si cum ar fi
scris asa de la inceput) — o linie de regula, 2-3 doar pentru metode cu contract nebanal
(parametri, cursor asteptat/lasat deschis, pozitionare la iesire). Istoricul modificarilor
sta DOAR in ANTETUL fisierului (niciodata inline) — la fel in `.prg` si in PL/SQL Oracle.
INTERZIS in comentariu: nume de agent ("claude"), referinte la propuneri/decizii/etape
(`docs/propuneri_*.md`, "M2", "T3", "dec.6", "runda27", "E7", "D-H2"), istoricul modificarii
("inlocuieste...", "nu mai depinde de...", "mutat din..."), date si autori pe cod nou.
Comentarii vechi in stil jurnal nu se rescriu din oficiu — doar cand blocul e oricum atins
sau la cerere explicita.
Antet: o singura intrare CUMULATIVA per functionalitate (`*!* DD.MM.YYYY` / `*!* autor` /
`*!* ce face, 1-2 fraze`) — la revenire se rescrie intrarea, nu se adauga alta; autorul e cine
semneaza livrarea (ex. `marius.mutu`), niciodata agent. Doar comportamentul final — fara
revizii/runde/patch-uri/corectii. La rezolvari de erori: fara comentarii.
Explicatiile merg in docs/ sau in mesajul de commit, nu in cod.
Changelog (`changelog_<aplicatie>.txt`): strictul necesar, pe limba utilizatorului, non-tehnic
— 1-3 fraze/intrare, fara detalii de implementare, fara enumerarea locurilor atinse. Cat timp
lucrarea n-a ajuns la utilizatori, erorile introduse si corectate in interior NU se mentioneaza
— intrarea descrie functionalitatea finala, `:nou:`/`:modificare:`; `:eroare:` doar pentru erori
care au fost in productie.
3. Modificari minime si SCOPED: doar ce s-a cerut, doar pe cazul cu problema, fara refactorizari
din oficiu. Cauta intai ce exista (`inventar-comun.md`) si refoloseste; daca lipseste ceva,
propune COMPLETAREA unei functii/tabele/view comune, nu o varianta paralela. 80/20: solutia cea
mai simpla care rezolva cazul real. Completeaza `inventar-comun.md` la orice descoperire/creare
de element comun nedocumentat.
4. Testare headless (fara IDE): `vfp9.exe -A -T "<script.prg>" <param>` din PowerShell.
Mediu, sabloane, capcane, depanare: `depanare_testare_vfp.md`.
5. Editare .vcx/.scx pe text (cache, cp1252 byte-safe, fidelity-check): `flux-editare-vfp-text.md`.
Cautare in binare: `cautare_vcx_vct.md`. Versiunile `.??2` sunt instantanee, pot fi mai vechi
decat binarul — verifica mtime inainte de concluzii; continutul real e in `.PJX`.
6. Delegare: implementarile, testele, verificarile si cercetarile se dau unor subagenti Sonnet in
background (lane-uri paralele); sesiunea principala doar orchestreaza si verifica, ca sa nu i
se umple contextul. Misiuni lungi: subagenti proaspeti per sarcina (max ~200-250k
tokens/subagent), nu unul singur cu context acumulat; handoff compact pe disc:
`orchestrare-subagenti.md`.
7. Conventii obligatorii, de citit cand atingi zona respectiva:
- editezi fisiere cu octeti cp1252 - `.vc2`/`.sc2`, dar si `.prg` (ex. `programe\ocautare.prg`,
unde `s`-urile cu virgula din `masina`/`si contul`/`transa` sunt octetul `0xBA`) ->
`conventie_encoding_cp1252.md`. Orice write cu un tool ce nu scrie cp1252 nativ (Edit/Write)
corupe caracterele >= 0x80 din TOT fisierul (`0xBA` -> `EF BF BD`), chiar la o singura linie
schimbata, si o repeta la FIECARE scriere editeaza tot ce ai de editat, verifica byte-level
si repara o singura data DUPA ultima scriere. Verificare: `perl -ne 'print "$.\n" if
/[\x80-\xFF]/' <fisier>`; reparare (pt. `0xBA`): `perl -e
'binmode(STDIN);binmode(STDOUT);local $/;$_=<STDIN>;s/\xEF\xBF\xBD/\xBA/g;print' < f > f.tmp`.
`EF BF BD` nu spune ce caracter s-a pierdut - toate diacriticele devin la fel; ia octetul corect
per pozitie din `svn cat <fisier>` (necorupt) inainte sa inlocuiesti - o inlocuire oarba cu
`0xBA` strica `a`/`t` cu caciula (`0xE3`, `0xFE`) din alte fisiere;
- adaugi/rearanjezi controale pe formulare sau coloane in grid -> `conventie_ux_formulare.md`;
- `GO` pe un `Recno()` capturat/primit ca parametru -> `conventie_go_recno.md`;
- `ALTER TABLE` pe cursorul intors de `goExecutor.oExecute()` -> `conventie_goexecutor_alter_table.md`;
- testare UI / prin MCP -> `testare-ui-vfp.md`, `testare-vfp-mcp.md`;
- garzi pe valori NULL din Oracle -> `conventie_null_vfp.md`;
- export date din Oracle -> `oracle_export.md`;
- modifici schema Oracle (tabele/view-uri/pachete) -> `scripturi-migrare-db.md`.
8. Eroare raportata de utilizator: nu analiza statica indelungata — scrie intai un test care o
reproduce pe fluxul real; el da cauza si confirma remedierea. Analiza statica doar cat sa stii
ce sa pui in test.
9. Context sesiune principala: la peste **250k** salveaza contextul intr-un handoff pe disc, il
predai unei sesiuni noi si te opresti. Limita maxima absoluta: **275k**. Nu estima - masoara:
hook-ul din `monitorizare-context.md` anunta pragul la fiecare mesaj.
10. Fisier de progres MASTER per proiect (`docs\progres.md`): la zi pe tot parcursul, nu doar la
predare — stare curenta, facut/testat, ipoteze excluse (cu dovada), ce urmeaza, fisiere atinse,
comenzi de rulat. O sesiune noua porneste de acolo, fara sa reia investigatia.
11. La final de lucrare/cercetare: **propune** actualizarea documentatiei — `COMUN\docs\` daca e
comun tuturor aplicatiilor, `docs\` al proiectului daca e specific (plus `inventar-comun.md`,
regula 3). Doar relevant si reutilizabil (80/20): flux ascuns, capcana, procedura/tabela cheie
— nu tot ce ai atins, nu verbose. Cateva randuri; propui, nu scrii din oficiu.
O notita = regula + strictul de context ca sa fie aplicabila: fara cazul particular in care ai
gasit-o, fara simptomele lantului de erori, fara ce se deduce din cod (cititorul stie deja).
12. Revizuire periodica a documentatiei (`COMUN\docs\`, `docs\` al proiectului, inclusiv acest
fisier): compacteaza pastrand semantica — taie ce se deduce din cod, exemplele repetate,
istoricul, tot ce nu mai schimba o decizie. Scopul: docs + reguli sa ocupe cat mai putin context
la incarcare. Propui rezultatul, nu rescrii din oficiu; nu pierzi nicio regula/capcana, doar
cuvintele in plus. Fisierele de reguli/conventii se completeaza doar cu ce e super-util,
simplu si concis. Cadenta o da hook-ul din `monitorizare-context.md` (marker la 30 de zile).

View File

@@ -1,21 +1,28 @@
# Scripturi migrare baza de date Oracle
Scripturile de migrare a schemei (si modelele pentru scripturi noi) sunt in
`DATABASE\SCRIPTURI_CLAR` de sub radacina suitei ROA (folderul parinte al aplicatiei,
`gcDirMare`/`dirgen` — ex. `D:\ROA\DATABASE\SCRIPTURI_CLAR`).
Sursa SVN: `http://svnroa:3001/svn/ROA/DATABASE/Branches/RB-1.00`.
`DATABASE\SCRIPTURI_CLAR` de sub radacina suitei ROA (`gcDirMare`/`dirgen` — ex.
`D:\ROA\DATABASE\SCRIPTURI_CLAR`). Sursa SVN: `http://svnroa:3001/svn/ROA/DATABASE/Branches/RB-1.00`.
Pentru un script nou, urmeaza formatul/conventiile celor recente de acolo.
Reguli confirmate de Marius (24.07.2026):
- **Line-endings CRLF obligatoriu** in scripturile `.sql` — tool-urile agentului scriu
implicit LF; dupa orice scriere, verifica si converteste byte-safe LF -> CRLF (fara
decodare/reincodare). Parsarea pe fluxul ROA (ex. `ALINES` pe `CHR(13)+CHR(10)`)
esueaza silentios pe LF: tot fisierul devine un singur rand.
- `versiune_db.txt` (marker-ul `YYYY_MM_DD_NN` din radacina aplicatiei) se scrie fara
newline la final (conventia existenta).
- Aplicarea prin ODBC/`goExecutor`: sintaxa SQL*Plus `exec pachet.procedura(...)` nu
functioneaza — foloseste `begin pachet.procedura(...); end;`.
- **Line-endings CRLF obligatoriu** in scripturile `.sql` — tool-urile agentului scriu implicit
LF; dupa orice scriere, verifica si converteste byte-safe LF -> CRLF (fara decodare/reincodare).
Parsarea pe fluxul ROA (ex. `ALINES` pe `CHR(13)+CHR(10)`) esueaza silentios pe LF: tot fisierul
devine un singur rand.
- `versiune_db.txt` (marker-ul `YYYY_MM_DD_NN` din radacina aplicatiei) se scrie fara newline la
final (conventia existenta).
- Aplicarea prin ODBC/`goExecutor`: sintaxa SQL*Plus `exec pachet.procedura(...)` nu functioneaza
— foloseste `begin pachet.procedura(...); end;`.
## Continutul unui script
- **Minimul necesar si intotdeauna SCOPED**: `update`/`insert` doar pe randurile cazului tratat
(setul, codul, firma anume), niciodata pe toate randurile care "seamana" cu el.
- **Fara `select` de raportare in script** — nu-l citeste nimeni la aplicare si poate da eroare.
Verificarile se fac inainte, separat, pe schema de lucru.
- **Idempotent**: rulat de doua ori nu mai schimba nimic (`merge`, `where <coloana> is null`).
## Numerotare si versiune_db.txt

View File

@@ -11,11 +11,11 @@ Fisiere in `COMUN\utile\Teste\`: `vfp_ui_harness.ps1` (orchestrator generic, par
`mock_amessagebox.prg` (mock dialog) — infrastructura sta in radacina `Teste\`; suitele stau in
subfoldere pe subiect. Exemplu complet: `achizitie_import\test_import_nota_ui.prg` + `.ps1`.
**REGULA (Marius, 17/07/2026): testele pe aplicatii frontend exerseaza fluxul REAL al
**REGULA (Marius): testele pe aplicatii frontend exerseaza fluxul REAL al
utilizatorului** — formularul/butonul/metoda pe care o apeleaza aplicatia, NU introducerea
directa a randurilor in cursoare/tabele. Popularea directa sare peste validari/filtre/efecte
laterale si da PASS fals (caz real: un articol "adaugat" direct in cursor trecea testul, dar
prin fluxul real nu se adauga deloc). Mock-urile raman permise doar pe INFRASTRUCTURA (Oracle,
laterale si da PASS fals (caz real: articol "adaugat" direct in cursor trecea testul, dar prin
fluxul real nu se adauga deloc). Mock-urile raman permise doar pe INFRASTRUCTURA (Oracle,
dialoguri modale), nu pe pasii fluxului testat.
## Test UI nou in 5 pasi
@@ -33,7 +33,7 @@ dialoguri modale), nu pe pasii fluxului testat.
5. `powershell -File vfp_ui_harness.ps1 -TestPrg <test.prg> -Steps @('pas0',...)`.
PNG-uri in `screenshots\step_<n>_<eticheta>.png`; log in `<test>_log.txt`.
## Capcane / deblocari (toate confirmate in sesiune)
## Capcane / deblocari
a. **`SET SAFETY OFF` + `SET TALK OFF` inaintea primului `STRTOFILE`.** Cu SAFETY ON, scrierea
log-ului existent scoate un dialog modal care blocheaza rularea (proces viu, "instanta
@@ -51,22 +51,20 @@ d. **`vfp9 -A test.prg` deschide INTERMITENT editorul** in loc sa ruleze (log go
`.fxp`-ul PRECOMPILAT. Precompilarea (`COMPILE`+`QUIT`) atarna dupa COMPILE si, rulata in
ACEEASI sesiune powershell, otraveste lansarile ulterioare - ruleaza-o intr-un proces copil
izolat (`Start-Process -Wait _precompile.ps1`).
e. **Suitele NU se ruleaza in paralel** intre ele: harness-ul isi omoara instantele `vfp9`
ramase inainte de fiecare lansare, deci un al doilea test pornit peste primul il ucide.
Omorarea e INSA filtrata pe linia de comanda (`Win32_Process.CommandLine` care contine
folderul de teste): instantele `vfp9` straine sesiunea IDE a utilizatorului sau teste
dintr-un ALT proiect VFP — nu sunt atinse si nu blocheaza rularea. Nu reintroduce
`Get-Process vfp9 | Stop-Process -Force` fara filtru.
f. **FARA FURT DE FOCUS (17/07/2026)**: `Graphics.CopyFromScreen` fura focus si se corupe daca
utilizatorul lucreaza in paralel - nu se mai foloseste. Capturile se fac cu `PrintWindow`
(user32, P/Invoke) pe `Process.MainWindowHandle`, flag `2` = `PW_RENDERFULLCONTENT`
(fallback `0` daca iese goala); merge cu fereastra acoperita, dar NU minimizata. Fereastra
se muta OFF-SCREEN (`SetWindowPos`, `HWND_BOTTOM`, x=-4000, `SWP_NOACTIVATE`) imediat ce
apare handle-ul si SE RE-IMPINGE la fiecare pas (VFP se reactiveaza singur la
`Show()`/dialoguri). Consolele powershell copil sunt `-WindowStyle Hidden` (sigur pentru
consola, NU pentru GUI VFP - ascunsa, `PrintWindow` poate reda gol). Implementat in
`vfp_ui_harness.ps1` (Take-Screenshot, Push-Offscreen, Wait-MainWindowHandle) si
`_precompile.ps1`.
e. **Suitele NU se ruleaza in paralel**: harness-ul omoara instantele `vfp9` ramase inainte de
fiecare lansare, deci un al doilea test pornit peste primul il ucide. Omorarea e filtrata pe
linia de comanda (`Win32_Process.CommandLine` contine folderul de teste): instantele `vfp9`
straine (sesiunea IDE a utilizatorului, teste dintr-un ALT proiect VFP) nu sunt atinse. Nu
reintroduce `Get-Process vfp9 | Stop-Process -Force` fara filtru.
f. **FARA FURT DE FOCUS**: `Graphics.CopyFromScreen` fura focus si se corupe daca
utilizatorul lucreaza in paralel - nu se mai foloseste. Capturile: `PrintWindow` (user32,
P/Invoke) pe `Process.MainWindowHandle`, flag `2` = `PW_RENDERFULLCONTENT` (fallback `0` daca
iese goala); merge cu fereastra acoperita, NU minimizata. Fereastra se muta OFF-SCREEN
(`SetWindowPos`, `HWND_BOTTOM`, x=-4000, `SWP_NOACTIVATE`) la aparitia handle-ului si SE
RE-IMPINGE la fiecare pas (VFP se reactiveaza singur la `Show()`/dialoguri). Consolele
powershell copil: `-WindowStyle Hidden` (sigur pentru consola, NU pentru GUI VFP ascunsa -
`PrintWindow` poate reda gol). Implementat in `vfp_ui_harness.ps1` (Take-Screenshot,
Push-Offscreen, Wait-MainWindowHandle) si `_precompile.ps1`.
g. **Mock de messagebox**: `FUNCTION amessagebox` care returneaza direct valoarea butonului
(6=Da), incarcat cu `SET PROCEDURE ... ADDITIVE` **PRIMUL**, inaintea fisierelor aplicatiei:
la nume duplicat de procedura VFP foloseste fisierul cautat PRIMUL (verificat empiric).
@@ -83,25 +81,23 @@ i. **Cursorii trebuie sa aiba EXACT indecsii creati de fluxul real** inainte de
uneori in cascada la apeluri repetate. Verifica in codul apelant ce indecsi se creeaza si
replica-i identic.
j. **Mock-urile de date trebuie sa reproduca structura si semantica REALA a sursei** (view
Oracle: toate coloanele; relatii intre randuri: toate randurile implicate, nu unul singur cu
valori "compuse" manual in test). Un mock incomplet lasa campuri mereu NULL sau ascunde
pasul care se testeaza. Cand un flag global activeaza cod suplimentar (ex. `gl406`), acel
cod cere mock-uri in plus - verifica ce apeleaza si adauga metodele lipsa din dummy.
Cu `gl406=.T.` (SAFT), `GetTaxCodeIdPart`/`GetTaxCode` cer: `goApp.ReadIni`/`WriteIni`
(proprietate simpla nu ajunge, clasa `dummyapp` are nevoie de METODE), `goExecutor.oReset`
(no-op e suficient), si un cursor `saft_taxtable` real (nu doar mock pe `goExecutor` -
`update_jtva_coloane` face `USE saft_taxtable` direct pe alias). Fara ele, simptomul e un
dialog nativ Windows "Open" (cauta `saft_taxtable.dbf`) care blocheaza headless la nesfarsit,
fara nicio linie noua in log si CPU 0% - vezi `depanare_testare_vfp.md` pentru diagnosticul
cu `EnumWindows`/`PrintWindow` pe fereastra ascunsa cand simptomul e "ecran gol, fara eroare".
Oracle: toate coloanele; relatii intre randuri: toate randurile implicate, nu una singura cu
valori "compuse" manual). Un mock incomplet lasa campuri NULL sau ascunde pasul testat. Cand
un flag global activeaza cod suplimentar (ex. `gl406`), acel cod cere mock-uri in plus -
verifica ce apeleaza si adauga metodele lipsa din dummy. Cu `gl406=.T.` (SAFT),
`GetTaxCodeIdPart`/`GetTaxCode` cer: `goApp.ReadIni`/`WriteIni` (clasa `dummyapp` are nevoie
de METODE, nu doar proprietate), `goExecutor.oReset` (no-op e suficient), si cursor
`saft_taxtable` real (nu doar mock pe `goExecutor` - `update_jtva_coloane` face
`USE saft_taxtable` direct pe alias). Fara ele, simptomul e dialog nativ Windows "Open" (cauta
`saft_taxtable.dbf`) care blocheaza headless la nesfarsit, fara linie noua in log si CPU 0% -
vezi `depanare_testare_vfp.md` pentru diagnostic cu `EnumWindows`/`PrintWindow`.
k. **`LOCATE FOR camp == 'literal'` pe camp `C(n)` padded nu gaseste nimic** (`==` e exact) -
foloseste `ALLTRIM(camp) == 'literal'`.
l. **`CREATEOBJECT`/`ADDPROPERTY` se comporta gresit apelate DINTR-O PROCEDURA in acest runtime
headless** (obiect returnat ca string de 30 spatii; `ADDPROPERTY` da eroare 11). Din
programul PRINCIPAL merg. Construieste obiectele-parametru INLINE in main, nu intr-un helper.
Cauza confirmata intr-un caz concret: linie de cod prea lunga in ACEEASI metoda de clasa -
vezi `depanare_testare_vfp.md` sectiunea 6. Remediul (constructie inline) ramane valabil
oricum, indiferent de cauza exacta dintr-un caz punctual.
headless** (obiect returnat ca string de 30 spatii; `ADDPROPERTY` da eroare 11). Din programul
PRINCIPAL merg. Construieste obiectele-parametru INLINE in main, nu intr-un helper. Cauza
confirmata intr-un caz concret: linie de cod prea lunga in ACEEASI metoda de clasa - vezi
`depanare_testare_vfp.md` sectiunea 6; remediul (constructie inline) ramane valabil oricum.
m. **Fara `SELECT-SQL` pe cursorul legat de grid**: `SELECT ... FROM <cursor> INTO CURSOR` cat
timp cursorul e RecordSource-ul unui grid viu poate omori procesul vfp9 silentios (fara
eroare catchabila, fara semafor). Foloseste xBase nativ (`COUNT FOR ... TO`, `CALCULATE`,
@@ -113,9 +109,9 @@ n. **Wrapper-ul `.ps1` trebuie sa paseze `-SyncDir` daca `.prg`-ul isi seteaza p
asteapta un fisier care nu vine). Timeout minim: ~30s x numarul de pasi din `-Steps`
(auto-continue per checkpoint din `HarnessWaitContinue`), plus marja de pornire.
o. **Formularul resincronizeaza singur dupa o alegere din grid** (`lSyncPending` + `tmrSync`,
ex. `do_modifica_explicatie_tva` din `ointroduceri.vcx`): starea de imediat dupa actiune NU e
ex. `do_modifica_explicatie_tva` din `ointroduceri.vcx`): starea imediat dupa actiune NU e
observabila - `DOEVENTS FORCE` lasa timer-ul sa porneasca, iar resincronizarea rescrie ce
tocmai s-a aplicat (la explicatia TVA: randul S revine la familia documentului si randurile T
se realiniaza dupa el). Scrie assert-urile pe starea de DUPA resincronizare si alege un efect
pe care resincronizarea NU il repara (acolo: `scc`-ul randului T, atins doar cand se schimba
explicatia). Altfel testul pica fara sa fie ceva gresit in cod.
tocmai s-a aplicat (la explicatia TVA: randul S revine la familia documentului, randurile T se
realiniaza dupa el). Scrie assert-urile pe starea de DUPA resincronizare, pe un efect pe care
resincronizarea NU il repara (acolo: `scc`-ul randului T, atins doar la schimbarea explicatiei)
- altfel testul pica fara sa fie ceva gresit in cod.

View File

@@ -14,16 +14,16 @@ Start-Process -FilePath "C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.e
```
- Gate-ul de pornire (`gcNumeProgram = 'ROAGEST'` in `roagest.prg`) verifica
`JUSTSTEM(SYS(16,0))` — numele programului de la nivelul 0 al stivei, nu numele
procesului `.exe`. Rulat interpretat, `SYS(16,0)` = `roagest.prg`, deci gate-ul trece.
`JUSTSTEM(SYS(16,0))` — numele programului de la nivelul 0 al stivei, nu numele procesului
`.exe`. Rulat interpretat, `SYS(16,0)` = `roagest.prg`, deci gate-ul trece.
- Fereastra rezultata are titlul `ROA - Gestiuni` (setat din `NUMEPROGRAM`).
## Capcana: focus furat de terminal
Daca sesiunea Claude Code afiseaza output in timp ce comanda de lansare ruleaza,
fereastra terminalului/IDE-ului ramane in prim-plan si VFP porneste in fundal —
`Screenshot`/`Snapshot` din `windows-mcp` pot raporta "No windows found" desi procesul
si fereastra exista (verificabil cu `Get-Process vfp9 | Select MainWindowTitle`).
Daca sesiunea Claude Code afiseaza output in timp ce comanda de lansare ruleaza, fereastra
terminalului/IDE-ului ramane in prim-plan si VFP porneste in fundal — `Screenshot`/`Snapshot`
din `windows-mcp` pot raporta "No windows found" desi procesul si fereastra exista (verificabil
cu `Get-Process vfp9 | Select MainWindowTitle`).
Fix: inainte de screenshot, adu explicit fereastra in prim-plan dupa titlu:
@@ -31,8 +31,8 @@ Fix: inainte de screenshot, adu explicit fereastra in prim-plan dupa titlu:
mcp__windows-mcp__App mode=switch name="ROA - Gestiuni"
```
apoi `Screenshot`. Nu te baza pe enumerarea implicita de ferestre a `windows-mcp` cand
ai lansat procesul chiar in runda curenta de comenzi.
apoi `Screenshot`. Nu te baza pe enumerarea implicita de ferestre a `windows-mcp` cand ai lansat
procesul chiar in runda curenta de comenzi.
## Curatare dupa test

View File

@@ -11,4 +11,10 @@ Vreau ca verificarile de coduri fiscale din D406, D394, Registrele de TVA sa fol
4. ROACONT - overificari.vcx > formularul istoric coduri fiscale are coloane care nu mai au relavanta sau nu mai sunt completate din tabel. in tabelul contafin_oracle.istoric_coduri_fiscale, campul regcom are spatii si nu se afiseaza in formularul istoric. verifica
5. ROACONT - VERIFICARE cod fiscal, label-ul de sub grid-ul cu rezultate si detalii F4 sa contina si status "TVA Incasare"
5. ROACONT - VERIFICARE cod fiscal, label-ul de sub grid-ul cu rezultate si detalii F4 sa contina si status "TVA Incasare"
6. ROAFACTURARE - EDITARE FACTURA EMISA ANTERIOR, CARE NU A FOST TRIMISA INCA IN EFACTURA (anaf_efactura.id_fact). punctul critic este ca notele contabile si eventual rulajele generate se genereaza complicat la emiterea facturii prin pack_facturare, iar editarea este o simpla editare, si nu sincronizeaza si notele contabile si rulajele. si sunt diverse tipuri de facturi sau de avize (pe baza de lista de preturi, pe baza de comanda, pe baza de contract, pe baza de aviz) si fiecare genereaza note contabile sau rulaje si articole de vanzare (vanzari si vanzari_detalii)
7. ROAFACTURARE - TVA unitar si valoarea TVA pe o linie de articol este calculata si nu salvata in vanzari si vanzari_detalii. din aceasta cauza, daca o factura are valoare totala 99.99 lei, dar utilizatorul doreste 100.00 lei total cu tva (pentru ca politica de preturi are bifat preturi fara TVA si se porneste calculul incepand de la pretul fara TVA al articolului) tva-ul se calculeaza rotunjit si nu se poate edita, ca sa dea factura fix 100.00 lei. implicatiile calculului TVA in loc de salvare sunt foarte mari si adanci in program, la introducerea facturii, listarea facturii initiale, relistarea facturii
8. ROAFACTURARE - in pack_facturare am salvat in vanzari valori totale denormalizat (fara tva, tva, cu tva, numarul avizului/comanda/contract etc.) ca sa nu le calculez in view din vanzari_detalii pentru ca view-ul de facturi este foarte complex, cu functii si expresii si nu era optimizabil si acceseaza total tabelele vanzari si vanzari_detalii. folosesc un view pe modelul original, si un view cu valorile totale din vanzari. doar ca am observat un bug, la facturile din avize, nu se salveaza corect in vanzari avizul sau numarul/data/suma chitantei daca factura este achitata numerar. trebuie depanat. schema de verificare productie este VENDING@ROA_VENDING

View File

@@ -397,7 +397,7 @@ Function verific_partener
ll_l=.F.
If Empty(tcCont) Or Type('tccont')#'C'
If Type('tccont')#'C' Or Empty(Nvl(tcCont,''))
Return ll_l
Else
lcCont = Alltrim(tcCont)

View File

@@ -0,0 +1,543 @@
* test_repro_partener_scc_null.prg
* REPRODUCERE: "achizitie din import > interna", dublu click pe coloana "Partener credit"
* (Grid1.cPartC.Text1.DblClick -> LostFocus(.T.) -> verific_partener in ooperatii_comune.prg).
* Cand contul creditor al randului (introdc.scc) vine NULL din nota contabila configurata,
* SQL-ul construit prin concatenare in verific_partener devine .NULL., iar garda din
* oExecutor.oExecute (If Empty(tcSql)) NU il prinde - EMPTY(.NULL.) e .F. in VFP - deci
* SQLEXEC primeste un statement NULL si da eroarea
* "SQL statement parameter is required for non-prepared SQLEXEC() calls." (OEXECUTOR.OEXECUTE)
*
* Ramura cu valuta merge pentru ca acolo nota contabila are contul creditor completat (401).
*
* Scenarii, pe formularul real import_nota(.T.) + dialogul real import_adauga_factura:
* A. rand cu scc NULL -> dublu click pe Partener credit: SQL-ul ajuns la executor e NULL (BUG)
* B. acelasi rand cu scc = '401' -> dublu click: SQL valid (comportamentul ramurii cu valuta)
*
* Rulare: powershell -ExecutionPolicy Bypass -File test_repro_partener_scc_null.ps1
SET SAFETY OFF
SET TALK OFF
SET DELETED ON
SET EXACT ON
SET CENTURY ON
SET DATE DMY
SET DECIMALS TO 4
SET NULLDISPLAY TO ''
CLOSE DATABASES
PUBLIC gcUILog
gcUILog = "D:\ROA\ROAGEST\COMUN\utile\Teste\achizitie_import\test_repro_partener_scc_null_log.txt"
STRTOFILE("START " + TTOC(DATETIME()) + CHR(13)+CHR(10), gcUILog)
PUBLIC gnAsserts, gnPass, gcSqlPrimit, glSqlNull, gnApeluri
STORE 0 TO gnAsserts, gnPass, gnApeluri
gcSqlPrimit = ''
glSqlNull = .F.
ON ERROR DO PnErr WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
ON SHUTDOWN QUIT
TRY
LOCAL gcAppPath, lcPath
gcAppPath = "D:\ROA\ROAGEST\"
SET DEFAULT TO (gcAppPath)
lcPath = gcAppPath + 'Date;' + gcAppPath + 'Include;' + gcAppPath + 'FERESTRE;' + ;
gcAppPath + 'GRAFICE;' + gcAppPath + 'CLASE;' + gcAppPath + 'MENIURI;' + ;
gcAppPath + 'PROGRAME;' + gcAppPath + 'RAPOARTE;' + gcAppPath + 'COMUN;' + ;
gcAppPath + 'COMUN\CLASE;' + gcAppPath + 'COMUN\FERESTRE;' + gcAppPath + 'COMUN\PROGRAME;' + ;
gcAppPath + 'COMUN\GRAFICE;' + gcAppPath + 'COMUN\RAPOARTE;' + gcAppPath + 'COMUN\MENIURI;' + ;
gcAppPath + 'COMUN\UTILE\GRIDEXTRAS;' + gcAppPath + 'COMUN\UTILE\CTL32;' + ;
gcAppPath + 'COMUN\UTILE\HPDF;' + gcAppPath + 'COMUN\UTILE\HPDF\REPORTOUTPUT;' + ;
gcAppPath + 'COMUN\UTILE\WEB;' + gcAppPath + 'COMUN\UTILE\EXCEL;' + ;
ADDBS(SUBSTR(gcAppPath,1,RAT([\],gcAppPath,2)))+[COMUNROA\]
SET PATH TO &lcPath ADDITIVE
DO PnLog WITH 'SET PATH OK'
*----- CLASE -----
SET CLASSLIB TO (gcAppPath + "comun\clase\appwiz") ADDITIVE
SET CLASSLIB TO GESTIUNI ADDITIVE
SET CLASSLIB TO CAUT ADDITIVE
SET CLASSLIB TO BAZA ADDITIVE
SET CLASSLIB TO comun ADDITIVE
SET CLASSLIB TO accessibility.vcx ADDITIVE
SET CLASSLIB TO messagebox ADDITIVE
SET CLASSLIB TO registry ADDITIVE
SET CLASSLIB TO cauta_alfa_forms.vcx ADDITIVE
SET CLASSLIB TO DECABAZA ADDITIVE
SET CLASSLIB TO onomenclatoare ADDITIVE
SET CLASSLIB TO stocuri.vcx ADDITIVE
SET CLASSLIB TO rulaje.vcx ADDITIVE
SET CLASSLIB TO ointroduceri ADDITIVE
SET CLASSLIB TO ointroduceri_web ADDITIVE
SET CLASSLIB TO ointroduceri_depozit ADDITIVE
SET CLASSLIB TO overificari ADDITIVE
SET CLASSLIB TO ferestre_oracle ADDITIVE
SET CLASSLIB TO ferestre_cere_date.vcx ADDITIVE
SET CLASSLIB TO configurare.vcx ADDITIVE
SET CLASSLIB TO serii_numere.vcx ADDITIVE
SET CLASSLIB TO omodificari.vcx ADDITIVE
SET CLASSLIB TO ocompensari.vcx ADDITIVE
SET CLASSLIB TO caut_ora ADDITIVE
SET CLASSLIB TO onote_contabile ADDITIVE
SET CLASSLIB TO otoolbar ADDITIVE
SET CLASSLIB TO bon_fisc ADDITIVE
SET CLASSLIB TO onom_articole ADDITIVE
SET CLASSLIB TO onom_retete ADDITIVE
SET CLASSLIB TO orapoarte ADDITIVE
SET CLASSLIB TO orapoarte_gestiuni ADDITIVE
SET CLASSLIB TO orapoarte_parametri ADDITIVE
SET CLASSLIB TO ONOM_CURS ADDITIVE
SET CLASSLIB TO ctl32_statusbar_fals.vcx ADDITIVE
SET CLASSLIB TO ctl32_common.vcx ADDITIVE
SET CLASSLIB TO ctl32_structs.vcx ADDITIVE
SET CLASSLIB TO ctl32_progressbar.vcx ADDITIVE
SET CLASSLIB TO ctl32_balloontip.vcx ADDITIVE
SET CLASSLIB TO ocriterii.vcx ADDITIVE
SET CLASSLIB TO oavize.vcx ADDITIVE
SET CLASSLIB TO onomenclatoare2 ADDITIVE
SET CLASSLIB TO wwdialogs.vcx ADDITIVE
SET CLASSLIB TO oimportxml.vcx ADDITIVE
SET CLASSLIB TO excelxml.vcx ADDITIVE
SET CLASSLIB TO orapoarte_obinv.vcx ADDITIVE
DO PnLog WITH 'SET CLASSLIB OK'
*----- PROCEDURI (mock-urile PRIMELE) -----
SET PROCEDURE TO PROCEDURI
SET PROCEDURE TO "D:\ROA\ROAGEST\COMUN\utile\Teste\mock_amessagebox.prg" ADDITIVE
SET PROCEDURE TO acces_meniu ADDITIVE
SET PROCEDURE TO cauta_alfa ADDITIVE
SET PROCEDURE TO pmenu ADDITIVE
SET PROCEDURE TO proceduri_comune ADDITIVE
SET PROCEDURE TO quitapp ADDITIVE
SET PROCEDURE TO init_program ADDITIVE
SET PROCEDURE TO oproceduri_listari.prg ADDITIVE
SET PROCEDURE TO oproceduri_configurare.prg ADDITIVE
SET PROCEDURE TO oproceduri_articole.prg ADDITIVE
SET PROCEDURE TO oproceduri_retete.prg ADDITIVE
SET PROCEDURE TO orapoarte.prg ADDITIVE
SET PROCEDURE TO mesaje ADDITIVE
SET PROCEDURE TO oserii_numere.prg ADDITIVE
SET PROCEDURE TO oexport.prg ADDITIVE
SET PROCEDURE TO wwConfig.prg ADDITIVE
SET PROCEDURE TO proceduri_rapoarte.prg ADDITIVE
SET PROCEDURE TO OPROCEDURI_CURS.PRG ADDITIVE
SET PROCEDURE TO validare.prg ADDITIVE
SET PROCEDURE TO GENCURSOR.PRG ADDITIVE
SET PROCEDURE TO OPROCEDURI_COMUNE.PRG ADDITIVE
SET PROCEDURE TO OINIT_OPTIUNI.PRG ADDITIVE
SET PROCEDURE TO updateserver.prg ADDITIVE
SET PROCEDURE TO oinainte_de.prg ADDITIVE
SET PROCEDURE TO ooperatii_comune.prg ADDITIVE
SET PROCEDURE TO Ocompensari.PRG ADDITIVE
SET PROCEDURE TO OPROCEDURI_aMS.PRG ADDITIVE
SET PROCEDURE TO oproceduri_rulaje ADDITIVE
SET PROCEDURE TO oproceduri_stocuri ADDITIVE
SET PROCEDURE TO OINTRODUCERI ADDITIVE
SET PROCEDURE TO oHeader.prg ADDITIVE
SET PROCEDURE TO proceduri_excel.PRG ADDITIVE
SET PROCEDURE TO onomenclatoare.PRG ADDITIVE
SET PROCEDURE TO osecurity ADDITIVE
SET PROCEDURE TO ocautare ADDITIVE
SET PROCEDURE TO orefaceri ADDITIVE
SET PROCEDURE TO ofacturare_comun.PRG ADDITIVE
SET PROCEDURE TO ofacturare_stoc.PRG ADDITIVE
SET PROCEDURE TO oproceduri_util.prg ADDITIVE
SET PROCEDURE TO wwxmlhttp.prg ADDITIVE
SET PROCEDURE TO ini.prg ADDITIVE
SET PROCEDURE TO odocumente.prg ADDITIVE
SET PROCEDURE TO regex.prg ADDITIVE
SET PROCEDURE TO wwutils.prg ADDITIVE
SET PROCEDURE TO iniacces.prg ADDITIVE
SET PROCEDURE TO version.prg ADDITIVE
SET PROCEDURE TO xdate.prg ADDITIVE
SET PROCEDURE TO oproceduri_obinv.prg ADDITIVE
SET PROCEDURE TO oproceduri_facturare.prg ADDITIVE
SET PROCEDURE TO "D:\ROA\ROAGEST\COMUN\utile\Teste\ui_harness.prg" ADDITIVE
DO PnLog WITH 'SET PROCEDURE OK'
*----- Globale -----
PUBLIC gnPc, gnPval, gnPcant, gnPpret, gnPPretval, gnPCurs, gnPPretV, gnPPretVal
STORE 2 TO gnPc, gnPval
gnPcant = 3
STORE 4 TO gnPpret, gnPPretval, gnPPretVal, gnPPretV, gnPCurs
PUBLIC gl406, gcS, gnAn, gnLuna, gnIdFirma, gnIdSucursala, gcAcces, gcFirma
gl406 = .T.
gcS = 'CONTAFIN'
gnAn = YEAR(DATE())
gnLuna = MONTH(DATE())
gnIdFirma = 110
gnIdSucursala = 110
gcAcces = "1;2;3;4;5;6;7;8;"
gcFirma = gcS
PUBLIC nror(65000)
PUBLIC gnMockRaspuns, gcMockUltimMesaj, gnMockUltimTip
gnMockRaspuns = 6
gcMockUltimMesaj = ''
gnMockUltimTip = 0
PUBLIC gnButon, gcTempPath, gnHandle, gnTipGest, gcCondSucursala
gnButon = 1
gcTempPath = ADDBS(SYS(2023))
gnHandle = -1
gnTipGest = 0
gcCondSucursala = ''
PUBLIC goExecutor, goApp
goExecutor = CREATEOBJECT('spionexecutor')
goApp = CREATEOBJECT('dummyapp')
*----- poAct: antetul notei interne (lei) -----
PUBLIC poAct
poAct = CREATEOBJECT('Custom')
poAct.AddProperty('nume_val', '')
poAct.AddProperty('curs', 1)
poAct.AddProperty('proc_tva', 1.21)
poAct.AddProperty('nnir', 0)
poAct.AddProperty('id_valuta', 0)
poAct.AddProperty('id_fdoc', 1)
poAct.AddProperty('fdoc', 'FACTURA')
poAct.AddProperty('id_partc', 463)
poAct.AddProperty('partc', 'R.A.J.A. C-TA')
poAct.AddProperty('serie_act', '')
poAct.AddProperty('dataact', DATE())
poAct.AddProperty('tva_incasare', 1)
poAct.AddProperty('id_set', 1)
poAct.AddProperty('id_gestin', 1)
IF USED('jtva_coloane2')
USE IN ('jtva_coloane2')
ENDIF
CREATE CURSOR jtva_coloane2 (ordine N(8), id_jtva_coloana N(14), denumire C(100), ;
jc N(1), jv N(1), afisat N(1), coloana_jc C(20), coloana_jv C(20), cota_tva N(6,2), id_tva N(14))
INSERT INTO jtva_coloane2 VALUES (0, 0, '', 0, 0, 1, '', '', 0, 0)
INSERT INTO jtva_coloane2 VALUES (1, 208, 'ACH. INT. NEEX. 21%', 1, 0, 1, 'RO21B', 'RO21T', 21, 209)
INSERT INTO jtva_coloane2 VALUES (2, 209, 'TVA ACH. INT. NEEX. 21%', 1, 0, 1, 'RO21T', '', 21, 0)
IF USED('saft_taxtable')
USE IN ('saft_taxtable')
ENDIF
CREATE CURSOR saft_taxtable (taxname C(250) NULL, typename C(250) NULL, taxcode N(6) NULL, ;
taxtype N(3) NULL, descriere C(250) NULL, tip C(100) NULL, descriere_tip C(250) NULL, ;
procent_taxa N(7,2) NULL, procent_prorata N(7,2) NULL, inactiv N(1) NULL, tva N(1) NULL, ;
wht N(1) NULL, tva_achizitii N(1) NULL, tva_livrari N(1) NULL)
INDEX ON taxcode TAG taxcode
INSERT INTO saft_taxtable (taxname, taxcode, descriere, procent_taxa, tva, wht, tva_achizitii, tva_livrari) ;
VALUES ('', 0, '', 0, 1, 1, 1, 1)
INSERT INTO saft_taxtable (taxname, taxcode, descriere, procent_taxa, tva, wht, tva_achizitii, tva_livrari) ;
VALUES ('301104-Achizitii interne cota 21%', 301104, '', 21, 1, 0, 1, 0)
*----- introdc gol + sablonul notei interne: contul creditor (scc) vine NULL din nomenclator -----
DO CreeazaIntrodcNull WITH 'introdc'
DO CreeazaIntrodcNull WITH 'introdc_sablon'
INSERT INTO introdc_sablon (scd, scc, cu_tva, ordine, id_set, participa_valuta, tip_rand, ;
id_jtva_coloana, ptva, explicatie_tva) ;
VALUES ('371', .NULL., 1, 1, 1, .T., 'B', 208, 21, 'ACH. INT. NEEX. 21%')
INSERT INTO introdc_sablon (scd, scc, cu_tva, ordine, id_set, participa_valuta, tip_rand, ;
id_jtva_coloana, ptva, explicatie_tva) ;
VALUES ('4428', .NULL., 1, 2, 1, .T., 'T', 209, 21, 'TVA ACH. INT. NEEX. 21%')
GO TOP IN introdc_sablon
IF USED('rul_temp')
USE IN ('rul_temp')
ENDIF
CREATE CURSOR rul_temp (denumire C(100), codmat C(30), cant N(14,3), pret_val N(18,4), ;
pretd N(18,4), pret N(18,4), pret_lei N(18,4), cont C(10), acont C(20), serie C(30), ;
lot C(30), adata_expirare C(10), proc_disc N(6,2), cota_tva N(6,2))
INSERT INTO rul_temp (denumire, codmat, cant, pret, pret_lei, cont, cota_tva) ;
VALUES ('PLACEHOLDER', 'PH', 1, 1, 1, '371', 21)
SELECT introdc
INDEX ON Str(Nvl(nr_doc,0),8) + Icase(tip_rand='B','1', tip_rand='S','2', tip_rand='G','3', tip_rand='T','4', tip_rand='D','5', '6') + Padr(Nvl(scd,''),10) TAG ord_doc
SET ORDER TO ord_doc
PRIVATE tlIntern
tlIntern = .T.
DO PnLog WITH 'CREATEOBJECT(import_nota, .T. - achizitie interna)'
SELECT introdc
PUBLIC goObj
goObj = CREATEOBJECT('IMPORT_nota', .T.)
IF VARTYPE(goObj) <> 'O'
DO PnLog WITH 'FAIL: instantiere import_nota'
QUIT
ENDIF
goObj.lDialogAratat = .T.
goObj.oact = poAct
goObj.WindowType = 0
goObj.Visible = .T.
goObj.Show()
goObj.WindowState = 2
DOEVENTS FORCE
SELECT rul_temp
ZAP
goObj.gridart.Refresh()
DOEVENTS FORCE
*========================= factura interna, prin dialogul real =========================
PUBLIC goDlg
goDlg = CREATEOBJECT('import_adauga_factura', goObj)
goDlg.cFelDoc = 'FACTURA'
goDlg.nIdFdoc = 1
goDlg.nNract = 15000
goDlg.dDataAct = DATE()
goDlg.nIdPartener = 463
goDlg.cPartener = 'R.A.J.A. C-TA'
goDlg.cExplicatia = 'Achizitie interna'
goDlg.nSuma = 1000
goDlg.nSumaLei = 0
goDlg.nCurs = 0
goDlg.nIdValuta = 0
goDlg.cValuta = ''
goDlg.chkInValutaCont.Value = 0
goDlg.chkParticipaValuta.Value = 1
goDlg.nIdExplicatieTva = 208
goDlg.cExplicatieTva = 'ACH. INT. NEEX. 21%'
goDlg.nProcentTva = 21
goDlg.optTipTva.Value = 1
goDlg.optTipTva.InteractiveChange()
goDlg.WindowType = 0
goDlg.Visible = .T.
goDlg.Show()
DOEVENTS FORCE
DO PnLog WITH 'dialog completat, valideaza() = ' + TRANSFORM(goDlg.valideaza())
PUBLIC goT
goT = CREATEOBJECT('Empty')
=ADDPROPERTY(goT,'serie_act',ALLTRIM(NVL(goDlg.cSerieAct,'')))
=ADDPROPERTY(goT,'nract',goDlg.nNract)
=ADDPROPERTY(goT,'dataact',goDlg.dDataAct)
=ADDPROPERTY(goT,'fdoc',goDlg.cFelDoc)
=ADDPROPERTY(goT,'id_fdoc',goDlg.nIdFdoc)
=ADDPROPERTY(goT,'id_partc',goDlg.nIdPartener)
=ADDPROPERTY(goT,'partc',goDlg.cPartener)
=ADDPROPERTY(goT,'explicatia',ALLTRIM(NVL(goDlg.cExplicatia,'')))
=ADDPROPERTY(goT,'suma',goDlg.nSuma)
=ADDPROPERTY(goT,'suma_val',0)
=ADDPROPERTY(goT,'in_valuta',0)
=ADDPROPERTY(goT,'participa_valuta',.T.)
=ADDPROPERTY(goT,'id_valuta',0)
=ADDPROPERTY(goT,'curs',0)
=ADDPROPERTY(goT,'nume_val','')
=ADDPROPERTY(goT,'cTipTva','F')
=ADDPROPERTY(goT,'id_jtva_coloana',goDlg.nIdExplicatieTva)
=ADDPROPERTY(goT,'disc_baza_lei',0)
=ADDPROPERTY(goT,'disc_baza_val',0)
DO PnLog WITH 'do_adauga_factura = ' + TRANSFORM(goObj.do_adauga_factura(goT))
goDlg.Hide()
DOEVENTS FORCE
DO DumpIntrodc
*========================= SCENARIU A: scc NULL (asa vine din nota interna) =========================
SELECT introdc
LOCATE FOR tip_rand == 'B'
DO Assert WITH 'A0-randul B al facturii exista', IIF(FOUND(),1,0), 1
DO Assert WITH 'A1-introdc.scc este NULL pe randul B (ca in nota interna)', IIF(ISNULL(introdc.scc),1,0), 1
gcSqlPrimit = ''
glSqlNull = .F.
gnApeluri = 0
DO PnLog WITH 'SCENARIU A: dublu click pe Partener credit, cu scc NULL'
TRY
goObj.Grid1.cPartC.Text1.DblClick()
CATCH TO loExcA
DO PnLog WITH ' EXCEPTIE ' + TRANSFORM(loExcA.ErrorNo) + ' [' + loExcA.Message + '] in ' + loExcA.Procedure + ':' + TRANSFORM(loExcA.LineNo)
ENDTRY
DOEVENTS FORCE
DO PnLog WITH ' apeluri executor = ' + TRANSFORM(gnApeluri) + ' SQL NULL/gol = ' + TRANSFORM(glSqlNull)
DO Assert WITH 'A2-executorul NU primeste SQL NULL/gol la dublu click (scc NULL)', IIF(glSqlNull,1,0), 0
SELECT introdc
LOCATE FOR tip_rand == 'B'
DO Assert WITH 'A3-partenerul randului ramane neschimbat dupa dublu click (scc NULL)', NVL(introdc.id_partc,0), 463
*========================= SCENARIU B: scc = 401 (ca pe ramura cu valuta) =========================
SELECT introdc
LOCATE FOR tip_rand == 'B'
REPLACE scc WITH '401'
gcSqlPrimit = ''
glSqlNull = .F.
gnApeluri = 0
DO PnLog WITH 'SCENARIU B: dublu click pe Partener credit, cu scc = 401'
TRY
goObj.Grid1.cPartC.Text1.DblClick()
CATCH TO loExcB
DO PnLog WITH ' EXCEPTIE ' + TRANSFORM(loExcB.ErrorNo) + ' [' + loExcB.Message + '] in ' + loExcB.Procedure + ':' + TRANSFORM(loExcB.LineNo)
ENDTRY
DOEVENTS FORCE
DO PnLog WITH ' apeluri executor = ' + TRANSFORM(gnApeluri) + ' SQL NULL/gol = ' + TRANSFORM(glSqlNull)
DO PnLog WITH ' ultimul SQL = [' + LEFT(NVL(gcSqlPrimit,'<NULL>'), 200) + ']'
DO Assert WITH 'B1-executorul NU primeste SQL NULL/gol la dublu click (scc = 401)', IIF(glSqlNull,1,0), 0
DO PnLog WITH '========================================================='
DO PnLog WITH 'REZULTAT: ' + TRANSFORM(gnPass) + '/' + TRANSFORM(gnAsserts) + ' assert-uri PASS'
IF gnPass = gnAsserts
DO PnLog WITH 'REZULTAT: PASS'
ELSE
DO PnLog WITH 'REZULTAT: FAIL'
ENDIF
CATCH TO loExc
DO PnLog WITH 'CATCH ErrorNo=' + TRANSFORM(loExc.ErrorNo) + ' Message=' + loExc.Message + ' Proc=' + loExc.Procedure + ' Line=' + TRANSFORM(loExc.LineNo) + ' [' + loExc.LineContents + ']'
ENDTRY
QUIT
*==================================================================================
PROCEDURE PnLog
LPARAMETERS tcMsg
SET SAFETY OFF
LOCAL lcL
lcL = IIF(FILE(gcUILog), FILETOSTR(gcUILog), '')
STRTOFILE(lcL + tcMsg + CHR(13)+CHR(10), gcUILog)
ENDPROC
PROCEDURE PnErr
LPARAMETERS tnErr, tcMsg, tcProg, tnLine
DO PnLog WITH 'ON ERROR ' + TRANSFORM(tnErr) + ' [' + tcProg + ':' + TRANSFORM(tnLine) + '] ' + tcMsg
ENDPROC
PROCEDURE Assert
LPARAMETERS tcNume, tnActual, tnAsteptat
gnAsserts = gnAsserts + 1
IF tnActual = tnAsteptat
gnPass = gnPass + 1
DO PnLog WITH ' PASS ' + tcNume
ELSE
DO PnLog WITH ' FAIL ' + tcNume + ' (actual=' + TRANSFORM(tnActual) + ', asteptat=' + TRANSFORM(tnAsteptat) + ')'
ENDIF
ENDPROC
PROCEDURE DumpIntrodc
LOCAL lnSel
lnSel = SELECT()
DO PnLog WITH 'DUMP introdc:'
SELECT introdc
SCAN
DO PnLog WITH ' recno=' + TRANSFORM(RECNO()) + ' tip_rand=' + tip_rand + ' nract=' + TRANSFORM(nract) + ;
' scd=[' + NVL(ALLTRIM(scd),'<NULL>') + '] scc=' + IIF(ISNULL(scc),'<NULL>','[' + ALLTRIM(NVL(scc,'')) + ']') + ;
' id_partc=' + TRANSFORM(NVL(id_partc,0)) + ' partc=[' + ALLTRIM(NVL(partc,'')) + '] suma=' + TRANSFORM(suma)
ENDSCAN
SELECT (lnSel)
ENDPROC
*-- introdc ca in productie: coloanele de conturi vin NULLABLE din Oracle (vnote_contabile)
PROCEDURE CreeazaIntrodcNull
LPARAMETERS tcAlias
IF USED(tcAlias)
USE IN (tcAlias)
ENDIF
CREATE CURSOR (tcAlias) ( ;
id_note N(14), explicatia C(100), scd C(10) NULL, ascd C(20) NULL, scc C(10) NULL, ascc C(20) NULL, ;
cu_tva N(1), id_set N(14), ordine N(8), in_valuta N(1), id_jtva_coloana N(14) NULL, ;
ptva N(6,2), explicatie_tva C(50), tipjurnal C(2), taxcode N(6), paymentcode C(9), ;
suma N(18,4), suma_val N(18,4), id_partd N(14), id_partc N(14), partd C(100), partc C(100), ;
id_fact N(14), id_factd N(14), id_factc N(14), pereched N(14), perechec N(14), ;
nract N(14), serie_act C(10), explicatia4 C(50), explicatia5 C(50), participa_valuta L, ;
id_valuta N(14), curs N(14,4), nume_val C(10), dataact D, fdoc C(50), id_fdoc N(14), ;
se_scrie N(1), tva_incasare N(1), doc_color N(10), doc_label C(10), tip_rand C(1), ;
doc_key C(80), nr_doc N(8), suma_doc N(18,4), suma_doc_val N(18,4), mod_manual N(1), expl_manual N(1), ;
scd_orig C(20), ascd_orig C(20), rand_dvi N(1), valuta_proprie N(1))
ENDPROC
PROCEDURE CreeazaJtvaColoaneView
LPARAMETERS tcCursor
IF USED(m.tcCursor)
USE IN (m.tcCursor)
ENDIF
CREATE CURSOR (m.tcCursor) (id_jtva_coloana N(14), denumire C(100), jc N(1), jv N(1), ;
coloana_jc C(20), coloana_jv C(20), cota_tva N(6,2), id_tva N(14) NULL, afisat N(1), ;
id_jtva_ex N(14) NULL, id_jtva_neex N(14) NULL, ordine N(8), ;
taxcode N(6) NULL, taxcode_neexigibil N(6) NULL, taxcode_n50 N(6) NULL, ;
taxcode_n50_tvai N(6) NULL, taxcode_n100 N(6) NULL, taxcode_regularizare N(6) NULL, taxcode_tvai N(6) NULL)
INSERT INTO (m.tcCursor) (id_jtva_coloana, denumire, jc, jv, afisat, ordine, cota_tva) VALUES (0, '', 0, 0, 1, 0, 0)
INSERT INTO (m.tcCursor) (id_jtva_coloana, denumire, jc, jv, coloana_jc, cota_tva, id_tva, afisat, ordine, taxcode) ;
VALUES (208, 'ACH. INT. NEEX. 21%', 1, 0, 'RO21B', 21, 209, 1, 1, 301104)
INSERT INTO (m.tcCursor) (id_jtva_coloana, denumire, jc, jv, coloana_jc, cota_tva, afisat, ordine, taxcode) ;
VALUES (209, 'TVA ACH. INT. NEEX. 21%', 1, 0, 'RO21T', 21, 1, 2, 301104)
ENDPROC
DEFINE CLASS dummyapp AS Custom
PROCEDURE ReadIni
LPARAMETERS tcSection, tcKey
RETURN ''
ENDPROC
PROCEDURE WriteIni
LPARAMETERS tcSection, tcKey, tcValue
RETURN .T.
ENDPROC
ENDDEFINE
*-- Acelasi contract ca oExecutor.oExecute pe parametrul SQL: in productie, un statement
*-- NULL/gol ajunge la SQLEXEC si da eroarea 1466. Aici doar il inregistram.
DEFINE CLASS spionexecutor AS Custom
cEroare = ''
PROCEDURE oExecute
LPARAMETERS tcSql, tcCursor
gnApeluri = gnApeluri + 1
gcSqlPrimit = tcSql
IF ISNULL(m.tcSql) OR EMPTY(NVL(m.tcSql,''))
glSqlNull = .T.
DO PnLog WITH ' >>> executor: SQL ' + IIF(ISNULL(m.tcSql),'NULL','GOL') + ;
' (EMPTY(tcSql)=' + TRANSFORM(EMPTY(m.tcSql)) + ' - garda din oExecute nu il prinde)'
RETURN -1
ENDIF
IF !EMPTY(m.tcCursor) AND USED(m.tcCursor)
USE IN (m.tcCursor)
ENDIF
IF 'VCONFIG_CONT_IREG' $ UPPER(m.tcSql)
CREATE CURSOR (m.tcCursor) (valoare N(10))
INSERT INTO (m.tcCursor) VALUES (0)
RETURN 1
ENDIF
IF 'VJTVA_COLOANE' $ UPPER(m.tcSql)
DO CreeazaJtvaColoaneView WITH m.tcCursor
RETURN 1
ENDIF
IF UPPER(ALLTRIM(NVL(m.tcCursor,''))) == 'RUL_TEMP'
CREATE CURSOR (m.tcCursor) (denumire C(100), codmat C(30), cant N(14,3), ;
pret_val N(18,4), pretd N(18,4), pret N(18,4), pret_lei N(18,4), cont C(10), ;
acont C(20), serie C(30), lot C(30), adata_expirare C(10), proc_disc N(6,2), cota_tva N(6,2))
RETURN 1
ENDIF
IF !EMPTY(m.tcCursor)
CREATE CURSOR (m.tcCursor) (id_temp N(1))
ENDIF
RETURN 1
ENDPROC
PROCEDURE oExecuta
LPARAMETERS tcSql, tcCursor
gnApeluri = gnApeluri + 1
gcSqlPrimit = tcSql
IF ISNULL(m.tcSql) OR EMPTY(NVL(m.tcSql,''))
glSqlNull = .T.
DO PnLog WITH ' >>> executor(oExecuta): SQL ' + IIF(ISNULL(m.tcSql),'NULL','GOL')
RETURN .F.
ENDIF
IF !EMPTY(m.tcCursor)
IF USED(m.tcCursor)
USE IN (m.tcCursor)
ENDIF
IF UPPER(m.tcCursor) == 'CJTVACOL4427'
CREATE CURSOR (m.tcCursor) (id_jtva_coloana N(14))
ELSE
CREATE CURSOR (m.tcCursor) (id_temp N(1))
ENDIF
ENDIF
RETURN .T.
ENDPROC
PROCEDURE oSelect2Value
LPARAMETERS tcSql, toValue
gnApeluri = gnApeluri + 1
gcSqlPrimit = tcSql
IF ISNULL(m.tcSql) OR EMPTY(NVL(m.tcSql,''))
glSqlNull = .T.
DO PnLog WITH ' >>> executor(oSelect2Value): SQL ' + IIF(ISNULL(m.tcSql),'NULL','GOL')
RETURN -1
ENDIF
toValue = ''
RETURN 1
ENDPROC
PROCEDURE oReset
ENDPROC
ENDDEFINE

View File

@@ -0,0 +1,18 @@
# test_repro_partener_scc_null.ps1 - rulare headless (fara harness/screenshots) a testului de
# reproducere pentru dublu click pe "Partener credit" cu contul creditor NULL.
# Rulare: powershell -ExecutionPolicy Bypass -File test_repro_partener_scc_null.ps1
$ErrorActionPreference = 'Stop'
$Teste = $PSScriptRoot
$Prg = Join-Path $Teste 'test_repro_partener_scc_null.prg'
$Fxp = [IO.Path]::ChangeExtension($Prg, '.fxp')
$Log = Join-Path $Teste 'test_repro_partener_scc_null_log.txt'
$Vfp = 'C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe'
Remove-Item $Fxp, $Log -ErrorAction SilentlyContinue
$p = Start-Process -FilePath $Vfp -ArgumentList '-A', '-T', "`"$Prg`"" -PassThru
if (-not $p.WaitForExit(240000)) {
$p.Kill()
throw 'TIMEOUT: testul nu s-a terminat in 240s'
}
if (-not (Test-Path $Log)) { throw "Lipseste logul $Log" }
Get-Content $Log

View File

@@ -0,0 +1,223 @@
* test_repro_anaf_path_nfjson.prg
* REPRODUCERE: in ROAGEST, la alegerea partenerului, banda arata mereu
* "ANAF nu a raspuns - verificare sarita", desi ANAF raspunde 200 pe aceeasi masina.
* Ipoteza testata: SET PATH din Programe\roagest.prg NU contine COMUN\UTILE\NFJSON,
* deci VerificareANAF.Init (validare.prg:1877, "Set Procedure To nfjsonread.prg Additive")
* arunca, CREATEOBJECT('VerificareANAF') esueaza in ANAF_VerificaCuiSingle si clasa de
* esec devine FARA_RASPUNS -> banda gri + serviciul ANAF marcat CAZUT pentru 10 minute.
*
* Scenarii:
* A. path ca in roagest.prg (fara NFJSON) -> CREATEOBJECT esueaza, clasa esec = FARA_RASPUNS
* B. acelasi path + COMUN\UTILE\NFJSON -> verdict ANAF real pentru CUI 13791411 (ARAFURA)
*
* Rulare: powershell -ExecutionPolicy Bypass -File test_repro_anaf_path_nfjson.ps1
SET SAFETY OFF
SET TALK OFF
SET DELETED ON
SET EXACT ON
SET CENTURY ON
SET DATE DMY
SET DECIMALS TO 4
SET NULLDISPLAY TO ''
CLOSE DATABASES
PUBLIC gcUILog, gnAsserts, gnPass
gcUILog = "D:\ROA\ROAGEST\COMUN\utile\Teste\partener_anaf\test_repro_anaf_path_nfjson_log.txt"
STRTOFILE("START " + TTOC(DATETIME()) + CHR(13)+CHR(10), gcUILog)
STORE 0 TO gnAsserts, gnPass
ON ERROR DO PnErr WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()
ON SHUTDOWN QUIT
LOCAL lcCui, llNegasit, lcClasa, loRez, loEx, lcPath, gcAppPath
lcCui = '13791411'
TRY
*----- SET PATH exact ca in Programe\roagest.prg (fara COMUN\UTILE\NFJSON) -----
gcAppPath = "D:\ROA\ROAGEST\"
SET DEFAULT TO (gcAppPath)
lcPath = gcAppPath + 'Date;' + gcAppPath + 'Include;' + gcAppPath + 'FERESTRE;' + ;
gcAppPath + 'GRAFICE;' + gcAppPath + 'CLASE;' + gcAppPath + 'MENIURI;' + ;
gcAppPath + 'PROGRAME;' + gcAppPath + 'RAPOARTE;' + gcAppPath + 'COMUN;' + ;
gcAppPath + 'COMUN\CLASE;' + gcAppPath + 'COMUN\FERESTRE;' + gcAppPath + 'COMUN\PROGRAME;' + ;
gcAppPath + 'COMUN\GRAFICE;' + gcAppPath + 'COMUN\RAPOARTE;' + gcAppPath + 'COMUN\MENIURI;' + ;
gcAppPath + 'COMUN\UTILE\GRIDEXTRAS;' + gcAppPath + 'COMUN\UTILE\CTL32;' + ;
gcAppPath + 'COMUN\UTILE\HPDF;' + gcAppPath + 'COMUN\UTILE\HPDF\REPORTOUTPUT;' + ;
gcAppPath + 'COMUN\UTILE\WEB;' + gcAppPath + 'COMUN\UTILE\EXCEL;' + ;
ADDBS(SUBSTR(gcAppPath,1,RAT([\],gcAppPath,2)))+[COMUNROA\]
SET PATH TO &lcPath
DO PnLog WITH 'SET PATH (ca in roagest.prg) OK'
SET PROCEDURE TO validare.prg
SET PROCEDURE TO ocautare.prg ADDITIVE
SET PROCEDURE TO regex.prg ADDITIVE
DO PnLog WITH 'SET PROCEDURE OK: ' + SET('Procedure')
PUBLIC gnIdUtil, goExecutor, goLog, poLog
gnIdUtil = -3
goExecutor = CREATEOBJECT('executor_spion')
LOCAL lcLogApp
lcLogApp = "D:\ROA\ROAGEST\COMUN\utile\Teste\partener_anaf\test_repro_anaf_path_nfjson_applog.txt"
STRTOFILE('', lcLogApp)
poLog = NEWOBJECT("Log_Mesaje", "Log_Mesaje.prg", "", lcLogApp)
goLog = poLog
*===== A1: CREATEOBJECT('VerificareANAF') pe path-ul din roagest.prg =====
loEx = .NULL.
TRY
LOCAL loVerif
loVerif = CREATEOBJECT('VerificareANAF')
DO PnLog WITH 'A1 CREATEOBJECT(VerificareANAF): OK (nu reproduce)'
CATCH TO loEx
DO PnLog WITH 'A1 CREATEOBJECT(VerificareANAF): EXCEPTIE ' + loEx.Message + ;
' [' + loEx.Procedure + ':' + TRANSFORM(loEx.LineNo) + ']'
ENDTRY
DO PnAssert WITH 'A1 VerificareANAF nu se poate instantia fara NFJSON pe path', !ISNULL(loEx)
*===== A2: fluxul real ANAF_VerificaCuiSingle -> clasa de esec =====
llNegasit = .F.
lcClasa = ''
loRez = ANAF_VerificaCuiSingle(m.lcCui, DATE(), @llNegasit, @lcClasa)
DO PnLog WITH 'A2 ANAF_VerificaCuiSingle: VARTYPE=' + VARTYPE(loRez) + ;
' negasit=' + TRANSFORM(llNegasit) + ' clasa_esec=[' + lcClasa + ']'
DO PnAssert WITH 'A2 clasa esec = FARA_RASPUNS (banda "ANAF nu a raspuns")', lcClasa == 'FARA_RASPUNS'
*===== A3: banda din ocautare - ANAF_StarePartener pe acelasi cod =====
LOCAL llNecesita, lcClasa3, loStare3
llNecesita = .F.
llNegasit = .F.
lcClasa3 = ''
loStare3 = ANAF_StarePartener(m.lcCui, DATE(), .F., @llNecesita, @llNegasit, @lcClasa3, 0)
DO PnLog WITH 'A3 ANAF_StarePartener: VARTYPE=' + VARTYPE(loStare3) + ' clasa_esec=[' + lcClasa3 + ']' + ;
' stare_serviciu=' + ANAF_StareServiciu()
DO PnAssert WITH 'A3 stare serviciu ANAF = CAZUT dupa primul cod', ANAF_StareServiciu() == 'CAZUT'
*===== B: acelasi mediu + COMUN\UTILE\NFJSON pe path =====
SET PATH TO (gcAppPath + 'COMUN\UTILE\NFJSON') ADDITIVE
DO PnLog WITH 'B SET PATH ... COMUN\UTILE\NFJSON ADDITIVE'
RELEASE goCacheANAF_Sesiune
ANAF_SeteazaStareServiciu('NECUNOSCUT', 'reluare scenariu B')
loEx = .NULL.
TRY
LOCAL loVerifB
loVerifB = CREATEOBJECT('VerificareANAF')
DO PnLog WITH 'B1 CREATEOBJECT(VerificareANAF): OK'
CATCH TO loEx
DO PnLog WITH 'B1 CREATEOBJECT(VerificareANAF): EXCEPTIE ' + loEx.Message
ENDTRY
DO PnAssert WITH 'B1 VerificareANAF se instantiaza cu NFJSON pe path', ISNULL(loEx)
llNegasit = .F.
lcClasa = ''
loRez = ANAF_VerificaCuiSingle(m.lcCui, DATE(), @llNegasit, @lcClasa)
IF VARTYPE(loRez) = 'O'
DO PnLog WITH 'B2 ANAF_VerificaCuiSingle: denumire=[' + ALLTRIM(NVL(loRez.denumire, '')) + ;
'] scpTVA=' + TRANSFORM(loRez.scpTVA) + ' clasa_esec=[' + lcClasa + ']'
ELSE
DO PnLog WITH 'B2 ANAF_VerificaCuiSingle: VARTYPE=' + VARTYPE(loRez) + ' clasa_esec=[' + lcClasa + ']'
ENDIF
DO PnAssert WITH 'B2 verdict ANAF primit pentru ' + m.lcCui, VARTYPE(loRez) = 'O'
DO PnAssert WITH 'B3 denumire ANAF = ARAFURA', VARTYPE(loRez) = 'O' AND 'ARAFURA' $ UPPER(ALLTRIM(NVL(loRez.denumire, '')))
*===== C: corpul lui ANAF_VerificaCuiSingle replicat inline, pas cu pas =====
LOCAL loVerifC, loHttpC, lcJson, loParsed, lnSalvate, llNegC, lcClasaC, loRezC
loVerifC = CREATEOBJECT('VerificareANAF')
TRY
loHttpC = ANAF_CreeazaCerereANAF(INT(VAL(m.lcCui)), DATE(), .F.)
lcJson = ALLTRIM(loHttpC.responseText)
DO PnLog WITH 'C1 ANAF_CreeazaCerereANAF: Status=' + TRANSFORM(loHttpC.Status) + ' raspuns(120)=' + LEFT(lcJson, 120)
CATCH TO loEx
lcJson = ''
DO PnLog WITH 'C1 ANAF_CreeazaCerereANAF: EXCEPTIE ' + loEx.Message + ' [' + loEx.Procedure + ':' + TRANSFORM(loEx.LineNo) + ']'
ENDTRY
TRY
loParsed = nfjsonread(m.lcJson)
DO PnLog WITH 'C2 nfjsonread: OK, TYPE=' + VARTYPE(loParsed)
CATCH TO loEx
DO PnLog WITH 'C2 nfjsonread: EXCEPTIE ' + loEx.Message + ' [' + loEx.Procedure + ':' + TRANSFORM(loEx.LineNo) + ']'
ENDTRY
TRY
USE IN (SELECT('crsANAFDiag'))
loVerifC.ParseJsonANAFv8(loParsed, 'crsANAFDiag')
DO PnLog WITH 'C3 ParseJsonANAFv8: OK, RECCOUNT=' + IIF(USED('crsANAFDiag'), TRANSFORM(RECCOUNT('crsANAFDiag')), '-')
CATCH TO loEx
DO PnLog WITH 'C3 ParseJsonANAFv8: EXCEPTIE ' + loEx.Message + ' [' + loEx.Procedure + ':' + TRANSFORM(loEx.LineNo) + ']'
ENDTRY
TRY
lnSalvate = loVerifC.SalveazaIstoricDinCursor('crsANAFDiag', gnIdUtil)
DO PnLog WITH 'C4 SalveazaIstoricDinCursor: OK, salvate=' + TRANSFORM(lnSalvate)
CATCH TO loEx
DO PnLog WITH 'C4 SalveazaIstoricDinCursor: EXCEPTIE ' + loEx.Message + ' [' + loEx.Procedure + ':' + TRANSFORM(loEx.LineNo) + ']'
ENDTRY
TRY
llNegC = .F.
lcClasaC = ''
loRezC = ANAF_VerdictDinCursor('crsANAFDiag', INT(VAL(m.lcCui)), @llNegC, @lcClasaC)
DO PnLog WITH 'C5 ANAF_VerdictDinCursor: VARTYPE=' + VARTYPE(loRezC) + ' negasit=' + TRANSFORM(llNegC) + ;
' clasa=[' + lcClasaC + ']' + IIF(VARTYPE(loRezC) = 'O', ' denumire=[' + ALLTRIM(NVL(loRezC.denumire, '')) + ']', '')
CATCH TO loEx
DO PnLog WITH 'C5 ANAF_VerdictDinCursor: EXCEPTIE ' + loEx.Message + ' [' + loEx.Procedure + ':' + TRANSFORM(loEx.LineNo) + ']'
ENDTRY
*===== D: path-ul REAL, construit din blocul lcPath din Programe\roagest.prg =====
LOCAL lcSursa, lnStart, lnStop, lcBloc, lcScript, lcPathReal, loVerifD, loRezD, lcClasaD, llNegD
lcSursa = FILETOSTR("D:\ROA\ROAGEST\Programe\roagest.prg")
lnStart = ATC("lcPath = gcAppPath + 'Date;'", lcSursa)
lnStop = ATC("COMUNROA\]", SUBSTR(lcSursa, lnStart)) + lnStart - 1
lcBloc = SUBSTR(lcSursa, lnStart, lnStop - lnStart + LEN("COMUNROA\]"))
lcScript = "LPARAMETERS gcAppPath" + CHR(13)+CHR(10) + "LOCAL lcPath" + CHR(13)+CHR(10) + ;
lcBloc + CHR(13)+CHR(10) + "RETURN lcPath"
lcPathReal = EXECSCRIPT(lcScript, gcAppPath)
DO PnLog WITH 'D path din roagest.prg: ' + lcPathReal
RELEASE PROCEDURE nfjsonread.prg, nfjsoncreate.prg
RELEASE goCacheANAF_Sesiune
ANAF_SeteazaStareServiciu('NECUNOSCUT', 'reluare scenariu D')
SET PATH TO &lcPathReal
DO PnAssert WITH 'D1 nfjsonread descarcat inainte de test', !('NFJSONREAD' $ UPPER(SET('Procedure')))
llNegD = .F.
lcClasaD = ''
loRezD = ANAF_VerificaCuiSingle(m.lcCui, DATE(), @llNegD, @lcClasaD)
IF VARTYPE(loRezD) = 'O'
DO PnLog WITH 'D2 ANAF_VerificaCuiSingle pe path-ul real: denumire=[' + ALLTRIM(NVL(loRezD.denumire, '')) + '] clasa_esec=[' + lcClasaD + ']'
ELSE
DO PnLog WITH 'D2 ANAF_VerificaCuiSingle pe path-ul real: VARTYPE=' + VARTYPE(loRezD) + ' clasa_esec=[' + lcClasaD + ']'
ENDIF
DO PnAssert WITH 'D2 verdict ANAF pe path-ul din roagest.prg', VARTYPE(loRezD) = 'O'
DO PnAssert WITH 'D3 fara clasa de esec (banda arata verdictul, nu "ANAF nu a raspuns")', lcClasaD == ''
CATCH TO loEx
DO PnLog WITH 'EXCEPTIE NEPRINSA: ' + loEx.Message + ' [' + loEx.Procedure + ':' + TRANSFORM(loEx.LineNo) + ']'
ENDTRY
DO PnLog WITH 'REZULTAT: ' + TRANSFORM(gnPass) + '/' + TRANSFORM(gnAsserts) + ' PASS'
QUIT
PROCEDURE PnAssert
LPARAMETERS tcNume, tlOk
gnAsserts = gnAsserts + 1
IF tlOk
gnPass = gnPass + 1
ENDIF
DO PnLog WITH IIF(tlOk, 'PASS ', 'FAIL ') + tcNume
ENDPROC
PROCEDURE PnErr
LPARAMETERS tnErr, tcMsg, tcProg, tnLine
DO PnLog WITH 'ON ERROR ' + TRANSFORM(tnErr) + ' [' + tcProg + ':' + TRANSFORM(tnLine) + '] ' + tcMsg
ENDPROC
PROCEDURE PnLog
LPARAMETERS tcMsg
STRTOFILE(TRANSFORM(tcMsg) + CHR(13)+CHR(10), gcUILog, .T.)
ENDPROC
DEFINE CLASS executor_spion AS Custom
*-- tine locul lui goExecutor: salvarea in ISTORIC_CODURI_FISCALE nu face obiectul testului
PROCEDURE oExecuta
LPARAMETERS tcSql, tcAlias
RETURN .T.
ENDPROC
ENDDEFINE

View File

@@ -0,0 +1,18 @@
# test_repro_anaf_path_nfjson.ps1 - rulare headless a testului de reproducere pentru
# "ANAF nu a raspuns - verificare sarita" in ROAGEST (COMUN\UTILE\NFJSON lipsa din SET PATH).
# Rulare: powershell -ExecutionPolicy Bypass -File test_repro_anaf_path_nfjson.ps1
$ErrorActionPreference = 'Stop'
$Teste = $PSScriptRoot
$Prg = Join-Path $Teste 'test_repro_anaf_path_nfjson.prg'
$Fxp = [IO.Path]::ChangeExtension($Prg, '.fxp')
$Log = Join-Path $Teste 'test_repro_anaf_path_nfjson_log.txt'
$Vfp = 'C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe'
Remove-Item $Fxp, $Log -ErrorAction SilentlyContinue
$p = Start-Process -FilePath $Vfp -ArgumentList '-A', '-T', "`"$Prg`"" -PassThru
if (-not $p.WaitForExit(240000)) {
$p.Kill()
throw 'TIMEOUT: testul nu s-a terminat in 240s'
}
if (-not (Test-Path $Log)) { throw "Lipseste logul $Log" }
Get-Content $Log

62
utile/context_watch.ps1 Normal file
View File

@@ -0,0 +1,62 @@
# context_watch.ps1 - cat context ocupa sesiunea curenta Claude Code.
# Citeste ultimul "usage" din transcriptul JSONL al sesiunii (input + cache_read + cache_creation).
# Utilizare:
# - ca hook (PostToolUse): primeste pe stdin JSON-ul hook-ului, cu transcript_path;
# - manual: powershell -File context_watch.ps1 [-TranscriptPath <cale.jsonl>] [-Prag 250000]
# Iese cu 2 si scrie pe stderr cand contextul depaseste pragul (asa ajunge mesajul la agent).
[CmdletBinding()]
param(
[string]$TranscriptPath,
[int]$Prag = 250000,
[int]$PragMax = 275000,
[switch]$Intotdeauna,
[switch]$Stdout # UserPromptSubmit: mesajul se scrie pe stdout si se iese cu 0
)
if (-not $TranscriptPath) {
$stdin = [Console]::In.ReadToEnd()
if ($stdin) {
try { $TranscriptPath = (ConvertFrom-Json $stdin).transcript_path } catch { }
}
}
if (-not $TranscriptPath -or -not (Test-Path $TranscriptPath)) {
$dir = Join-Path $env:USERPROFILE ".claude\projects\$((Get-Location).Path -replace '[:\\/]','-')"
if (Test-Path $dir) {
$f = Get-ChildItem "$dir\*.jsonl" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
if ($f) { $TranscriptPath = $f.FullName }
}
}
if (-not $TranscriptPath -or -not (Test-Path $TranscriptPath)) { exit 0 }
# doar coada fisierului - transcriptul poate avea zeci de MB
$fs = [IO.File]::Open($TranscriptPath, 'Open', 'Read', 'ReadWrite')
try {
$len = [Math]::Min(400KB, $fs.Length)
$fs.Seek(-$len, 'End') | Out-Null
$buf = New-Object byte[] $len
$fs.Read($buf, 0, $len) | Out-Null
} finally { $fs.Close() }
$coada = [Text.Encoding]::UTF8.GetString($buf)
$m = [regex]::Matches($coada, '"usage":\{.*?"output_tokens":\d+')
if ($m.Count -eq 0) { exit 0 }
$ultim = $m[$m.Count - 1].Value
$total = 0
foreach ($camp in @('input_tokens', 'cache_creation_input_tokens', 'cache_read_input_tokens')) {
if ($ultim -match ('"' + $camp + '":(\d+)')) { $total += [int]$Matches[1] }
}
$k = [Math]::Round($total / 1000)
$mesaj = ''
if ($total -ge $PragMax) {
$mesaj = "CONTEXT ${k}k - peste limita de $([Math]::Round($PragMax/1000))k (regula 9): scrie handoff-ul in docs\progres.md si preda sesiunea acum."
} elseif ($total -ge $Prag) {
$mesaj = "CONTEXT ${k}k - peste $([Math]::Round($Prag/1000))k (regula 9): actualizeaza docs\progres.md si pregateste predarea; deleaga la subagenti ce mai ai de citit/testat."
}
if ($mesaj) {
if ($Stdout) { Write-Output $mesaj; exit 0 }
[Console]::Error.WriteLine($mesaj)
exit 2
}
if ($Intotdeauna) { Write-Output "CONTEXT ${k}k" }
exit 0

View File

@@ -0,0 +1,27 @@
# docs_revizie_check.ps1 - reaminteste revizuirea periodica de compactare a documentatiei (regula 12).
# Marker: COMUN\docs\.ultima_revizie (data ultimei revizii, YYYY-MM-DD).
# Utilizare:
# ca hook (SessionStart): powershell -File docs_revizie_check.ps1 -Stdout
# dupa o revizie: powershell -File docs_revizie_check.ps1 -Marcheaza
param(
[int]$Zile = 30,
[switch]$Stdout,
[switch]$Marcheaza
)
$marker = Join-Path (Split-Path $PSScriptRoot -Parent) 'docs\.ultima_revizie'
if ($Marcheaza) {
Set-Content $marker (Get-Date -Format 'yyyy-MM-dd') -Encoding ascii
Write-Output "marcat: $(Get-Content $marker)"
exit 0
}
$ultima = if (Test-Path $marker) { [datetime]::ParseExact((Get-Content $marker -Raw).Trim(), 'yyyy-MM-dd', $null) } else { [datetime]'2000-01-01' }
$vechime = [int]((Get-Date) - $ultima).TotalDays
if ($vechime -lt $Zile) { exit 0 }
$mesaj = "DOCS: ultima revizuire de compactare acum $vechime zile (regula 12). Propune-i utilizatorului o runda pe COMUN\docs si docs\ ale proiectului; dupa aplicare ruleaza docs_revizie_check.ps1 -Marcheaza."
if ($Stdout) { Write-Output $mesaj; exit 0 }
[Console]::Error.WriteLine($mesaj)
exit 2