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:
1
docs/.ultima_revizie
Normal file
1
docs/.ultima_revizie
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2026-08-02
|
||||||
@@ -1,127 +1,127 @@
|
|||||||
# Prompt: căutare și editare în cod VFP (foxbin2prg) — reutilizabil în orice proiect Visual FoxPro
|
# 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
|
**Prompt gata de copiat** pentru Claude Code (sau alt agent), care configurează și folosește
|
||||||
configurează și folosește sistemul `foxbin2prg` ca să poată **căuta** cod-sursă aflat **în interiorul
|
sistemul `foxbin2prg` ca să poată **căuta** cod-sursă aflat **în interiorul fișierelor binare VFP**
|
||||||
fișierelor binare VFP** (`.vcx/.vct`, `.scx/.sct`, `.frx/.frt`, `.mnx/.mnt`, `.dbc/.dct`) într-un
|
(`.vcx/.vct`, `.scx/.sct`, `.frx/.frt`, `.mnx/.mnt`, `.dbc/.dct`) într-un proiect nou — și, pentru
|
||||||
proiect nou — și, pentru `.vcx`/`.scx`, să poată și **modifica** acel cod direct pe text, cu
|
`.vcx`/`.scx`, să poată și **modifica** acel cod direct pe text, cu write-back în binar
|
||||||
write-back în binar (`txt2vcx.ps1`), fără trecere prin IDE-ul VFP.
|
(`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
|
Unealta e partajată, la `D:\ROA\UTIL\foxbin2prg\` — nu se copiază per proiect. Doar spui agentului
|
||||||
spui agentului care e proiectul curent (folderul + fișierul `.pjx`).
|
care e proiectul curent (folderul + fișierul `.pjx`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Cum se folosește
|
## Cum se folosește
|
||||||
|
|
||||||
1. Deschide proiectul VFP în Claude Code.
|
1. Deschide proiectul VFP în Claude Code.
|
||||||
2. Copiază blocul de mai jos în prompt.
|
2. Copiază blocul de mai jos în prompt.
|
||||||
3. Înlocuiește cele **3 valori** marcate `<<...>>` cu datele proiectului tău:
|
3. Înlocuiește cele **3 valori** marcate `<<...>>`:
|
||||||
- `<<RADACINA_PROIECT>>` = folderul rădăcină al proiectului (ex. `D:\ROA\ROAGEST`)
|
- `<<RADACINA_PROIECT>>` = folderul rădăcină al proiectului (ex. `D:\ROA\ROAGEST`)
|
||||||
- `<<FISIER_PJX>>` = calea către `.pjx` (ex. `D:\ROA\ROAGEST\roagest.pjx`)
|
- `<<FISIER_PJX>>` = calea către `.pjx` (ex. `D:\ROA\ROAGEST\roagest.pjx`)
|
||||||
- `<<NUME_PROIECT>>` = etichetă scurtă pentru folderul de cache (ex. `roagest`)
|
- `<<NUME_PROIECT>>` = etichetă scurtă pentru folderul de cache (ex. `roagest`)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ▼▼▼ PROMPT DE COPIAT ▼▼▼
|
## ▼▼▼ PROMPT DE COPIAT ▼▼▼
|
||||||
|
|
||||||
```
|
```
|
||||||
Acest proiect este o aplicație Visual FoxPro 9. O mare parte din cod (proceduri, metode,
|
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
|
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
|
(.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).
|
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
|
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.
|
în reprezentarea lor TEXT (.vc2/.sc2/.fr2/.mn2/.dc2) într-un cache, și apoi caută în cache.
|
||||||
|
|
||||||
PARAMETRII PROIECTULUI CURENT:
|
PARAMETRII PROIECTULUI CURENT:
|
||||||
- Rădăcină proiect: <<RADACINA_PROIECT>>
|
- Rădăcină proiect: <<RADACINA_PROIECT>>
|
||||||
- Fișier proiect (.pjx): <<FISIER_PJX>>
|
- Fișier proiect (.pjx): <<FISIER_PJX>>
|
||||||
- Cache text: D:\ROA\_vfp_textcache\<<NUME_PROIECT>>
|
- 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
|
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
|
.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.
|
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).
|
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):
|
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>>'
|
& '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
|
(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)
|
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
|
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.
|
'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):
|
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.
|
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.
|
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):
|
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>>'
|
& '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).
|
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:
|
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ă
|
a. Investighează pe cache, propune modificarea și AȘTEAPTĂ ACORDUL pe abordare înainte să
|
||||||
editezi ceva.
|
editezi ceva.
|
||||||
b. Refresh cache (PAS 1) dacă a rulat vreo sesiune de IDE de la ultimul refresh (staleness-ul
|
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
|
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
|
de write-back închide COMPLET VFP IDE și exe-ul aplicației — procesele reziduale țin lock
|
||||||
pe binare.
|
pe binare.
|
||||||
c. Editează .vc2/.sc2 BYTE-SAFE: formatul e position-sensitive (nu reformata/reflow linii),
|
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
|
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
|
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ă.
|
ca bytes (PowerShell), conținutul NOU doar ASCII; nu folosi unelte care re-encodează.
|
||||||
d. Write-back:
|
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>>'
|
& '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
|
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
|
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
|
rămâne neatins. Ținte sub COMUN\ cer flag-ul -AllowComun ȘI aprobare explicită — o
|
||||||
modificare acolo afectează toate aplicațiile ROA.
|
modificare acolo afectează toate aplicațiile ROA.
|
||||||
e. Diff lizibil pentru review: extrage binarul vechi din git (git show HEAD:cale > temp, atât
|
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
|
.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
|
compară cu cache-ul editat: git diff --no-index. COMMIT DOAR după ce omul confirmă pe diff
|
||||||
și testează în IDE.
|
și testează în IDE.
|
||||||
|
|
||||||
EXCEPȚII: pentru .mnx (GENMENU) și .frx (fragile la round-trip) nu există write-back — scrie
|
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ă),
|
propunerea de modificare într-un fișier docs/propuneri_<subiect>.md (cod + unde se inserează),
|
||||||
iar aplicarea se face manual în IDE-ul VFP.
|
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
|
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
|
sesiunile următoare rescrie doar ce s-a schimbat. Când citești codul unei metode, dă referințe
|
||||||
fișier:linie din cache.
|
fișier:linie din cache.
|
||||||
```
|
```
|
||||||
|
|
||||||
## ▲▲▲ SFÂRȘIT PROMPT ▲▲▲
|
## ▲▲▲ SFÂRȘIT PROMPT ▲▲▲
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Note pentru adaptare
|
## Note pentru adaptare
|
||||||
|
|
||||||
- `<<NUME_PROIECT>>` îl poți pune orice etichetă scurtă (ex. `roagest`), doar ca numele
|
- `<<NUME_PROIECT>>` poate fi orice etichetă scurtă (ex. `roagest`), unică per proiect (numele
|
||||||
folderului de cache să fie unic per proiect.
|
folderului de cache).
|
||||||
- Ține cache-ul în `D:\ROA\_vfp_textcache\`, adică **în afara** folderului `foxbin2prg`. Motiv:
|
- Ț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
|
`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.
|
`.??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
|
- Scriptul citește lista de fișiere direct din `.pjx`, deci convertește doar ce folosește efectiv
|
||||||
efectiv proiectul (rapid), nu tot `COMUN\`.
|
proiectul (rapid), nu tot `COMUN\`.
|
||||||
- Cache-ul (`D:\ROA\_vfp_textcache\<proiect>`) e regenerabil și e în afara arborelui de versionare
|
- Cache-ul e regenerabil, în afara arborelui de versionare al proiectului (și al clonei
|
||||||
al proiectului (și în afara clonei foxbin2prg) — poate fi șters oricând.
|
foxbin2prg) — poate fi șters oricând.
|
||||||
- Conversia NU necesită IDE-ul VFP deschis (folosește `FoxBin2Prg.EXE` compilat).
|
- 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`
|
- 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.
|
ț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ă
|
- 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.
|
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,
|
- 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`.
|
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
|
- 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).
|
`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`.
|
- 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`,
|
- Tabel corespondență binar → text: `.vcx`→`.vc2`, `.scx`→`.sc2`, `.frx`→`.fr2`, `.mnx`→`.mn2`,
|
||||||
`.dbc`→`.dc2`, `.lbx`→`.lb2`.
|
`.dbc`→`.dc2`, `.lbx`→`.lb2`.
|
||||||
|
|||||||
@@ -1,139 +1,131 @@
|
|||||||
# Căutare în codul din librăriile/formele VFP (`.vcx`/`.vct`, `.scx`/`.sct`, ...)
|
# 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,
|
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).
|
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
|
Căutare de cod-sursă (proceduri, metode, parametri) care **nu** stă în `.prg`, ci în interiorul
|
||||||
în interiorul fișierelor binare VFP: librării de clase (`.vcx`+`.vct`), forme (`.scx`+`.sct`),
|
binarelor VFP: librării de clase (`.vcx`+`.vct`), forme (`.scx`+`.sct`), rapoarte (`.frx`+`.frt`),
|
||||||
rapoarte (`.frx`+`.frt`), meniuri (`.mnx`+`.mnt`), baze de date (`.dbc`+`.dct`).
|
meniuri (`.mnx`+`.mnt`), baze de date (`.dbc`+`.dct`).
|
||||||
|
|
||||||
## De ce e nevoie de asta
|
## De ce e nevoie de asta
|
||||||
|
|
||||||
Un `.vcx` este de fapt o **tabelă DBF**: codul metodelor stă în câmpuri memo în `.vct`. Un
|
Un `.vcx` e o **tabelă DBF**: codul metodelor stă în câmpuri memo în `.vct`. `grep` direct pe
|
||||||
`grep` direct pe `.vct` *găsește* textul, dar îl vede ca fișier binar (octeți `\0` între linii),
|
`.vct` găsește textul dar ca binar (octeți `\0` între linii), fără numere de linie și greu de
|
||||||
fără numere de linie utile și greu de citit. Soluția: convertim binarul în reprezentarea lui
|
citit. Soluția: convertim binarul în reprezentarea lui **TEXT** (`.vc2`, `.sc2`, …) — PRG-style
|
||||||
**TEXT** (`.vc2`, `.sc2`, …) — un PRG-style lizibil, cu metode sortate alfabetic — și căutăm
|
lizibil, metode sortate alfabetic — și căutăm în text cu `grep`/`Grep`.
|
||||||
în text cu `grep`/`Grep`.
|
|
||||||
|
> **Regula de aur:** textul generat e **doar pentru citire/căutare**, CU O EXCEPȚIE: pentru
|
||||||
> **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
|
||||||
> `.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
|
||||||
> `PROMPT_cautare_vfp.md` pasul 3 pentru fluxul complet (ordine obligatorie, encoding,
|
> `.frx`/`.mnx`/`.dbc` nu există write-back — modificările se fac tot în **IDE-ul VFP**.
|
||||||
> fidelity check). Pentru `.frx`/`.mnx`/`.dbc` nu există write-back — modificările se fac tot
|
|
||||||
> în **IDE-ul VFP**.
|
## Unelte disponibile (verificate)
|
||||||
|
|
||||||
## Unelte disponibile (verificate)
|
| Unealtă | Cale | Rol | Recomandare |
|
||||||
|
|---|---|---|---|
|
||||||
| 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 |
|
||||||
| **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 |
|
| prgtovcx | `D:\ROA\UTIL\prgtovcx\prgtovcx.PRG` | Invers: `.prg` → `.vcx` | **Nu** pentru căutare (direcție opusă) |
|
||||||
| 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, text mai fidel decât vcx2prg.
|
||||||
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: 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`
|
||||||
> Dacă `FoxBin2Prg.EXE` lipsește, se compilează o singură dată: deschide
|
> (deja în folder).
|
||||||
> `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`
|
||||||
|
|
||||||
## 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.
|
||||||
`D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1` automatizează tot: copiază binarul + memo-ul într-un
|
**Incremental** (sare peste ce e deja la zi).
|
||||||
**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).
|
```powershell
|
||||||
|
# DOAR fișierele proiectului curent (recomandat, rapid) -> cache text propriu
|
||||||
Parametrizează scriptul cu proiectul curent și un cache separat per proiect (nu amesteca
|
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
|
||||||
cache-urile mai multor proiecte ROA):
|
-Project '<RADACINA_PROIECT>\<proiect>.pjx' -ProjectRoot '<RADACINA_PROIECT>' `
|
||||||
|
-CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>'
|
||||||
```powershell
|
|
||||||
# DOAR fișierele proiectului curent (recomandat, rapid) -> cache text propriu
|
# include și rapoartele (.frx) și meniurile (.mnx)
|
||||||
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
|
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
|
||||||
-Project '<RADACINA_PROIECT>\<proiect>.pjx' -ProjectRoot '<RADACINA_PROIECT>' `
|
-Project '<RADACINA_PROIECT>\<proiect>.pjx' -ProjectRoot '<RADACINA_PROIECT>' `
|
||||||
-CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>'
|
-CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>' -Types vcx,scx,frx,mnx
|
||||||
|
|
||||||
# include și rapoartele (.frx) și meniurile (.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 `
|
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source '<RADACINA_PROIECT>\COMUN\clase\caut.vcx'
|
||||||
-Project '<RADACINA_PROIECT>\<proiect>.pjx' -ProjectRoot '<RADACINA_PROIECT>' `
|
|
||||||
-CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>' -Types vcx,scx,frx,mnx
|
# rebuild curat (șterge cache-ul întâi) / forțează reconversia
|
||||||
|
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
|
||||||
# conversie punctuală a unui fișier sau folder (chiar dacă NU e în proiect, ex. o clasă din COMUN)
|
-Project '<RADACINA_PROIECT>\<proiect>.pjx' -ProjectRoot '<RADACINA_PROIECT>' `
|
||||||
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source '<RADACINA_PROIECT>\COMUN\clase\caut.vcx'
|
-CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>' -Clean
|
||||||
|
```
|
||||||
# rebuild curat (șterge cache-ul întâi) / forțează reconversia
|
|
||||||
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
|
Exemplu (ROAAUTO):
|
||||||
-Project '<RADACINA_PROIECT>\<proiect>.pjx' -ProjectRoot '<RADACINA_PROIECT>' `
|
|
||||||
-CacheRoot 'D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>' -Clean
|
```powershell
|
||||||
```
|
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
|
||||||
|
-Project D:\ROA\ROAAUTO\roaauto.pjx -ProjectRoot D:\ROA\ROAAUTO `
|
||||||
Exemplu concret (ROAAUTO):
|
-CacheRoot D:\ROA\UTIL\foxbin2prg\_textcache_roaauto
|
||||||
|
```
|
||||||
```powershell
|
|
||||||
powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
|
Rezultatul ajunge în cache, cu aceeași structură de directoare ca proiectul (ex.:
|
||||||
-Project D:\ROA\ROAAUTO\roaauto.pjx -ProjectRoot D:\ROA\ROAAUTO `
|
`_textcache_roaauto\Clase\odevize.vc2`, `_textcache_roaauto\comun\clase\_frm_base.vc2`). Apoi:
|
||||||
-CacheRoot D:\ROA\UTIL\foxbin2prg\_textcache_roaauto
|
|
||||||
```
|
```bash
|
||||||
|
grep -rn "PROCEDURE do_calcul_tarife" "D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>"
|
||||||
Rezultatul ajunge în cache-ul indicat, cu aceeași structură de directoare ca proiectul (ex.:
|
grep -rln "factura_salvare" "D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>" # ce clase ating subiectul
|
||||||
`_textcache_roaauto\Clase\odevize.vc2`, `_textcache_roaauto\comun\clase\_frm_base.vc2`). Apoi:
|
```
|
||||||
|
|
||||||
```bash
|
Flux tipic: rulează scriptul o dată (populează cache-ul), apoi caută cu `Grep` în cache. La
|
||||||
# cu unealta Grep (preferat) sau grep:
|
sesiuni următoare rescrie doar ce s-a schimbat (incremental). Pentru o librărie din `COMUN\` care
|
||||||
grep -rn "PROCEDURE do_calcul_tarife" "D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>"
|
nu e în proiect, convertește-o punctual cu `-Source`.
|
||||||
grep -rln "factura_salvare" "D:\ROA\UTIL\foxbin2prg\_textcache_<nume_proiect>" # ce clase ating subiectul
|
|
||||||
```
|
## Alternativă manuală (fără script)
|
||||||
|
|
||||||
Flux tipic pentru o problemă: rulează scriptul cu parametrii de mai sus o dată (populează
|
FoxBin2Prg scrie textul **lângă sursă**. Ca să nu murdărești folderul de clase al proiectului,
|
||||||
cache-ul), apoi caută cu `Grep` în cache. La sesiuni următoare rescrie doar ce s-a schimbat
|
copiază perechea binar+memo într-un folder temporar și convertește acolo:
|
||||||
(incremental). Dacă ai nevoie de o librărie din `COMUN\` care nu e în proiect, convertește-o
|
|
||||||
punctual cu `-Source`.
|
```powershell
|
||||||
|
# .vcx -> .vc2 (cType gol = extensia decide direcția BIN2PRG)
|
||||||
## Alternativă manuală (fără script)
|
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'
|
||||||
FoxBin2Prg scrie textul **lângă sursă**. Ca să nu murdărești folderul de clase al proiectului,
|
# => D:\tmp\odevize.vc2
|
||||||
copiază perechea binar+memo într-un folder temporar și convertește acolo:
|
```
|
||||||
|
|
||||||
```powershell
|
Poziții parametri: `fișier, cType, cTextName, lGenText, cDontShowErrors=1, cDebug=0,
|
||||||
# .vcx -> .vc2 (cType gol = extensia decide direcția BIN2PRG)
|
cDontShowProgress=1`. **Lasă `cType` gol** — extensia (`.vcx`) determină direcția. (Nu da explicit
|
||||||
Copy-Item D:\ROA\<proiect>\Clase\odevize.vcx, D:\ROA\<proiect>\Clase\odevize.vct D:\tmp\
|
`"BIN2PRG"` pentru un singur fișier: în acel mod EXE-ul așteaptă un *director*.)
|
||||||
& 'D:\ROA\UTIL\foxbin2prg\FoxBin2Prg.EXE' 'D:\tmp\odevize.vcx' '' '' '' '1' '0' '1'
|
|
||||||
# => D:\tmp\odevize.vc2
|
Detalii complete de parametri: `D:\ROA\UTIL\foxbin2prg\docs\FoxBin2Prg_Run.md`.
|
||||||
```
|
|
||||||
|
## Soluție rapidă „murdară" (un singur fișier, fără conversie)
|
||||||
Pozițiile parametrilor folosite: `fișier, cType, cTextName, lGenText, cDontShowErrors=1,
|
|
||||||
cDebug=0, cDontShowProgress=1`. **Lasă `cType` gol** — extensia (`.vcx`) determină direcția.
|
Pentru „există metoda X undeva în librărie?", `grep` merge direct pe `.vct` (îl vede ca binar, dar
|
||||||
(Nu da explicit `"BIN2PRG"` pentru un singur fișier: în acel mod EXE-ul așteaptă un *director*.)
|
găsește potrivirile):
|
||||||
|
|
||||||
Detalii complete de parametri: `D:\ROA\UTIL\foxbin2prg\docs\FoxBin2Prg_Run.md`.
|
```bash
|
||||||
|
grep -c "PROCEDURE" "D:\ROA\<proiect>\Clase\odevize.VCT"
|
||||||
## Soluție rapidă „murdară" (un singur fișier, fără conversie)
|
grep -a -o "PROCEDURE [a-zA-Z0-9_]*" "D:\ROA\<proiect>\Clase\odevize.VCT"
|
||||||
|
```
|
||||||
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):
|
Bun pentru „da/nu" și nume de metode; pentru corp/context, folosește conversia în text.
|
||||||
|
|
||||||
```bash
|
## Corespondență extensii binar → text
|
||||||
grep -c "PROCEDURE" "D:\ROA\<proiect>\Clase\odevize.VCT"
|
|
||||||
grep -a -o "PROCEDURE [a-zA-Z0-9_]*" "D:\ROA\<proiect>\Clase\odevize.VCT"
|
| Container | Binar (+memo) | Text |
|
||||||
```
|
|---|---|---|
|
||||||
|
| Librărie clase | `.vcx` + `.vct` | `.vc2` |
|
||||||
Bun pentru „da/nu" și nume de metode; pentru citit corpul/contextul, folosește conversia în text.
|
| Formă | `.scx` + `.sct` | `.sc2` |
|
||||||
|
| Raport | `.frx` + `.frt` | `.fr2` |
|
||||||
## Corespondență extensii binar → text
|
| Etichetă | `.lbx` + `.lbt` | `.lb2` |
|
||||||
|
| Meniu | `.mnx` + `.mnt` | `.mn2` |
|
||||||
| Container | Binar (+memo) | Text |
|
| Bază de date | `.dbc` + `.dct` | `.dc2` |
|
||||||
|---|---|---|
|
|
||||||
| Librărie clase | `.vcx` + `.vct` | `.vc2` |
|
## Note
|
||||||
| Formă | `.scx` + `.sct` | `.sc2` |
|
|
||||||
| Raport | `.frx` + `.frt` | `.fr2` |
|
- Codul aplicației stă mai ales în `Clase\*.vcx`; multe `.vcx`-uri sunt în `COMUN\` (framework
|
||||||
| Etichetă | `.lbx` + `.lbt` | `.lb2` |
|
partajat între toate aplicațiile ROA — vezi `CLAUDE.md` per proiect).
|
||||||
| Meniu | `.mnx` + `.mnt` | `.mn2` |
|
- Cache-ul text e regenerabil, în afara arborelui SVN/git al proiectului — poate fi șters oricând.
|
||||||
| Bază de date | `.dbc` + `.dct` | `.dc2` |
|
- 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
|
||||||
## Note
|
editarea `.sc2`/`.vc2` (nu doar la căutare).
|
||||||
|
|
||||||
- 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).
|
|
||||||
|
|||||||
@@ -1,82 +1,71 @@
|
|||||||
# Capcană: corupere diacritice la editarea `.sc2`/`.vc2` (encoding cp1252)
|
# Capcană: corupere diacritice la editarea `.sc2`/`.vc2` (encoding cp1252)
|
||||||
|
|
||||||
Partajat între proiectele ROA* (similar cu `PROMPT_cautare_vfp.md` din acest folder) — capcana
|
Partajat între proiectele ROA* — capcana ține de formatul `.sc2`/`.vc2` produs de FoxBin2Prg,
|
||||||
ține de formatul `.sc2`/`.vc2` produs de FoxBin2Prg, nu de un proiect anume.
|
nu de un proiect anume.
|
||||||
|
|
||||||
Descoperit de 2 ori în aceeași sesiune (2026-07-10, în ROAAUTO): odată în
|
## De ce se întâmplă
|
||||||
`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
|
Fișierele `.sc2`/`.vc2` sunt **cp1252** (Windows-1252), nu UTF-8 (vezi antetul: `CPID="1252"`).
|
||||||
nu scrie cp1252 nativ, și a corupt TOATE caracterele cu diacritice din fișier, nu doar linia
|
Dacă un editor/tool citește fișierul ca UTF-8, fiecare byte >= 0x80 (diacritic) devine invalid
|
||||||
pe care voia s-o schimbe.
|
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
|
||||||
## De ce se întâmplă
|
FoxBin2Prg la write-back), apar ca `�`. Caracterul original e **ireversibil pierdut**
|
||||||
|
(recuperabil DOAR din altă sursă: git history, backup).
|
||||||
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
|
Codebase-ul ROA "reciclează" caractere cp1252 fără echivalent direct pentru Ș/ă/ț:
|
||||||
(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
|
| Literă românească | Caracter folosit (cp1252) | Byte |
|
||||||
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
|
| ă | ã (a-tilde) | `0xE3` |
|
||||||
**ireversibil pierdut** (nu mai există în fișier sub nicio formă) — recuperabil DOAR din altă
|
| Ă | Ã | `0xC3` |
|
||||||
sursă (git history, backup).
|
| ț | þ (thorn minuscul) | `0xFE` |
|
||||||
|
| Ș (majusculă) | ª (ordinal masculin) | `0xAA` |
|
||||||
Codebase-ul ROA folosește un hack vechi de "reciclare" a unor caractere cp1252 needependente
|
| ș (minusculă) | º (ordinal feminin) | `0xBA` |
|
||||||
de Ș/ă/ț (care nu au echivalent direct în cp1252) pentru diacritice românești:
|
| î, â | î, â (native cp1252) | `0xEE`, `0xE2` |
|
||||||
|
|
||||||
| Literă românească | Caracter folosit (cp1252) | Byte |
|
Par "gunoi"/typo într-un editor UTF-8 (`ã`, `þ`, `ª`, `º`) — **sunt corecte, nu le "corecta"
|
||||||
|---|---|---|
|
fără să verifici encoding-ul.**
|
||||||
| ă | ã (a-tilde) | `0xE3` |
|
|
||||||
| Ă | Ã | `0xC3` |
|
## Cum se verifică dacă un fișier `.sc2`/`.vc2` e corupt
|
||||||
| ț | þ (thorn minuscul) | `0xFE` |
|
|
||||||
| Ș (majusculă) | ª (ordinal masculin) | `0xAA` |
|
```powershell
|
||||||
| ș (minusculă) | º (ordinal feminin) | `0xBA` |
|
$bytes = [System.IO.File]::ReadAllBytes("<path>.vc2")
|
||||||
| î, â | î, â (existente nativ în cp1252) | `0xEE`, `0xE2` |
|
$text = [System.Text.Encoding]::GetEncoding(1252).GetString($bytes)
|
||||||
|
$text -split "`r`n" | Select-String ([char]0xFFFD) # cauta caracterul de replacement
|
||||||
Aceste caractere par "gunoi"/typo la prima vedere într-un editor UTF-8 (`ã`, `þ`, `ª`, `º`) —
|
```
|
||||||
**sunt corecte, nu le "corecta" fără să verifici encoding-ul.**
|
|
||||||
|
Dacă apare `�` (sau `$text` conține U+FFFD) — fișierul are corupere de encoding.
|
||||||
## Cum se verifică dacă un fișier `.sc2`/`.vc2` e corupt
|
|
||||||
|
## Cum se repară
|
||||||
```powershell
|
|
||||||
$bytes = [System.IO.File]::ReadAllBytes("<path>.vc2")
|
1. **Nu edita orbește peste corupere** — caracterul original e deja pierdut din fișierul curent.
|
||||||
$text = [System.Text.Encoding]::GetEncoding(1252).GetString($bytes)
|
2. Dacă corupera s-a întâmplat într-o sesiune anterioară necomisă (HEAD-ul git încă e curat):
|
||||||
$text -split "`r`n" | Select-String ([char]0xFFFD) # cauta caracterul de replacement
|
recuperează originalul convertind binarul din HEAD în text:
|
||||||
```
|
```bash
|
||||||
|
git show HEAD:<cale>.vcx > /tmp/head.vcx
|
||||||
Dacă apare `�` (sau `$text` conține U+FFFD) în output — fișierul are corupere de encoding.
|
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
|
||||||
## Cum se repară
|
```
|
||||||
|
apoi decodează ambele fișiere (HEAD curat + curent corupt) ca cp1252 și compară linie cu
|
||||||
1. **Nu edita orbește peste corupere** — caracterul original e deja pierdut din fișierul
|
linie (PowerShell, nu `diff`/Bash direct — nu decodează cp1252 corect la afișare, deși
|
||||||
curent.
|
detectează totuși diferența de octeți).
|
||||||
2. Dacă fișierul e sub control de versiune (git) și corupera s-a întâmplat **într-o sesiune
|
3. Reconstruiește fișierul text pornind de la versiunea HEAD (curată), reaplicând DOAR
|
||||||
anterioară necomisă** (deci HEAD-ul git încă are versiunea curată): recuperează originalul
|
modificările intenționate din sesiunea curentă (nu invers — nu cârpi fișierul corupt
|
||||||
convertind binarul din HEAD în text și comparând:
|
caracter cu caracter).
|
||||||
```bash
|
4. Scrie rezultatul înapoi ca bytes cp1252
|
||||||
git show HEAD:<cale>.vcx > /tmp/head.vcx
|
(`[System.Text.Encoding]::GetEncoding(1252).GetBytes(...)`), NU ca string UTF-8/`Out-File`
|
||||||
git show HEAD:<cale>.vct > /tmp/head.vct # (sau .VCT, dupa caz)
|
implicit.
|
||||||
powershell -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source /tmp/head.vcx -CacheRoot /tmp/head_out
|
5. Rulează write-back (`txt2vcx.ps1 -Force`) și verifică fidelity check = zero diferențe.
|
||||||
```
|
|
||||||
apoi decodează ambele fișiere (HEAD curat + curent corupt) ca cp1252 și compară linie cu
|
## Cum se evită pe viitor
|
||||||
linie (PowerShell, nu `diff` direct — `diff`/Bash nu decodează cp1252 corect pentru afișare,
|
|
||||||
deși detectează totuși diferența de octeți).
|
Când editezi `.sc2`/`.vc2` cu tool-uri text (Read/Edit/Write), verifică întâi dacă fișierul
|
||||||
3. Reconstruiește fișierul text pornind de la versiunea HEAD (curată), și reaplică DOAR
|
conține diacritice (`ã`, `þ`, `ª`, `º`, `î`, `â` etc.) — dacă da, **orice rescrie completă
|
||||||
modificările intenționate din sesiunea curentă peste ea (nu invers — nu încerca să "cârpești"
|
trebuie făcută la nivel de octeți cu encoding cp1252 explicit**, nu presupunând UTF-8.
|
||||||
fișierul corupt caracter cu caracter, e mai sigur să repornești de la baza curată).
|
Editările punctuale (Edit tool, string replace) sunt sigure DOAR dacă tool-ul păstrează restul
|
||||||
4. Scrie rezultatul înapoi ca bytes cp1252 (`[System.Text.Encoding]::GetEncoding(1252).GetBytes(...)`),
|
fișierului byte-identic (nu rescrie tot fișierul reîncodat).
|
||||||
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.
|
## Vezi și
|
||||||
|
|
||||||
## Cum se evită pe viitor
|
`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).
|
||||||
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).
|
|
||||||
|
|||||||
@@ -1,65 +1,55 @@
|
|||||||
# Capcană: `ALTER TABLE` pe cursorul întors de `goExecutor.oExecute()`
|
# Capcană: `ALTER TABLE` pe cursorul întors de `goExecutor.oExecute()`
|
||||||
|
|
||||||
Partajat între proiectele ROA* — `goExecutor` (clasa `oExecutor`, definită în
|
Partajat între proiectele ROA* — `goExecutor` (clasa `oExecutor`, definită în
|
||||||
`COMUN/programe/oproceduri_comune.prg`, metoda `oExecute`) e utilitarul standard pentru
|
`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*.
|
interogări SQL pass-through (`SQLExec`) către Oracle, folosit peste tot în codul ROA*.
|
||||||
|
|
||||||
## Ce nu funcționează
|
## Ce nu funcționează
|
||||||
|
|
||||||
```foxpro
|
```foxpro
|
||||||
lnSucces = goExecutor.oExecute(lcSql, lcCursor)
|
lnSucces = goExecutor.oExecute(lcSql, lcCursor)
|
||||||
...
|
...
|
||||||
ALTER TABLE (lcCursor) ADD COLUMN coloananoua L && <- pică
|
ALTER TABLE (lcCursor) ADD COLUMN coloananoua L && <- pică
|
||||||
```
|
```
|
||||||
|
|
||||||
Cursorul întors de `oExecute()` (rezultatul unui `SQLExec`) poate refuza comenzi DDL
|
Cursorul întors de `oExecute()` poate refuza comenzi DDL ulterioare, cu erori în lanț
|
||||||
ulterioare, cu erori în lanț (descoperite empiric, în această ordine, în ROAAUTO
|
(descoperite empiric, în această ordine):
|
||||||
`autopass_cursor_comenzi`/`autopass_cursor_operatii`):
|
|
||||||
|
1. `Function is not supported on remote tables.` — pe `ALTER TABLE` direct pe cursorul original.
|
||||||
1. `Function is not supported on remote tables.` — pe `ALTER TABLE` direct pe cursorul
|
2. Chiar și după rematerializare (`SELECT * FROM (cursor) INTO CURSOR (acelasi_nume) READWRITE`)
|
||||||
original.
|
→ `Alias name is already in use.` (sursa și ținta nu pot avea același nume).
|
||||||
2. Chiar și după o încercare de rematerializare (`SELECT * FROM (cursor) INTO CURSOR
|
3. Cu alias scratch diferit ca țintă → tot `Invalid operation for the cursor.` pe `ALTER TABLE`,
|
||||||
(acelasi_nume) READWRITE`) → `Alias name is already in use.` (sursa și ținta nu pot
|
chiar dacă țintă ar trebui să fie deja un cursor local obișnuit.
|
||||||
avea același nume într-un `SELECT...INTO CURSOR`).
|
|
||||||
3. Cu un alias scratch diferit ca țintă (`SELECT * FROM (cursor) INTO CURSOR
|
## Ce funcționează
|
||||||
(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
|
**Nu folosi `ALTER TABLE` deloc pe rezultatul unui `oExecute()`.** Include coloanele
|
||||||
obișnuit.
|
suplimentare direct în `SELECT`-ul de rematerializare, ca expresii literale alături de `*`
|
||||||
|
(VFP suportă `SELECT *, expr AS coloana FROM ...`):
|
||||||
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
|
```foxpro
|
||||||
funcțiile AUTOPASS.
|
lcCursorRaw = lcCursor + '_raw'
|
||||||
|
IF USED(lcCursorRaw)
|
||||||
## Ce funcționează
|
USE IN (lcCursorRaw)
|
||||||
|
ENDIF
|
||||||
**Nu folosi `ALTER TABLE` deloc pe rezultatul unui `oExecute()`.** Include coloanele
|
|
||||||
suplimentare direct în `SELECT`-ul de rematerializare, ca expresii literale alături de `*`
|
lnSucces = goExecutor.oExecute(lcSql, lcCursorRaw)
|
||||||
(VFP suportă `SELECT *, expr AS coloana FROM ...`):
|
IF lnSucces < 0
|
||||||
|
* tratare eroare, RETURN
|
||||||
```foxpro
|
ENDIF
|
||||||
lcCursorRaw = lcCursor + '_raw'
|
|
||||||
IF USED(lcCursorRaw)
|
SELECT *, .F. AS coloananoua, SPACE(100) AS altacoloana ;
|
||||||
USE IN (lcCursorRaw)
|
FROM (lcCursorRaw) INTO CURSOR (lcCursor) READWRITE
|
||||||
ENDIF
|
USE IN (lcCursorRaw)
|
||||||
|
|
||||||
lnSucces = goExecutor.oExecute(lcSql, lcCursorRaw)
|
* de-aici incolo doar REPLACE (date), NICIODATA ALTER TABLE (structura) pe (lcCursor)
|
||||||
IF lnSucces < 0
|
```
|
||||||
* tratare eroare, RETURN
|
|
||||||
ENDIF
|
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),
|
||||||
SELECT *, .F. AS coloananoua, SPACE(100) AS altacoloana ;
|
doar comanda imediat următoare unui `oExecute()` e restricționată.
|
||||||
FROM (lcCursorRaw) INTO CURSOR (lcCursor) READWRITE
|
|
||||||
USE IN (lcCursorRaw)
|
## Vezi și
|
||||||
|
|
||||||
* de-aici incolo doar REPLACE (date), NICIODATA ALTER TABLE (structura) pe (lcCursor)
|
Exemplu complet aplicat: ROAAUTO, `Programe/oproceduri_autopass.prg`,
|
||||||
```
|
`autopass_cursor_comenzi()`/`autopass_cursor_operatii()`.
|
||||||
|
|
||||||
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()`.
|
|
||||||
|
|||||||
21
docs/conventie_null_vfp.md
Normal file
21
docs/conventie_null_vfp.md
Normal 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.`.
|
||||||
@@ -1,64 +1,53 @@
|
|||||||
# Convenție UX pentru formulare VFP (preferința lui Marius, valabilă pe toate proiectele ROA*)
|
# 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`
|
Partajat între proiectele ROA* — `COMUN\` e clonat/sincronizat în fiecare aplicație ROA, e locul
|
||||||
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.
|
||||||
corect pentru o convenție de design care nu ține de un singur proiect.
|
|
||||||
|
## Ce înseamnă in practică, pe proprietăți VFP
|
||||||
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,
|
- **Fiecare grup funcțional pe rândul lui**, nu înghesuit pe același `Top` cu altul fără
|
||||||
butoane grupate la margini, fără elemente lipite unele de altele.
|
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
|
||||||
## Ce înseamnă in practică, pe proprietăți VFP
|
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
|
||||||
- **Fiecare grup funcțional pe rândul lui** — nu înghesui controale fără legătură directă pe
|
lipite imediat după textbox-ul pe care îl controlează — altfel nu se disting ca acțiune
|
||||||
același `Top`. Ex: rândul de perioadă (date + Actualizează) separat de rândul de
|
separată de câmpul de input.
|
||||||
statistici (Declarabile/Transmise/Blocate), separat de panoul de configurare.
|
- **Acțiunea principală + oprirea ei alăturate** (ex. Transmite + Renunță), nu împrăștiate în
|
||||||
- **Spațiere vizibilă între grupuri, strânsă în interiorul unui grup** — butoane din
|
altă parte a rândului.
|
||||||
aceeași acțiune (ex. Validează dry-run → Transmite → Renunță) la 6-10px unele de altele;
|
- **Un singur rând de acțiuni cât se poate** — un rând orizontal in loc de rânduri noi
|
||||||
gap de 20-30px față de următorul grup funcțional (ex. Selectează tot vs. grupul
|
dedesubt; formele rămân compacte pe verticală.
|
||||||
Validare/Transmitere vs. Actualizează statusuri).
|
- **Caption-uri scurte, sentence case, nu ALL CAPS** — ex. "Transmite" nu "TRANSMITE". ALL
|
||||||
- **Butoanele secundare/de configurare aliniate la marginea din dreapta a containerului**,
|
CAPS/text lung pe un buton citește ca zgomot, nu ca ierarhie.
|
||||||
nu lipite imediat după textbox-ul pe care îl controlează — altfel nu se disting vizual ca
|
- **Culoare = semnal, nu decor** — doar pentru acțiuni cu semnificație clară (verde =
|
||||||
acțiune separată de câmpul de input.
|
pozitiv/transmite, roșu = oprire/pericol, albastru = navigare/link extern); restul butoanelor
|
||||||
- **Acțiunea principală + oprirea ei alăturate** — un buton de tip "Renunță/Oprește" trebuie
|
rămân stilul implicit din `_baza.vcx`.
|
||||||
poziționat lângă acțiunea pe care o anulează (ex. Transmite + Renunță), nu împrăștiat în
|
|
||||||
altă parte a rândului.
|
## Clase de controale (confirmat de Marius, 24.07.2026, pe frm_verif_partener_anaf ROACONT)
|
||||||
- **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;
|
- **Intotdeauna controale din `_baza.vcx`, nu controale native VFP** — orice grid, label,
|
||||||
păstrează formele compacte pe verticală.
|
textbox, checkbox etc. dintr-un formular nou se bazeaza pe clasa corespunzatoare din
|
||||||
- **Caption-uri scurte, sentence case, nu ALL CAPS** — ex. "Transmite" nu "TRANSMITE";
|
`COMUN\clase\_baza.vcx`, nu pe clasa nativa Visual FoxPro. Clasele din `_baza.vcx` au
|
||||||
"Dashboard AutoPass" nu "Deschide dashboard AUTOPASS". ALL CAPS/text lung pe un buton
|
fontul default **Arial 10** — nu se suprascrie FontName pe controale (explicit: fara
|
||||||
citește ca zgomot, nu ca ierarhie.
|
Arial Narrow).
|
||||||
- **Culoare = semnal, nu decor** — folosește culoare distinctă doar pentru acțiuni cu
|
- **Butoanele de inchidere/confirmare stau in bara de titlu**, din `cmd_butoane.vcx` —
|
||||||
semnificație clară (verde = acțiune pozitivă/transmite, roșu = oprire/pericol, albastru =
|
modelul Renunt/Termin (clasa de forma `frm_termin_renunt` din `_frm_child.vcx` le aduce
|
||||||
navigare/deschidere link extern); restul butoanelor rămân stilul implicit din `_baza.vcx`.
|
deja). Nu se dubleaza aceste actiuni cu butoane in corpul formei.
|
||||||
|
- **Actiunile care au corespondent `but_*` in `cmd_butoane.vcx`** (Nou/Adauga, Modifica,
|
||||||
## Clase de controale (confirmat de Marius, 24.07.2026, pe frm_verif_partener_anaf ROACONT)
|
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.
|
||||||
- **Intotdeauna controale din `_baza.vcx`, nu controale native VFP** — orice grid, label,
|
- **Doar actiunile FARA corespondent `but_*`** primesc butoane pe clasele `cmd_*` din
|
||||||
textbox, checkbox etc. dintr-un formular nou se bazeaza pe clasa corespunzatoare din
|
`cmd_butoane.vcx` (ex. `cmd_executa`) — nu clase improvizate si nu CommandButton nativ.
|
||||||
`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
|
## Vocabular
|
||||||
Arial Narrow).
|
|
||||||
- **Butoanele de inchidere/confirmare stau in bara de titlu**, din `cmd_butoane.vcx` —
|
Funcțional, compact, aerisit, minimalist, grupat, ușor de înțeles de utilizatori, modern —
|
||||||
modelul Renunt/Termin (clasa de forma `frm_termin_renunt` din `_frm_child.vcx` le aduce
|
asta e reperul calitativ pentru orice formular nou sau refacere de layout, pe orice
|
||||||
deja). Nu se dubleaza aceste actiuni cu butoane in corpul formei.
|
aplicație ROA*.
|
||||||
- **Actiunile care au corespondent `but_*` in `cmd_butoane.vcx`** (Nou/Adauga, Modifica,
|
|
||||||
Salveaza, Sterge, Verifica etc.) folosesc CU PREDILECTIE clasa dedicata `but_*`
|
## Vezi și
|
||||||
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
|
- `PROMPT_cautare_vfp.md` din acest folder — cum se caută/editează cod în binarele VFP text-cache
|
||||||
`cmd_butoane.vcx` (ex. `cmd_executa`) — nu clase improvizate si nu CommandButton nativ.
|
(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
|
||||||
## Vocabular
|
editarea `.sc2`/`.vc2`; relevantă ori de câte ori editezi text-cache-ul unui formular/librărie
|
||||||
|
pentru a aplica aceste reguli de UX.
|
||||||
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.
|
|
||||||
|
|||||||
@@ -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() }
|
$p.WaitForExit(120000); if (!$p.HasExited) { $p.Kill() }
|
||||||
```
|
```
|
||||||
- `-A` ignora config.fpw implicit, `-T` sare peste splash; **ambele obligatorii** - fara `-T`
|
- `-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).
|
procesul ramane pe ecranul de intampinare (simptom identic cu o eroare de compilare). `-c<cale>`
|
||||||
Un `-c<cale>` explicit (lipit de flag) e preluat chiar si impreuna cu `-A`.
|
explicit (lipit de flag) e preluat si cu `-A`.
|
||||||
- **SAFETY**: sub `-A` porneste ON, deci primul `STRTOFILE` peste un log existent (sau
|
- **SAFETY**: sub `-A` porneste ON - primul `STRTOFILE` peste un log existent (sau `COMPILE` peste
|
||||||
`COMPILE` peste un `.err`/`.fxp` existent) scoate dialogul modal "overwrite?" si procesul
|
un `.err`/`.fxp` existent) scoate dialogul modal "overwrite?" si procesul pare agatat. Pune
|
||||||
pare agatat. Pune `SET SAFETY OFF` ca PRIMA linie din script si/sau `SAFETY=OFF` +
|
`SET SAFETY OFF` ca PRIMA linie din script si/sau `SAFETY=OFF`+`RESOURCE=OFF` intr-un config.fpw
|
||||||
`RESOURCE=OFF` intr-un config.fpw propriu pasat cu `-c`. Verificare: logheaza
|
propriu pasat cu `-c`. Verificare: logheaza `SET("SAFETY")`/`SET("RESOURCE")` la start.
|
||||||
`SET("SAFETY")`/`SET("RESOURCE")` la start.
|
|
||||||
- In script: logare cu STRTOFILE (nu WAIT WINDOW / debugger - nu exista consola);
|
- In script: logare cu STRTOFILE (nu WAIT WINDOW / debugger - nu exista consola);
|
||||||
`ON ERROR DO <handler> WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()` care logheaza si
|
`ON ERROR DO <handler> WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()` care logheaza si
|
||||||
continua (mimeaza ErrorHandler); `QUIT` obligatoriu la final.
|
continua (mimeaza ErrorHandler); `QUIT` obligatoriu la final.
|
||||||
- `LINENO()` din handler e relativ la inceputul metodei: linia in `.vc2` = linia raportata +
|
- `LINENO()` din handler e relativ la inceputul metodei: linia in `.vc2` = linia raportata +
|
||||||
linia `PROCEDURE`.
|
linia `PROCEDURE`.
|
||||||
- Nu rula cu IDE-ul sau exe-ul aplicatiei deschis (lock pe binare); sterge `.fxp`-ul vechi
|
- Nu rula cu IDE-ul sau exe-ul aplicatiei deschis (lock pe binare); sterge `.fxp`-ul vechi dupa
|
||||||
daca ai editat scriptul intre rulari. Daca nu-l stergi, VFP ruleaza codul vechi din `.fxp`
|
editarea scriptului - altfel VFP ruleaza codul vechi din `.fxp` fara niciun semn (testul poate
|
||||||
fara niciun semn - testul poate trece si raportul poate parea valid, desi modificarea nu a
|
trece fals; se prinde doar cand lipseste din log o linie scrisa doar de codul nou).
|
||||||
fost executata; se prinde doar dupa ce lipseste din log o linie pe care o scrie doar codul nou.
|
|
||||||
- Forme modale: `Show(1)` blocheaza. Replica in script doar liniile relevante din Show, sau
|
- Forme modale: `Show(1)` blocheaza. Replica in script doar liniile relevante din Show, sau
|
||||||
seteaza `WindowType = 0`.
|
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)
|
## 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,
|
1. `git show <rev>:clase\fisier.vcx > temp\fisier.vcx` (+ `.vct`); pentru diff lizibil,
|
||||||
`vcx2txt.ps1 -Source temp\fisier.vcx -CacheRoot temp\txt`.
|
`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
|
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
|
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,
|
test: trebuie sa aiba EXACT indecsii pe care ii creeaza fluxul real inainte de instantiere,
|
||||||
altfel ordinea/logica difera si testul da rezultat fals.
|
altfel ordinea/logica difera si testul da rezultat fals.
|
||||||
- **Un grid isi pierde TOATE coloanele** (`ColumnCount` devine 0, fara eroare in log) daca un
|
- **Un grid isi pierde TOATE coloanele** (`ColumnCount` devine 0, fara eroare in log) daca
|
||||||
ControlSource crapa la re-evaluare in timp ce coloanele sunt atinse programatic (ex. font per
|
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
|
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
|
"Property <cColWithLabel> is not found". Similar, un cursor legat la grid recreat de Init
|
||||||
lasa grid-ul fara coloane (eroare 1925).
|
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
|
- **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
|
"Data type mismatch" la `CREATEOBJECT`-ul formei (faza de constructie, raportata la linia
|
||||||
apelanta, Details gol).
|
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 ...
|
`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`.
|
CONSTRUCTIE, inainte de `Init`.
|
||||||
- **Literal string > 255 caractere = eroare de COMPILARE, nu de runtime** (masurat 24.07.2026:
|
- **Literal string > 255 caractere = eroare de COMPILARE, nu runtime** (255 trece, 256 pica).
|
||||||
255 trece, 256 pica). Mesaj: `Unrecognized command verb` daca linia incepe cu un apel de
|
Mesaj: `Unrecognized command verb` daca linia incepe cu un apel de metoda,
|
||||||
metoda, `Command contains unrecognized phrase/keyword` la o atribuire. Insidios: restul
|
`Command contains unrecognized phrase/keyword` la o atribuire. Insidios: restul programului
|
||||||
programului ruleaza, doar linia aceea lipseste din `.fxp` si da eroare 16 cand se ajunge la
|
ruleaza, doar linia lipseste din `.fxp` si da eroare 16 cand se ajunge la ea. De aceea SQL-ul
|
||||||
ea. De aceea SQL-ul lung se scrie cu `TEXT TO <var> [TEXTMERGE] NOSHOW ... ENDTEXT` sau
|
lung se scrie cu `TEXT TO <var> [TEXTMERGE] NOSHOW ... ENDTEXT` sau concatenat. Verificare:
|
||||||
concatenat. Verificare: `awk 'length($0) > 260 {print NR": "length($0)}' fisier.prg`.
|
`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
|
- **Linie de COD (nu doar literal string) prea lunga intr-o metoda de clasa `.vc2` poate arunca
|
||||||
arunca eroarea 11 ("Function argument value, type, or count is invalid") pe PRIMA
|
eroarea 11 ("Function argument value, type, or count is invalid") pe PRIMA instructiune a
|
||||||
instructiune a metodei, nu pe linia vinovata** - simptom complet derutant. Se exclude prin
|
metodei, nu pe linia vinovata** - simptom derutant. Se exclude prin diagnostic: aceeasi
|
||||||
diagnostic: aceeasi expresie merge normal la nivel de program, in alta clasa, intr-o
|
expresie merge normal la nivel de program, in alta clasa, intr-o subclasa cu metoda noua, si
|
||||||
subclasa cu metoda noua, si pe instanta virgina - deci nu tine de tipul datelor, de context
|
pe instanta virgina - deci nu tine de tipul datelor, de context sau de clasa parinte. Reper
|
||||||
sau de clasa parinte. Reper practic: linii preexistente >200 caractere intr-o clasa mare
|
practic: linii preexistente >200 caractere intr-o clasa mare functioneaza pana la ~250; pragul
|
||||||
functioneaza pana la ~250; pragul real e in jur de 255, ca la literalii de string. Remediu:
|
real e in jur de 255, ca la literalii de string. Remediu: sparge expresia in pasi cu variabile
|
||||||
sparge expresia in pasi cu variabile locale. Verificare (comparat intre fisierul curent si
|
locale. Verificare (comparat intre fisierul curent si un backup anterior):
|
||||||
un backup anterior):
|
|
||||||
```powershell
|
```powershell
|
||||||
$l=[IO.File]::ReadAllLines($p,[Text.Encoding]::GetEncoding(28591))
|
$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 } }
|
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
|
- **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
|
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
|
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
|
constanta (nu se declanseaza deloc, sau loveste tot). Simptome vazute: comasare de randuri
|
||||||
randuri care nu se mai producea deloc; un test agatat. Remediu: in clauze de filtrare
|
care nu se mai producea deloc; test agatat. Remediu: in clauze de filtrare foloseste expresia
|
||||||
foloseste expresia INLINE pe camp (`Nvl(camp,0) <> 1`); pastreaza helper-ul doar in cod
|
INLINE pe camp (`Nvl(camp,0) <> 1`); pastreaza helper-ul doar in cod procedural (`If`,
|
||||||
procedural (`If`, `Replace` pe randul curent), unde pointerul e garantat pozitionat.
|
`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
|
## 7. Capcane la SCRIEREA scriptului de test
|
||||||
|
|
||||||
- **`SET SAFETY OFF` in primele linii, INAINTE de orice `STRTOFILE`/`CREATE CURSOR`** (plus
|
- **`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
|
`SET TALK OFF`). Fara el VFP deschide dialogul de confirmare la suprascriere, iar headless
|
||||||
log, iar headless dialogul blocheaza procesul pana la timeout. Suitele existente il au deja -
|
dialogul blocheaza procesul pana la timeout. Suitele existente il au deja - capcana apare la
|
||||||
capcana apare la scripturile ad-hoc, scrise repede pentru o masuratoare.
|
scripturile ad-hoc, scrise repede pentru o masuratoare.
|
||||||
- **`DEFINE CLASS ... ENDDEFINE` nu poate sta la mijlocul programului principal.** Toate liniile
|
- **`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
|
de DUPA `ENDDEFINE` dau "Statement is not in a procedure" (vezi `<script>.ERR`); scriptul se
|
||||||
ruleaza doar pana acolo si se opreste silentios, fara sa ajunga la `QUIT` - simptom: vfp9.exe
|
opreste silentios, fara sa ajunga la `QUIT` - simptom: vfp9.exe pare agatat la nesfarsit. Pune
|
||||||
pare agatat la nesfarsit. Pune orice `DEFINE CLASS` auxiliar la FINALUL fisierului.
|
orice `DEFINE CLASS` auxiliar la FINALUL fisierului.
|
||||||
- **Dummy-uri cu metode**: `CREATEOBJECT('Custom')` + `AddProperty()` adauga doar PROPRIETATI.
|
- **Dummy-uri cu metode**: `CREATEOBJECT('Custom')` + `AddProperty()` adauga doar PROPRIETATI.
|
||||||
Daca clasa testata apeleaza `goExecutor.oExecute(...)`, dummy-ul trebuie sa fie
|
Daca clasa testata apeleaza `goExecutor.oExecute(...)`, dummy-ul trebuie sa fie
|
||||||
`DEFINE CLASS dummyexecutor AS Custom` cu `PROCEDURE oExecute` reala.
|
`DEFINE CLASS dummyexecutor AS Custom` cu `PROCEDURE oExecute` reala.
|
||||||
- **Diagnostic "script agatat"**, in ordine: (1) exista `<script>.ERR` langa `.prg`? => s-a
|
- **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`)
|
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 -
|
`EnumWindows`/`GetWindowText`/`GetWindowThreadProcessId` (`Add-Type`, user32) filtrat pe PID -
|
||||||
daca vezi doar fereastra principala + "Command", nu e dialog, cauta alta cauza (tipic `-T`
|
daca vezi doar fereastra principala + "Command", nu e dialog, cauta alta cauza (tipic `-T`
|
||||||
lipsa). Confirma mereu cauza inainte de a schimba scriptul.
|
lipsa). Confirma mereu cauza inainte de a schimba scriptul.
|
||||||
|
|||||||
@@ -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:`.
|
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
|
- 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`,
|
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
|
"Data type mismatch" raportat la linia apelanta. Dupa orice sesiune IDE pe clasa: refresh
|
||||||
cache + compara lista `*m:` cu starea de dinainte.
|
cache + compara lista `*m:` cu starea de dinainte.
|
||||||
- Nu folosi *Project > Build* ca sa recompilezi un binar vizat: rebuild-ul recompileaza toate
|
- Nu folosi *Project > Build* ca sa recompilezi un binar vizat: rebuild-ul recompileaza toate
|
||||||
|
|||||||
@@ -1,65 +1,46 @@
|
|||||||
# Flux SVN + git pentru COMUN
|
# Flux SVN + git pentru COMUN
|
||||||
|
|
||||||
**SVN = șeful** (munca reală circulă prin el). **git = oglindă** pentru unelte (Claude, căutare).
|
**SVN = șeful** (munca reală circulă prin el). **git = oglindă** pentru unelte (Claude, căutare).
|
||||||
git primește de la SVN, niciodată invers.
|
git primește de la SVN, niciodată invers.
|
||||||
|
|
||||||
## Reguli
|
## Reguli
|
||||||
|
|
||||||
1. **Munca reală se comite DOAR în SVN.** Nu face `git commit` cu o modificare nouă care n-a trecut prin SVN.
|
1. **Munca reală se comite DOAR în SVN.** Nu face `git commit` cu o modificare noua care n-a
|
||||||
2. **git se împrospătează DIN svn**, într-o singură direcție.
|
trecut prin SVN.
|
||||||
3. **COMUN se publică pe git dintr-UN SINGUR folder** (publisher, ex. `ROAAUTO\COMUN`). Celelalte doar se aliniază la origin.
|
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
|
||||||
## Lucrat în paralel în 2 proiecte (ex. roagest + roaauto), fișiere diferite
|
doar se aliniază la origin.
|
||||||
|
|
||||||
### 1. Împaci în SVN
|
## Lucrat în paralel în 2 proiecte (ex. roagest + roaauto), fișiere diferite
|
||||||
```
|
|
||||||
# ROAGEST\COMUN
|
1. **Împaci în SVN**: `svn commit` in ROAGEST\COMUN -> `svn update` in ROAAUTO\COMUN (aduce
|
||||||
svn commit -m "modificari roagest"
|
fisierele din roagest, fara conflict pe fisiere diferite) -> `svn commit` acolo -> `svn update`
|
||||||
# ROAAUTO\COMUN
|
inapoi in ROAGEST\COMUN. Acum ambele copii SVN au tot — e sursa de adevăr.
|
||||||
svn update # aduce fisierele din roagest (alte fisiere -> fara conflict)
|
2. **Oglindești în git, doar din folderul publisher**: `git add -A` + `git commit` + `git push`
|
||||||
svn commit -m "modificari roaauto"
|
in ROAAUTO\COMUN.
|
||||||
# ROAGEST\COMUN
|
3. **Celălalt folder: aliniere, NU commit** — in ROAGEST\COMUN: `git fetch origin` +
|
||||||
svn update # aduce fisierele din roaauto
|
`git reset --hard origin/main`. Sigur: fișierele sunt deja identice cu origin (le-a făcut svn),
|
||||||
```
|
`reset` doar mută pointerul.
|
||||||
Acum ambele copii SVN au tot. E sursa de adevăr.
|
|
||||||
|
Când te muți dintr-un proiect în altul: `svn update` in proiectul unde intri, apoi
|
||||||
### 2. Oglindești în git (doar din folderul publisher)
|
`git reset --hard origin/main` in COMUN, ca git-ul sa fie curat.
|
||||||
```
|
|
||||||
cd ROAAUTO\COMUN
|
## Regula care rezumă tot
|
||||||
git add -A
|
|
||||||
git commit -m "sync svn"
|
> Un singur folder publică în git (commit+push). Celelalte doar `git reset --hard origin/main`.
|
||||||
git push
|
> Munca circulă prin SVN; git fotografiază rezultatul.
|
||||||
```
|
|
||||||
|
## Model de branching (git urmareste text .??2)
|
||||||
### 3. Celălalt folder: aliniere, NU commit
|
|
||||||
```
|
git urmareste versiunile text FoxBin2Prg (.vc2/.sc2/…), improspatate in-arbore cu `git_sync.ps1`
|
||||||
cd ROAGEST\COMUN
|
la inceput de sesiune si inainte de orice commit; nu comite cat timp `git_sync` raporteaza esecuri
|
||||||
git fetch origin
|
(exit nenul). Doua benzi:
|
||||||
git reset --hard origin/main
|
|
||||||
```
|
- **`main` = oglinda SVN**: primeste DOAR commit-uri `sync SVN rN`, facute din stare curata
|
||||||
Sigur: fișierele sunt deja identice cu origin (le-a făcut svn), `reset` doar mută pointerul.
|
(imediat dupa `svn update`, inainte de lucru local).
|
||||||
|
- **Claude lucreaza pe branch** `claude/<subiect>` si comite doar acolo;
|
||||||
## Când te muți dintr-un proiect în altul
|
`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
|
||||||
svn update # in proiectul unde intri
|
(merge in `main` la urmatorul sync sau stergere).
|
||||||
git reset --hard origin/main # in COMUN, ca git-ul sa fie curat
|
- Igiena: sync pe `main` doar din stare curata — `svn update` in mijlocul lucrului amesteca
|
||||||
```
|
binarele pe disc.
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
|||||||
@@ -1,48 +1,46 @@
|
|||||||
# Inrolarea unui proiect ROA (Visual FoxPro) in fluxul git-text FoxBin2Prg
|
# 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
|
Pasi pentru o sesiune Claude Code care inroleaza un proiect ROA in fluxul in care git urmareste
|
||||||
in fluxul in care git urmareste DOAR versiunile text FoxBin2Prg (.vc2/.sc2/.fr2/.mn2/
|
DOAR versiunile text FoxBin2Prg (.vc2/.sc2/.fr2/.mn2/.lb2/.pj2/.dc2/.db2) generate in arbore,
|
||||||
.lb2/.pj2/.dc2/.db2) generate in arbore, langa binarele VFP. SVN ramane sursa de
|
langa binarele VFP. SVN ramane sursa de adevar si nu se atinge (niciun svn commit fara acordul
|
||||||
adevar si nu se atinge (niciun svn commit fara acordul explicit al utilizatorului).
|
explicit al utilizatorului).
|
||||||
|
|
||||||
Proiecte deja inrolate (16.07.2026): ROACONT, ROAGEST, ROAAUTO, ROAIMOB, ROAACNPRO,
|
Proiecte deja inrolate: ROACONT, ROAGEST, ROAAUTO, ROAIMOB, ROAACNPRO, ROAFACTURARE + COMUN
|
||||||
ROAFACTURARE + COMUN (romfast/comun.git). Modelul de referinta este ROACONT.
|
(romfast/comun.git). Modelul de referinta e ROACONT.
|
||||||
|
|
||||||
## Reguli pentru sesiunea care executa
|
## Reguli pentru sesiunea care executa
|
||||||
|
|
||||||
- Foloseste EXCLUSIV PowerShell pentru comenzi (NU tool-ul Bash — bash.exe crapa pe
|
- Foloseste EXCLUSIV PowerShell (NU Bash — bash.exe crapa pe aceste masini si lasa stackdump-uri).
|
||||||
aceste masini si lasa stackdump-uri).
|
- NU face niciun `svn commit`. NU modifica binarele VFP. La final binarele trebuie sa fie
|
||||||
- NU face niciun `svn commit`. NU modifica binarele VFP. La final binarele trebuie sa
|
byte-identice (`svn status`: niciun binar M).
|
||||||
fie byte-identice (verificabil cu `svn status`: niciun binar M).
|
- Rularile de conversie dureaza zeci de minute pe proiecte mari: sunt incrementale, daca expira
|
||||||
- Rularile de conversie dureaza zeci de minute pe proiecte mari: sunt incrementale,
|
timeout-ul tool-ului se reiau pana la capat.
|
||||||
daca expira timeout-ul tool-ului se reiau pana la capat.
|
|
||||||
- Nu rula doua conversii git_sync in paralel pe acelasi arbore.
|
- Nu rula doua conversii git_sync in paralel pe acelasi arbore.
|
||||||
|
|
||||||
## Preconditii
|
## Preconditii
|
||||||
|
|
||||||
1. Tooling-ul partajat exista in `D:\ROA\UTIL\foxbin2prg\`: `git_sync.ps1`,
|
1. Tooling partajat in `D:\ROA\UTIL\foxbin2prg\`: `git_sync.ps1`, `vfp_filemap.ps1`,
|
||||||
`vfp_filemap.ps1`, `txt2vcx.ps1`, `test_git_sync.ps1`,
|
`txt2vcx.ps1`, `test_git_sync.ps1`, `test_roundtrip.ps1`. Citeste-le inainte (macar help-ul
|
||||||
`test_roundtrip.ps1`. Citeste-le inainte (macar help-ul din git_sync.ps1).
|
din git_sync.ps1). `roa_sync.ps1` (+ `test_roa_sync.ps1`) traieste in `COMUN\scripts\` si
|
||||||
`roa_sync.ps1` (+ `test_roa_sync.ps1`) traieste in `COMUN\scripts\` si vine
|
vine singur cu svn update; in foxbin2prg a ramas doar un stub de compatibilitate.
|
||||||
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
|
||||||
2. Proiectul e working copy SVN valid (`svn info D:\ROA\<PROIECT>`), cu `COMUN\`
|
(external SVN).
|
||||||
inauntru (external SVN).
|
3. Repo-ul gitea exista: `git ls-remote git@gitea.romfast.ro:romfast/<proiect>.git`. Daca nu
|
||||||
3. Repo-ul gitea exista: `git ls-remote git@gitea.romfast.ro:romfast/<proiect>.git`.
|
exista, cere utilizatorului sa-l creeze din interfata gitea (NU crea repo-uri prin API din
|
||||||
Daca nu exista, cere utilizatorului sa-l creeze din interfata gitea (NU crea
|
proprie initiativa).
|
||||||
repo-uri prin API din proprie initiativa).
|
4. SVN global-ignores pe masina contine `*.vc2 *.sc2 *.fr2 *.mn2 *.lb2 *.pj2 *.dc2 *.db2
|
||||||
4. SVN global-ignores pe masina contine `*.vc2 *.sc2 *.fr2 *.mn2 *.lb2 *.pj2 *.dc2
|
*.dbf.cfg` (in `%APPDATA%\Subversion\config`, sectiunea [miscellany]). Fara asta, textele apar
|
||||||
*.db2 *.dbf.cfg` (in `%APPDATA%\Subversion\config`, sectiunea [miscellany]).
|
ca `?` in svn status si risca svn add accidental.
|
||||||
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
|
||||||
5. Daca proiectul ARE deja git cu istoric si urmeaza reset: confirmarea utilizatorului
|
exista clone active pe alte masini (force-push rescrie istoria).
|
||||||
ca nu exista clone active pe alte masini (force-push rescrie istoria).
|
|
||||||
|
|
||||||
## Pasi
|
## Pasi
|
||||||
|
|
||||||
### 1. Inventar prealabil (inainte de orice stergere)
|
### 1. Inventar prealabil (inainte de orice stergere)
|
||||||
|
|
||||||
- Exista `.git`? Noteaza `git remote -v` si branch-ul. Exista `COMUN\.git`?
|
- 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
|
- `git ls-files *.dbf` (daca exista repo vechi): tabelele urmarite azi ca binare sunt candidate
|
||||||
candidate la conversie .db2 (cerinta: tot ce e convertibil trece pe text).
|
la conversie .db2 (cerinta: tot ce e convertibil trece pe text).
|
||||||
|
|
||||||
### 2. Conversia completa
|
### 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>
|
& D:\ROA\UTIL\foxbin2prg\git_sync.ps1 -ProjectRoot D:\ROA\<PROIECT>
|
||||||
```
|
```
|
||||||
|
|
||||||
- DbfList implicit acopera `Locale\locale*.dbf`, `Help\*.dbf`, `DATE\Optiuni_*.dbf`
|
- DbfList implicit acopera `Locale\locale*.dbf`, `Help\*.dbf`, `DATE\Optiuni_*.dbf` si toate
|
||||||
si toate dbf-urile COMUN. Tabele de configurare specifice proiectului se adauga cu
|
dbf-urile COMUN. Tabele de configurare specifice proiectului se adauga cu `-DbfList` explicit
|
||||||
`-DbfList` explicit (ATENTIE: parametrii array NU se pot pasa prin
|
(ATENTIE: parametrii array NU se pot pasa prin `powershell -File` — invoca scriptul in-process
|
||||||
`powershell -File` — invoca scriptul in-process cu `&`, altfel array-ul se
|
cu `&`, altfel array-ul se colapseaza). Tabele operationale mari nu se adauga; un .db2 peste
|
||||||
colapseaza). Tabele operationale mari nu se adauga; un .db2 peste 5 MB ramane binar.
|
5 MB ramane binar.
|
||||||
- Esecuri de conversie — se investigheaza fiecare:
|
- Esecuri de conversie — se investigheaza fiecare:
|
||||||
- meniuri pre-VFP9 ("NOT in VFP 9 Format"): raman binare, cu exceptii negate `!` in
|
- 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);
|
.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,
|
- clase FFC/third-party cu roundtrip fals-negativ (#INCLUDE lipsa in staging izolat, ex. cele
|
||||||
ex. cele 6 din COMUN deja scutite implicit): se adauga la `-RoundtripExempt`;
|
6 din COMUN deja scutite implicit): se adauga la `-RoundtripExempt`;
|
||||||
- alte esecuri reale: fisierul ramane binar urmarit (exceptie `!`) si se raporteaza.
|
- alte esecuri reale: fisierul ramane binar urmarit (exceptie `!`) si se raporteaza.
|
||||||
- Regula: nu se trece mai departe cu esecuri neexplicate (exit code nenul).
|
- Regula: nu se trece mai departe cu esecuri neexplicate (exit code nenul).
|
||||||
|
|
||||||
### 3. .gitignore si .gitattributes
|
### 3. .gitignore si .gitattributes
|
||||||
|
|
||||||
- Copiaza `D:\ROA\ROACONT\.gitignore` ca model si adapteaza: sectiunea machine-local
|
- Copiaza `D:\ROA\ROACONT\.gitignore` ca model si adapteaza: sectiunea machine-local (exe-ul
|
||||||
(exe-ul proiectului, <proiect>_ref.DBF/FPT/CDX, FOXUSER, .ini/.ARM, log-uri) si
|
proiectului, <proiect>_ref.DBF/FPT/CDX, FOXUSER, .ini/.ARM, log-uri) si sectiunea dbf: fiecare
|
||||||
sectiunea dbf: fiecare .dbf care are .db2 se ignora INDIVIDUAL (plus .fpt-ul lui).
|
.dbf care are .db2 se ignora INDIVIDUAL (plus .fpt-ul lui). NU ignora: `*.??2`, `*.dbf.cfg`,
|
||||||
NU ignora: `*.??2`, `*.dbf.cfg`, grafica (bmp/ico/jpg/png), ocx, tmpl.
|
grafica (bmp/ico/jpg/png), ocx, tmpl.
|
||||||
- `.gitattributes` cu `* -text` (SVN ramane autoritatea EOL; git nu normalizeaza).
|
- `.gitattributes` cu `* -text` (SVN ramane autoritatea EOL; git nu normalizeaza).
|
||||||
|
|
||||||
### 4. Init/reset repo proiect
|
### 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):
|
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/
|
- 0 binare convertibile urmarite (vcx/vct/scx/sct/frx/frt/mnx/mnt/lbx/lbt/pjx/pjt/dbc/dct/cdx/dcx),
|
||||||
dbc/dct/cdx/dcx), cu exceptia celor cu `!` justificate;
|
cu exceptia celor cu `!` justificate;
|
||||||
- textele .??2 prezente; 0 fisiere din COMUN/ (are repo-ul lui).
|
- textele .??2 prezente; 0 fisiere din COMUN/ (are repo-ul lui).
|
||||||
|
|
||||||
Commit: `Initial: flux text FoxBin2Prg (git urmareste .??2 in-arbore, binarele VFP
|
Commit: `Initial: flux text FoxBin2Prg (git urmareste .??2 in-arbore, binarele VFP git-ignored)`
|
||||||
git-ignored)` + linia Co-Authored-By a sesiunii. Push: `git push -u origin main`
|
+ linia Co-Authored-By a sesiunii. Push: `git push -u origin main` (`--force` doar la reset).
|
||||||
(`--force` doar la reset).
|
|
||||||
|
|
||||||
### 5. Clona COMUN a proiectului
|
### 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
|
git -C D:\ROA\<PROIECT>\COMUN checkout origin/main -- .gitignore
|
||||||
```
|
```
|
||||||
|
|
||||||
Diferentele ramase in `git status` = revizii SVN diferite ale clonei (normal).
|
Diferentele ramase in `git status` = revizii SVN diferite ale clonei (normal). NU comite nimic in
|
||||||
NU comite nimic in comun.git dintr-o clona decalata — comun se comite doar din clona
|
comun.git dintr-o clona decalata — comun se comite doar din clona in care s-a lucrat efectiv,
|
||||||
in care s-a lucrat efectiv, dupa svn update.
|
dupa svn update.
|
||||||
|
|
||||||
### 6. roa_sync.bat
|
### 6. roa_sync.bat
|
||||||
|
|
||||||
Copiaza `D:\ROA\ROAFACTURARE\roa_sync.bat` in radacina proiectului (e generic,
|
Copiaza `D:\ROA\ROAFACTURARE\roa_sync.bat` in radacina proiectului (generic, foloseste `%~dp0` si
|
||||||
foloseste `%~dp0` si cheama `COMUN\scripts\roa_sync.ps1`) si include-l in commit.
|
cheama `COMUN\scripts\roa_sync.ps1`) si include-l in commit. Utilizatorul il ruleaza la inceput de
|
||||||
Utilizatorul il ruleaza la inceput de sesiune: svn update -> git_sync -> commit
|
sesiune: svn update -> git_sync -> commit "sync SVN rN" pe main (proiect + COMUN) -> reconciliere
|
||||||
"sync SVN rN" pe main (proiect + COMUN) -> reconciliere cu origin + push (doar
|
cu origin + push (doar commit-uri de sync) -> inchide branch-urile claude/* cu diff gol.
|
||||||
commit-uri de sync) -> inchide branch-urile claude/* cu diff gol.
|
|
||||||
|
|
||||||
### 7. Verificari finale
|
### 7. Verificari finale
|
||||||
|
|
||||||
- Acoperire: fiecare binar convertibil din arbore (inclusiv COMUN) are text .??2
|
- Acoperire: fiecare binar convertibil din arbore (inclusiv COMUN) are text .??2 langa el
|
||||||
langa el (exceptiile `!` enumerate si justificate).
|
(exceptiile `!` enumerate si justificate).
|
||||||
- `svn status`: niciun binar modificat, niciun .??2 adaugat in SVN.
|
- `svn status`: niciun binar modificat, niciun .??2 adaugat in SVN.
|
||||||
- `git ls-remote origin main` = HEAD-ul local.
|
- `git ls-remote origin main` = HEAD-ul local.
|
||||||
- Raport final: numar texte per tip, esecuri/scutiri, commit hash, push status.
|
- Raport final: numar texte per tip, esecuri/scutiri, commit hash, push status.
|
||||||
|
|
||||||
## Note operationale
|
## Note operationale
|
||||||
|
|
||||||
- Dialogurile modale FoxBin2Prg sunt suprimate de scripturi printr-un `foxbin2prg.cfg`
|
- Dialogurile modale FoxBin2Prg sunt suprimate de scripturi printr-un `foxbin2prg.cfg` cu
|
||||||
cu `DontShowErrors: 1` scris per-director de staging (cfg-ul global de langa exe NU
|
`DontShowErrors: 1` scris per-director de staging (cfg-ul global de langa exe NU e fiabil).
|
||||||
e fiabil). Daca utilizatorul vede totusi un MessageBox, e un dialog nativ VFP —
|
Daca utilizatorul vede totusi un MessageBox, e un dialog nativ VFP — watchdog-ul din
|
||||||
watchdog-ul din Invoke-FoxBin2PrgSafe il omoara la timeout.
|
Invoke-FoxBin2PrgSafe il omoara la timeout.
|
||||||
- Tabelele legate de un DBC au nevoie de .dbc/.dct/.dcx si .cdx langa ele la conversie
|
- Tabelele legate de un DBC au nevoie de .dbc/.dct/.dcx si .cdx langa ele la conversie
|
||||||
(git_sync face asta automat in staging).
|
(git_sync face asta automat in staging).
|
||||||
- `DBF_Conversion_Support: 4` (scris de git_sync in cfg-ul de staging) exporta DATELE
|
- `DBF_Conversion_Support: 4` (scris de git_sync in cfg-ul de staging) exporta DATELE in .db2, nu
|
||||||
in .db2, nu doar structura.
|
doar structura.
|
||||||
- Fisierele doar-git (docs, .bat, .gitignore) se comit separat, inainte de sync-ul
|
- Fisierele doar-git (docs, .bat, .gitignore) se comit separat, inainte de sync-ul "sync SVN rN",
|
||||||
"sync SVN rN", altfel nimeresc in commit-ul de sincronizare.
|
altfel nimeresc in commit-ul de sincronizare.
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
# Inventar COMUN - functii/clase reutilizabile (ROAGEST)
|
# Inventar COMUN - functii/clase reutilizabile (ROAGEST)
|
||||||
|
|
||||||
Scop: referinta rapida pt. plan/code-review, ca sa refoloseasca comunele in loc sa se reinventeze
|
Scop: reutilizare comune la plan/code-review (ex. cursor2lista() in loc de Scan manual pe cursor).
|
||||||
(ex: Scan manual pt. lista dintr-un cursor, cand exista deja cursor2lista()). Generat prin grep pe
|
Generat prin grep pe COMUN/programe/*.prg + cache text D:\ROA\_vfp_textcache\roagest. Numerele =
|
||||||
COMUN/programe/*.prg + cache text D:\ROA\_vfp_textcache\roagest (nu presupuneri). Numerele = nr.
|
nr. aparitii grep in proiect (indiciu cat de "canonic" e functia).
|
||||||
aparitii grep in tot proiectul (indiciu de cat de "canonic" e functia).
|
|
||||||
|
|
||||||
## 1. Functii comune - COMUN\programe\oproceduri_comune.prg (clasa Oracle/executor + utilitare)
|
## 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 | - |
|
| GetUserDocPath | - | folder documente utilizator curent | - |
|
||||||
| aleg_document_pereche | (vezi ooperatii_comune) | vezi sectiune 2 | - |
|
| 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,
|
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,
|
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 -
|
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
|
in roagest.prg OPROCEDURI_COMUNE.PRG (linia 238) vine dupa proceduri_comune (linia 218), deci activa
|
||||||
varianta activa e cea din `oproceduri_comune.prg`. Din varianta veche raman folosite doar 2 functii
|
e varianta din `oproceduri_comune.prg`. Unice din varianta veche: `extrage_optiuni(cLista,nId)`
|
||||||
unice: `extrage_optiuni(cLista,nId)` (valoare dintr-o lista "id::val;id::val", 11 uz) si
|
(valoare din lista "id::val;id::val", 11 uz), `myScatter(tcBlank)` (SCATTER generic in obiect, 3 uz);
|
||||||
`myScatter(tcBlank)` (SCATTER generic in obiect, 3 uz); restul functiilor unice de acolo = moarte.
|
restul functiilor unice de acolo = moarte.
|
||||||
|
|
||||||
## 2. Functii comune - COMUN\programe\ooperatii_comune.prg (contabilitate/analitice/balanta)
|
## 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) | - |
|
| PreviewerConfig (clasa) | SetValue/GetValue | property-bag optiuni FoxyPreviewer (param toPreviewerConfig la export2frx) | - |
|
||||||
|
|
||||||
### Export Excel - 3 mecanisme paralele (atentie la confuzii)
|
### 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
|
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
|
Automation celula-cu-celula, cere Excel instalat; uz mic (2-12). `get_excel_mask` acolo =
|
||||||
acolo = conversie masca VFP -> format Excel (nu confunda cu `get_mask` din sect. 1).
|
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
|
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
|
Plus functiile libere `export_xls`/`ExportToXMLExcel` din oproceduri_comune.prg (sect. 1) - cod
|
||||||
diferit de metoda `goExport.export_xls`, doar nume identic.
|
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)
|
## 7. Ce am lasat pe dinafara (intentionat)
|
||||||
|
|
||||||
- `proceduri_comune.prg` (varianta veche) - acoperita acum in nota de la sect. 1 (2 functii unice
|
- `proceduri_comune.prg` (varianta veche) - acoperita in nota sect. 1 (2 functii unice folosite,
|
||||||
folosite, restul dublate sau moarte); functiile ei unice cu 0 aparitii (caut_nume_politica,
|
restul dublate/moarte); functiile ei unice cu 0 aparitii (caut_nume_politica,
|
||||||
make_sectii_utilizator, recompune_optiuni, cere*/compara*, debug_*_eventtracking, ...) - omise.
|
make_sectii_utilizator, recompune_optiuni, cere*/compara*, debug_*_eventtracking, ...) - omise.
|
||||||
- `oproceduri_comune_imob.prg` - varianta specifica ROAIMOB, nu ROAGEST.
|
- `oproceduri_comune_imob.prg` - varianta specifica ROAIMOB, nu ROAGEST.
|
||||||
- `xdate.prg` - script procedural (incarca cursoarele xsets/xrequest/xnote la DO), nu expune functii.
|
- `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
|
- Metoda `getUserRepPath` din oExportConfig - complet comentata (moarta); varianta activa e functia
|
||||||
libera omonima din `proceduri_rapoarte.prg` (cod diferit).
|
libera omonima din `proceduri_rapoarte.prg` (cod diferit).
|
||||||
- Clase de nomenclatoare mari (`onomenclatoare.vcx`, `onom_articole.vcx`, `stocuri.vcx`, `rulaje.vcx`,
|
- 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
|
`ointroduceri*.vcx`, `oinventar.vcx`) - business logic gestiune, prea voluminos pt. acest inventar
|
||||||
inventar (candidat pt. un inventar separat, per-flux, daca devine necesar).
|
(candidat pt. inventar separat per-flux, daca devine necesar).
|
||||||
- Clasele de configurare/serii (`configurare.vcx`, `serii_numere.vcx`, `ferestre_oracle.vcx`,
|
- Clasele de configurare/serii (`configurare.vcx`, `serii_numere.vcx`, `ferestre_oracle.vcx`,
|
||||||
`bon_fisc.vcx`) si utilitarele (`GridExtras`, `ctl32`, `hpdf`) - neinventariate, uz mai rar
|
`bon_fisc.vcx`) si utilitarele (`GridExtras`, `ctl32`, `hpdf`) - neinventariate, uz rar in
|
||||||
in fluxurile curente de lucru (`excelxml.vcx` e acoperita la sect. 3).
|
fluxurile curente (`excelxml.vcx` e acoperita la sect. 3).
|
||||||
- Functiile din `COMUN\programe` fara nicio aparitie gasita prin grep in ROAGEST (posibil folosite
|
- Functiile din `COMUN\programe` fara nicio aparitie prin grep in ROAGEST (posibil doar alte
|
||||||
doar de alte aplicatii ROA) - omise.
|
aplicatii ROA) - omise.
|
||||||
|
|
||||||
## 8. Cum se foloseste
|
## 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
|
(`grep -rn "<nume_functie_candidata>" COMUN/programe D:\ROA\_vfp_textcache\roagest`) ca sa
|
||||||
confirmi ca nu exista deja o comuna echivalenta.
|
confirmi ca nu exista deja o comuna echivalenta.
|
||||||
- **La code-review**: daca un diff introduce Scan manual pt. liste, MESSAGEBOX direct, SQLEXEC direct,
|
- **La code-review**: daca un diff introduce Scan manual pt. liste, MESSAGEBOX direct, SQLEXEC
|
||||||
un buton cu Click suprascris in loc de `caction`, un export Excel/listare construite manual in loc
|
direct, un buton cu Click suprascris in loc de `caction`, export Excel/listare construite manual
|
||||||
de `goExport.export2*`/FoxyPreview, sau un dialog de alegere nomenclator facut din SELECT+grid in
|
in loc de `goExport.export2*`/FoxyPreview, sau un dialog de alegere nomenclator din SELECT+grid
|
||||||
loc de `caut_*` (ocautare.prg), semnaleaza reutilizarea comunei corespunzatoare din tabelele de mai sus.
|
in loc de `caut_*` (ocautare.prg), semnaleaza comuna corespunzatoare din tabelele de mai sus.
|
||||||
|
|||||||
42
docs/monitorizare-context.md
Normal file
42
docs/monitorizare-context.md
Normal 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`.
|
||||||
@@ -1,61 +1,61 @@
|
|||||||
# Export surse Oracle (PACK_CONTAFIN & co.) — cum se face
|
# Export surse Oracle (PACK_CONTAFIN & co.) — cum se face
|
||||||
|
|
||||||
`PACK_CONTAFIN.pck` din acest folder este exportul sursei pachetului PL/SQL `PACK_CONTAFIN`.
|
`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
|
Claude Code își face singur exportul/reîmprospătarea — nu mai e nevoie de export manual din
|
||||||
PL/SQL Developer.
|
PL/SQL Developer.
|
||||||
|
|
||||||
## Conexiune
|
## Conexiune
|
||||||
|
|
||||||
- Client: `D:\ROA\instantclient_19_18\sqlplus.exe` (`TNS_ADMIN` e deja setat spre același folder).
|
- 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`).
|
- 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/utilizator: `MARIUSM_AUTO` (schema de dezvoltare a lui Marius).
|
||||||
- **Parola nu e versionată** — se află local, în `D:\ROA\ROAGEST\docs\local\oracle.md`
|
- **Schema de lucru pentru verificari: `MARIUSM_AUTO` pe `ROA_CENTRAL`** - nu `ACN` sau altele.
|
||||||
(folder ignorat de git), pe mașina de lucru.
|
- **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 un sinonim `PUBLIC`.
|
`PACK_CONTAFIN` există în schemele `MARIUSM_AUTO` (dev) și `ACN`, plus sinonim `PUBLIC`.
|
||||||
Exportul de referință se face din `MARIUSM_AUTO`.
|
Exportul de referință se face din `MARIUSM_AUTO`.
|
||||||
|
|
||||||
## Gotcha sqlplus pe Windows/PowerShell
|
## Gotcha sqlplus pe Windows/PowerShell
|
||||||
|
|
||||||
Nu trimite SQL prin pipe din PowerShell (`'select...' | sqlplus`) — BOM-ul UTF-16 sparge parserul
|
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**
|
(`SP2-0734: unknown command beginning "select..."`). Scrie un fișier `.sql` cu encoding **ASCII**
|
||||||
și rulează-l cu `@fisier.sql`.
|
și rulează-l cu `@fisier.sql`.
|
||||||
|
|
||||||
## Comanda de export (re-generare .pck)
|
## Comanda de export (re-generare .pck)
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
-- export_pack.sql
|
-- export_pack.sql
|
||||||
set pagesize 0 linesize 400 trimspool on feedback off heading off termout off
|
set pagesize 0 linesize 400 trimspool on feedback off heading off termout off
|
||||||
spool D:\ROA\ROAGEST\COMUN\docs\PACK_CONTAFIN.pck
|
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 text from all_source where owner='MARIUSM_AUTO' and name='PACK_CONTAFIN' and type='PACKAGE' order by line;
|
||||||
select '/' from dual;
|
select '/' from dual;
|
||||||
select text from all_source where owner='MARIUSM_AUTO' and name='PACK_CONTAFIN' and type='PACKAGE BODY' order by line;
|
select text from all_source where owner='MARIUSM_AUTO' and name='PACK_CONTAFIN' and type='PACKAGE BODY' order by line;
|
||||||
select '/' from dual;
|
select '/' from dual;
|
||||||
spool off
|
spool off
|
||||||
exit
|
exit
|
||||||
```
|
```
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
& 'D:\ROA\instantclient_19_18\sqlplus.exe' -L -S 'MARIUSM_AUTO/<parola>@ROA_CENTRAL' '@export_pack.sql'
|
& '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
|
Același tipar merge pentru orice alt pachet/procedură (`PACK_SESIUNE`, `PACK_PRETURI`, …) sau
|
||||||
DDL de tabele/view-uri (`all_tab_columns`, `dbms_metadata.get_ddl`).
|
pentru DDL de tabele/view-uri (`all_tab_columns`, `dbms_metadata.get_ddl`).
|
||||||
|
|
||||||
## Ce e strict necesar de știut despre PACK_CONTAFIN
|
## Ce e strict necesar de știut despre PACK_CONTAFIN
|
||||||
|
|
||||||
Pachetul central de **scriere a documentelor** — clientul VFP populează tabelele temporare
|
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:
|
`ACT_TEMP`/`RUL_TEMP` (prin `oscrie_in_fisiere`-ul din COMUN), apoi pachetul distribuie:
|
||||||
|
|
||||||
- `SCRIE_IN_FISIERE` — orchestratorul (apelat per document).
|
- `SCRIE_IN_FISIERE` — orchestratorul (apelat per document).
|
||||||
- `SCRIE_IN_ACT` — `ACT_TEMP` → `ACT` (notele contabile).
|
- `SCRIE_IN_ACT` — `ACT_TEMP` → `ACT` (notele contabile).
|
||||||
- `SCRIE_IN_RUL` — `RUL_TEMP` → `RUL` (mișcările de stoc); completează `COD`, `DATAORA`, `ID_FACT`
|
- `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
|
(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
|
`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.
|
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
|
- `SCRIE_IN_RUL_OBINV` / `SCRIE_IN_STOC` / `SCRIE_IN_STOC_OBINV` — variantele pentru obiecte de
|
||||||
inventar și actualizarea stocului.
|
inventar și actualizarea stocului.
|
||||||
- `VERIFICA_NOTE_CONTABILE`, `SCRIE_JC_2007`/`SCRIE_JV_2007` (jurnale TVA),
|
- `VERIFICA_NOTE_CONTABILE`, `SCRIE_JC_2007`/`SCRIE_JV_2007` (jurnale TVA),
|
||||||
`SCRIE_IN_BALANTA(_PARTENERI)`, `sterge_document`, `finalizeaza_document_*`.
|
`SCRIE_IN_BALANTA(_PARTENERI)`, `sterge_document`, `finalizeaza_document_*`.
|
||||||
- Stare de sesiune prin settere/gettere (`SET_COD`/`GET_COD`, `SET_IDFACT`, `SET_ID_SUCURSALA`, …)
|
- Stare de sesiune prin settere/gettere (`SET_COD`/`GET_COD`, `SET_IDFACT`, `SET_ID_SUCURSALA`, …)
|
||||||
+ `PACK_SESIUNE` (an/lună, opțiuni firmă).
|
+ `PACK_SESIUNE` (an/lună, opțiuni firmă).
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Orchestrare cu subagenti: context mic, misiuni descompuse
|
# Orchestrare cu subagenti: context mic, misiuni descompuse
|
||||||
|
|
||||||
Regula (valabila in toate proiectele ROA/VFP): un singur subagent care duce o misiune lunga
|
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
|
(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.
|
calitate degradata, cost mare. Nu se lucreaza asa.
|
||||||
|
|
||||||
## Cum se lucreaza
|
## 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
|
## Disciplina de context a ORCHESTRATORULUI
|
||||||
|
|
||||||
Pragul de ~200-250k e pentru subagenti, dar orchestratorul se umple la fel de repede daca isi
|
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
|
lasa in sesiune munca de CITIT (masurat: o runda de implementare + 4 rulari de teste a dus
|
||||||
de 25 de teste): sesiunea principala a ajuns la ~570k desi tot codul fusese scris de subagenti.
|
sesiunea principala la ~570k desi tot codul fusese scris de subagenti). Principalii consumatori:
|
||||||
Consumul, in ordinea marimii: (1) citirea rezultatelor de test dupa fiecare test terminat, cu tot
|
citirea rezultatelor de test dupa fiecare rulare (cu tot cu liniile "OK"), citirea codului pentru
|
||||||
cu liniile "OK"; (2) citirea codului ca sa diagnosticheze esecurile; (3) diagnostic si fixuri
|
diagnostic, fixuri aplicate direct in loc de delegate.
|
||||||
aplicate direct in loc de delegate.
|
|
||||||
|
|
||||||
- **Nu citi log-uri brute.** Scripturile de raportare afiseaza DOAR esecurile plus un total
|
- **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
|
("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
|
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
|
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.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Prompt: seteaza conventia docs/ (insight-uri de proiect) intr-un proiect ROA
|
# 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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,60 +1,81 @@
|
|||||||
# Reguli de lucru agent (comune proiectelor ROA VFP)
|
# Reguli de lucru agent (comune proiectelor ROA VFP)
|
||||||
|
|
||||||
1. Modificari de cod: livreaza FISIER de diff `docs\diff_runda<N>_<subiect>.patch`
|
1. Modificari de cod: diff ca FISIER `docs\diff_runda<N>_<subiect>.patch`
|
||||||
(`git diff --no-index <baseline.bak> <editat>`), nu diff in terminal.
|
(`git diff --no-index <baseline.bak> <editat>`), nu in terminal. Write-back in binar (txt2vcx)
|
||||||
Write-back in binar (txt2vcx) si commit DOAR dupa aprobarea patch-ului de catre utilizator.
|
si commit DOAR dupa aprobarea patch-ului. Patch-urile (in .gitignore, `docs/diff_runda*.patch`)
|
||||||
Patch-urile sunt intermediare de review: NU se comit NICIODATA in git (sunt in
|
nu se comit niciodata, raman local. Dupa commit: sterge patch-urile si backup-urile
|
||||||
.gitignore ca `docs/diff_runda*.patch`); raman doar local, pe disc.
|
`*.pre_runda*.bak`.
|
||||||
Curatenie: dupa commit se sterg patch-urile de review si backup-urile de lucru
|
2. Comentarii in cod: minime, strict functionale, descriu comportamentul CURENT (ca si cum ar fi
|
||||||
(`*.pre_runda*.bak`).
|
scris asa de la inceput) — o linie de regula, 2-3 doar pentru metode cu contract nebanal
|
||||||
2. Comentarii in cod: minime si strict functionale - descriu comportamentul CURENT, ca si cum
|
(parametri, cursor asteptat/lasat deschis, pozitionare la iesire). Istoricul modificarilor
|
||||||
codul ar fi fost scris asa de la inceput. O linie de regula; 2-3 linii doar pentru o metoda
|
sta DOAR in ANTETUL fisierului (niciodata inline) — la fel in `.prg` si in PL/SQL Oracle.
|
||||||
cu contract nebanal (parametri, cursorul asteptat/lasat deschis, pozitionarea la iesire).
|
INTERZIS in comentariu: nume de agent ("claude"), referinte la propuneri/decizii/etape
|
||||||
Istoricul modificarilor sta DOAR in ANTETUL fisierului, niciodata inline; se aplica la fel
|
(`docs/propuneri_*.md`, "M2", "T3", "dec.6", "runda27", "E7", "D-H2"), istoricul modificarii
|
||||||
in `.prg` si in package-urile/procedurile PL/SQL Oracle.
|
("inlocuieste...", "nu mai depinde de...", "mutat din..."), date si autori pe cod nou.
|
||||||
INTERZIS in comentariu: nume de agent ("claude"), referinte la documente de propuneri sau la
|
Comentarii vechi in stil jurnal nu se rescriu din oficiu — doar cand blocul e oricum atins
|
||||||
decizii/etape (`docs/propuneri_*.md`, "M2", "T3", "dec.6", "runda27", "E7", "D-H2"), istoricul
|
sau la cerere explicita.
|
||||||
modificarii ("inlocuieste ...", "nu mai depinde de ...", "mutat din ..."), date si autori pe
|
Antet: o singura intrare CUMULATIVA per functionalitate (`*!* DD.MM.YYYY` / `*!* autor` /
|
||||||
cod nou. Comentariile vechi in stil jurnal nu se rescriu din oficiu - doar cand blocul e
|
`*!* ce face, 1-2 fraze`) — la revenire se rescrie intrarea, nu se adauga alta; autorul e cine
|
||||||
oricum atins, sau la cerere explicita.
|
semneaza livrarea (ex. `marius.mutu`), niciodata agent. Doar comportamentul final — fara
|
||||||
In ANTETUL fisierului se tine o singura intrare CUMULATIVA per functionalitate, in stilul
|
revizii/runde/patch-uri/corectii. La rezolvari de erori: fara comentarii.
|
||||||
existent (`*!* DD.MM.YYYY` / `*!* autor` / `*!* ce face, 1-2 fraze`): la revenirea pe aceeasi
|
Explicatiile merg in docs/ sau in mesajul de commit, nu in cod.
|
||||||
lucrare se rescrie intrarea, nu se adauga alta. Autorul e persoana care semneaza livrarea
|
Changelog (`changelog_<aplicatie>.txt`): strictul necesar, pe limba utilizatorului, non-tehnic
|
||||||
(ex. `marius.mutu`) - niciodata "claude" sau alt nume de agent.
|
— 1-3 fraze/intrare, fara detalii de implementare, fara enumerarea locurilor atinse. Cat timp
|
||||||
Se descrie doar comportamentul final, fara referinte la revizii, runde, patch-uri sau la
|
lucrarea n-a ajuns la utilizatori, erorile introduse si corectate in interior NU se mentioneaza
|
||||||
corectii facute pe parcurs. La rezolvari de erori NU se adauga comentarii deloc.
|
— intrarea descrie functionalitatea finala, `:nou:`/`:modificare:`; `:eroare:` doar pentru erori
|
||||||
Explicatiile merg in docs/ sau in mesajul de commit, nu in cod.
|
care au fost in productie.
|
||||||
Changelog (`changelog_<aplicatie>.txt`): text minimal, pe limba utilizatorului, nu tehnic,
|
3. Modificari minime si SCOPED: doar ce s-a cerut, doar pe cazul cu problema, fara refactorizari
|
||||||
o fraza scurta per intrare. Cat timp lucrarea nu a ajuns la utilizatori (fara deploy),
|
din oficiu. Cauta intai ce exista (`inventar-comun.md`) si refoloseste; daca lipseste ceva,
|
||||||
erorile introduse si corectate in interiorul ei NU se pomenesc - intrarea descrie
|
propune COMPLETAREA unei functii/tabele/view comune, nu o varianta paralela. 80/20: solutia cea
|
||||||
functionalitatea asa cum ajunge la utilizator, `:nou:`/`:modificare:`; `:eroare:` ramane
|
mai simpla care rezolva cazul real. Completeaza `inventar-comun.md` la orice descoperire/creare
|
||||||
doar pentru erori care au fost in productie.
|
de element comun nedocumentat.
|
||||||
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.
|
||||||
4. Testare headless (fara IDE): `vfp9.exe -A -T "<script.prg>" <param>` din PowerShell.
|
Mediu, sabloane, capcane, depanare: `depanare_testare_vfp.md`.
|
||||||
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`.
|
||||||
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
|
||||||
Cautare in binare: `cautare_vcx_vct.md`.
|
decat binarul — verifica mtime inainte de concluzii; continutul real e in `.PJX`.
|
||||||
Versiunile `.??2` sunt instantanee si pot fi mai vechi decat binarul - verifica mtime-ul
|
6. Delegare: implementarile, testele, verificarile si cercetarile se dau unor subagenti Sonnet in
|
||||||
inainte de a trage concluzii din ele; continutul real al proiectului se citeste din `.PJX`.
|
background (lane-uri paralele); sesiunea principala doar orchestreaza si verifica, ca sa nu i
|
||||||
6. Misiuni lungi (teste, investigatii, sarcini inlantuite): NU un singur subagent cu context
|
se umple contextul. Misiuni lungi: subagenti proaspeti per sarcina (max ~200-250k
|
||||||
acumulat — orchestrator + subagenti proaspeti per sarcina (max ~200-250k tokens/subagent),
|
tokens/subagent), nu unul singur cu context acumulat; handoff compact pe disc:
|
||||||
handoff compact pe disc: `orchestrare-subagenti.md`.
|
`orchestrare-subagenti.md`.
|
||||||
7. Conventii obligatorii, de citit cand atingi zona respectiva:
|
7. Conventii obligatorii, de citit cand atingi zona respectiva:
|
||||||
- editezi orice fisier cu octeti cp1252 - `.vc2`/`.sc2`, dar si `.prg` (ex. `programe\ocautare.prg`,
|
- 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`) ->
|
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)
|
`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 daca schimbi o singura
|
corupe caracterele >= 0x80 din TOT fisierul (`0xBA` -> `EF BF BD`), chiar la o singura linie
|
||||||
linie, si o face din nou la FIECARE scriere. Deci: editezi tot ce ai de editat, si abia DUPA ultima
|
schimbata, si o repeta la FIECARE scriere — editeaza tot ce ai de editat, verifica byte-level
|
||||||
scriere verifici byte-level si repari o singura data; daca mai editezi dupa reparare, se strica iar.
|
si repara o singura data DUPA ultima scriere. Verificare: `perl -ne 'print "$.\n" if
|
||||||
Verificare: `perl -ne 'print "$.\n" if /[\x80-\xFF]/' <fisier>`; reparare (aici pentru `0xBA`):
|
/[\x80-\xFF]/' <fisier>`; reparare (pt. `0xBA`): `perl -e
|
||||||
`perl -e 'binmode(STDIN);binmode(STDOUT);local $/;$_=<STDIN>;s/\xEF\xBF\xBD/\xBA/g;print' < f > f.tmp`.
|
'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
|
`EF BF BD` nu spune ce caracter s-a pierdut - toate diacriticele devin la fel; ia octetul corect
|
||||||
corect per pozitie din `svn cat <fisier>` (SVN are versiunea necorupta) si abia apoi inlocuieste;
|
per pozitie din `svn cat <fisier>` (necorupt) inainte sa inlocuiesti - o inlocuire oarba cu
|
||||||
o inlocuire oarba cu `0xBA` strica `a`/`t` cu caciula (`0xE3`, `0xFE`) din alte fisiere;
|
`0xBA` strica `a`/`t` cu caciula (`0xE3`, `0xFE`) din alte fisiere;
|
||||||
- adaugi/rearanjezi controale pe formulare sau coloane in grid -> `conventie_ux_formulare.md`;
|
- 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`;
|
- `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`;
|
- `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`;
|
- testare UI / prin MCP -> `testare-ui-vfp.md`, `testare-vfp-mcp.md`;
|
||||||
- export date din Oracle -> `oracle_export.md`;
|
- garzi pe valori NULL din Oracle -> `conventie_null_vfp.md`;
|
||||||
- modifici schema Oracle (tabele/view-uri/pachete) -> `scripturi-migrare-db.md`
|
- export date din Oracle -> `oracle_export.md`;
|
||||||
(unde stau scripturile de migrare si modelele pentru scripturi noi).
|
- 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).
|
||||||
|
|||||||
@@ -1,21 +1,28 @@
|
|||||||
# Scripturi migrare baza de date Oracle
|
# Scripturi migrare baza de date Oracle
|
||||||
|
|
||||||
Scripturile de migrare a schemei (si modelele pentru scripturi noi) sunt in
|
Scripturile de migrare a schemei (si modelele pentru scripturi noi) sunt in
|
||||||
`DATABASE\SCRIPTURI_CLAR` de sub radacina suitei ROA (folderul parinte al aplicatiei,
|
`DATABASE\SCRIPTURI_CLAR` de sub radacina suitei ROA (`gcDirMare`/`dirgen` — ex.
|
||||||
`gcDirMare`/`dirgen` — ex. `D:\ROA\DATABASE\SCRIPTURI_CLAR`).
|
`D:\ROA\DATABASE\SCRIPTURI_CLAR`). Sursa SVN: `http://svnroa:3001/svn/ROA/DATABASE/Branches/RB-1.00`.
|
||||||
Sursa SVN: `http://svnroa:3001/svn/ROA/DATABASE/Branches/RB-1.00`.
|
|
||||||
Pentru un script nou, urmeaza formatul/conventiile celor recente de acolo.
|
Pentru un script nou, urmeaza formatul/conventiile celor recente de acolo.
|
||||||
|
|
||||||
Reguli confirmate de Marius (24.07.2026):
|
Reguli confirmate de Marius (24.07.2026):
|
||||||
|
|
||||||
- **Line-endings CRLF obligatoriu** in scripturile `.sql` — tool-urile agentului scriu
|
- **Line-endings CRLF obligatoriu** in scripturile `.sql` — tool-urile agentului scriu implicit
|
||||||
implicit LF; dupa orice scriere, verifica si converteste byte-safe LF -> CRLF (fara
|
LF; dupa orice scriere, verifica si converteste byte-safe LF -> CRLF (fara decodare/reincodare).
|
||||||
decodare/reincodare). Parsarea pe fluxul ROA (ex. `ALINES` pe `CHR(13)+CHR(10)`)
|
Parsarea pe fluxul ROA (ex. `ALINES` pe `CHR(13)+CHR(10)`) esueaza silentios pe LF: tot fisierul
|
||||||
esueaza silentios pe LF: tot fisierul devine un singur rand.
|
devine un singur rand.
|
||||||
- `versiune_db.txt` (marker-ul `YYYY_MM_DD_NN` din radacina aplicatiei) se scrie fara
|
- `versiune_db.txt` (marker-ul `YYYY_MM_DD_NN` din radacina aplicatiei) se scrie fara newline la
|
||||||
newline la final (conventia existenta).
|
final (conventia existenta).
|
||||||
- Aplicarea prin ODBC/`goExecutor`: sintaxa SQL*Plus `exec pachet.procedura(...)` nu
|
- Aplicarea prin ODBC/`goExecutor`: sintaxa SQL*Plus `exec pachet.procedura(...)` nu functioneaza
|
||||||
functioneaza — foloseste `begin pachet.procedura(...); end;`.
|
— 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
|
## Numerotare si versiune_db.txt
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
`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`.
|
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
|
utilizatorului** — formularul/butonul/metoda pe care o apeleaza aplicatia, NU introducerea
|
||||||
directa a randurilor in cursoare/tabele. Popularea directa sare peste validari/filtre/efecte
|
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
|
laterale si da PASS fals (caz real: articol "adaugat" direct in cursor trecea testul, dar prin
|
||||||
prin fluxul real nu se adauga deloc). Mock-urile raman permise doar pe INFRASTRUCTURA (Oracle,
|
fluxul real nu se adauga deloc). Mock-urile raman permise doar pe INFRASTRUCTURA (Oracle,
|
||||||
dialoguri modale), nu pe pasii fluxului testat.
|
dialoguri modale), nu pe pasii fluxului testat.
|
||||||
|
|
||||||
## Test UI nou in 5 pasi
|
## 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',...)`.
|
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`.
|
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
|
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
|
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
|
`.fxp`-ul PRECOMPILAT. Precompilarea (`COMPILE`+`QUIT`) atarna dupa COMPILE si, rulata in
|
||||||
ACEEASI sesiune powershell, otraveste lansarile ulterioare - ruleaza-o intr-un proces copil
|
ACEEASI sesiune powershell, otraveste lansarile ulterioare - ruleaza-o intr-un proces copil
|
||||||
izolat (`Start-Process -Wait _precompile.ps1`).
|
izolat (`Start-Process -Wait _precompile.ps1`).
|
||||||
e. **Suitele NU se ruleaza in paralel** intre ele: harness-ul isi omoara instantele `vfp9`
|
e. **Suitele NU se ruleaza in paralel**: harness-ul omoara instantele `vfp9` ramase inainte de
|
||||||
ramase inainte de fiecare lansare, deci un al doilea test pornit peste primul il ucide.
|
fiecare lansare, deci un al doilea test pornit peste primul il ucide. Omorarea e filtrata pe
|
||||||
Omorarea e INSA filtrata pe linia de comanda (`Win32_Process.CommandLine` care contine
|
linia de comanda (`Win32_Process.CommandLine` contine folderul de teste): instantele `vfp9`
|
||||||
folderul de teste): instantele `vfp9` straine — sesiunea IDE a utilizatorului sau teste
|
straine (sesiunea IDE a utilizatorului, teste dintr-un ALT proiect VFP) nu sunt atinse. Nu
|
||||||
dintr-un ALT proiect VFP — nu sunt atinse si nu blocheaza rularea. Nu reintroduce
|
reintroduce `Get-Process vfp9 | Stop-Process -Force` fara filtru.
|
||||||
`Get-Process vfp9 | Stop-Process -Force` fara filtru.
|
f. **FARA FURT DE FOCUS**: `Graphics.CopyFromScreen` fura focus si se corupe daca
|
||||||
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: `PrintWindow` (user32,
|
||||||
utilizatorul lucreaza in paralel - nu se mai foloseste. Capturile se fac cu `PrintWindow`
|
P/Invoke) pe `Process.MainWindowHandle`, flag `2` = `PW_RENDERFULLCONTENT` (fallback `0` daca
|
||||||
(user32, P/Invoke) pe `Process.MainWindowHandle`, flag `2` = `PW_RENDERFULLCONTENT`
|
iese goala); merge cu fereastra acoperita, NU minimizata. Fereastra se muta OFF-SCREEN
|
||||||
(fallback `0` daca iese goala); merge cu fereastra acoperita, dar NU minimizata. Fereastra
|
(`SetWindowPos`, `HWND_BOTTOM`, x=-4000, `SWP_NOACTIVATE`) la aparitia handle-ului si SE
|
||||||
se muta OFF-SCREEN (`SetWindowPos`, `HWND_BOTTOM`, x=-4000, `SWP_NOACTIVATE`) imediat ce
|
RE-IMPINGE la fiecare pas (VFP se reactiveaza singur la `Show()`/dialoguri). Consolele
|
||||||
apare handle-ul si SE RE-IMPINGE la fiecare pas (VFP se reactiveaza singur la
|
powershell copil: `-WindowStyle Hidden` (sigur pentru consola, NU pentru GUI VFP ascunsa -
|
||||||
`Show()`/dialoguri). Consolele powershell copil sunt `-WindowStyle Hidden` (sigur pentru
|
`PrintWindow` poate reda gol). Implementat in `vfp_ui_harness.ps1` (Take-Screenshot,
|
||||||
consola, NU pentru GUI VFP - ascunsa, `PrintWindow` poate reda gol). Implementat in
|
Push-Offscreen, Wait-MainWindowHandle) si `_precompile.ps1`.
|
||||||
`vfp_ui_harness.ps1` (Take-Screenshot, Push-Offscreen, Wait-MainWindowHandle) si
|
|
||||||
`_precompile.ps1`.
|
|
||||||
g. **Mock de messagebox**: `FUNCTION amessagebox` care returneaza direct valoarea butonului
|
g. **Mock de messagebox**: `FUNCTION amessagebox` care returneaza direct valoarea butonului
|
||||||
(6=Da), incarcat cu `SET PROCEDURE ... ADDITIVE` **PRIMUL**, inaintea fisierelor aplicatiei:
|
(6=Da), incarcat cu `SET PROCEDURE ... ADDITIVE` **PRIMUL**, inaintea fisierelor aplicatiei:
|
||||||
la nume duplicat de procedura VFP foloseste fisierul cautat PRIMUL (verificat empiric).
|
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
|
uneori in cascada la apeluri repetate. Verifica in codul apelant ce indecsi se creeaza si
|
||||||
replica-i identic.
|
replica-i identic.
|
||||||
j. **Mock-urile de date trebuie sa reproduca structura si semantica REALA a sursei** (view
|
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
|
Oracle: toate coloanele; relatii intre randuri: toate randurile implicate, nu una singura cu
|
||||||
valori "compuse" manual in test). Un mock incomplet lasa campuri mereu NULL sau ascunde
|
valori "compuse" manual). Un mock incomplet lasa campuri NULL sau ascunde pasul testat. Cand
|
||||||
pasul care se testeaza. Cand un flag global activeaza cod suplimentar (ex. `gl406`), acel
|
un flag global activeaza cod suplimentar (ex. `gl406`), acel cod cere mock-uri in plus -
|
||||||
cod cere mock-uri in plus - verifica ce apeleaza si adauga metodele lipsa din dummy.
|
verifica ce apeleaza si adauga metodele lipsa din dummy. Cu `gl406=.T.` (SAFT),
|
||||||
Cu `gl406=.T.` (SAFT), `GetTaxCodeIdPart`/`GetTaxCode` cer: `goApp.ReadIni`/`WriteIni`
|
`GetTaxCodeIdPart`/`GetTaxCode` cer: `goApp.ReadIni`/`WriteIni` (clasa `dummyapp` are nevoie
|
||||||
(proprietate simpla nu ajunge, clasa `dummyapp` are nevoie de METODE), `goExecutor.oReset`
|
de METODE, nu doar proprietate), `goExecutor.oReset` (no-op e suficient), si cursor
|
||||||
(no-op e suficient), si un cursor `saft_taxtable` real (nu doar mock pe `goExecutor` -
|
`saft_taxtable` real (nu doar mock pe `goExecutor` - `update_jtva_coloane` face
|
||||||
`update_jtva_coloane` face `USE saft_taxtable` direct pe alias). Fara ele, simptomul e un
|
`USE saft_taxtable` direct pe alias). Fara ele, simptomul e dialog nativ Windows "Open" (cauta
|
||||||
dialog nativ Windows "Open" (cauta `saft_taxtable.dbf`) care blocheaza headless la nesfarsit,
|
`saft_taxtable.dbf`) care blocheaza headless la nesfarsit, fara linie noua in log si CPU 0% -
|
||||||
fara nicio linie noua in log si CPU 0% - vezi `depanare_testare_vfp.md` pentru diagnosticul
|
vezi `depanare_testare_vfp.md` pentru diagnostic cu `EnumWindows`/`PrintWindow`.
|
||||||
cu `EnumWindows`/`PrintWindow` pe fereastra ascunsa cand simptomul e "ecran gol, fara eroare".
|
|
||||||
k. **`LOCATE FOR camp == 'literal'` pe camp `C(n)` padded nu gaseste nimic** (`==` e exact) -
|
k. **`LOCATE FOR camp == 'literal'` pe camp `C(n)` padded nu gaseste nimic** (`==` e exact) -
|
||||||
foloseste `ALLTRIM(camp) == 'literal'`.
|
foloseste `ALLTRIM(camp) == 'literal'`.
|
||||||
l. **`CREATEOBJECT`/`ADDPROPERTY` se comporta gresit apelate DINTR-O PROCEDURA in acest runtime
|
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
|
headless** (obiect returnat ca string de 30 spatii; `ADDPROPERTY` da eroare 11). Din programul
|
||||||
programul PRINCIPAL merg. Construieste obiectele-parametru INLINE in main, nu intr-un helper.
|
PRINCIPAL merg. Construieste obiectele-parametru INLINE in main, nu intr-un helper. Cauza
|
||||||
Cauza confirmata intr-un caz concret: linie de cod prea lunga in ACEEASI metoda de clasa -
|
confirmata intr-un caz concret: linie de cod prea lunga in ACEEASI metoda de clasa - vezi
|
||||||
vezi `depanare_testare_vfp.md` sectiunea 6. Remediul (constructie inline) ramane valabil
|
`depanare_testare_vfp.md` sectiunea 6; remediul (constructie inline) ramane valabil oricum.
|
||||||
oricum, indiferent de cauza exacta dintr-un caz punctual.
|
|
||||||
m. **Fara `SELECT-SQL` pe cursorul legat de grid**: `SELECT ... FROM <cursor> INTO CURSOR` cat
|
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
|
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`,
|
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`
|
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.
|
(auto-continue per checkpoint din `HarnessWaitContinue`), plus marja de pornire.
|
||||||
o. **Formularul resincronizeaza singur dupa o alegere din grid** (`lSyncPending` + `tmrSync`,
|
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
|
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
|
tocmai s-a aplicat (la explicatia TVA: randul S revine la familia documentului, randurile T se
|
||||||
se realiniaza dupa el). Scrie assert-urile pe starea de DUPA resincronizare si alege un efect
|
realiniaza dupa el). Scrie assert-urile pe starea de DUPA resincronizare, pe un efect pe care
|
||||||
pe care resincronizarea NU il repara (acolo: `scc`-ul randului T, atins doar cand se schimba
|
resincronizarea NU il repara (acolo: `scc`-ul randului T, atins doar la schimbarea explicatiei)
|
||||||
explicatia). Altfel testul pica fara sa fie ceva gresit in cod.
|
- altfel testul pica fara sa fie ceva gresit in cod.
|
||||||
|
|||||||
@@ -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
|
- Gate-ul de pornire (`gcNumeProgram = 'ROAGEST'` in `roagest.prg`) verifica
|
||||||
`JUSTSTEM(SYS(16,0))` — numele programului de la nivelul 0 al stivei, nu numele
|
`JUSTSTEM(SYS(16,0))` — numele programului de la nivelul 0 al stivei, nu numele procesului
|
||||||
procesului `.exe`. Rulat interpretat, `SYS(16,0)` = `roagest.prg`, deci gate-ul trece.
|
`.exe`. Rulat interpretat, `SYS(16,0)` = `roagest.prg`, deci gate-ul trece.
|
||||||
- Fereastra rezultata are titlul `ROA - Gestiuni` (setat din `NUMEPROGRAM`).
|
- Fereastra rezultata are titlul `ROA - Gestiuni` (setat din `NUMEPROGRAM`).
|
||||||
|
|
||||||
## Capcana: focus furat de terminal
|
## Capcana: focus furat de terminal
|
||||||
|
|
||||||
Daca sesiunea Claude Code afiseaza output in timp ce comanda de lansare ruleaza,
|
Daca sesiunea Claude Code afiseaza output in timp ce comanda de lansare ruleaza, fereastra
|
||||||
fereastra terminalului/IDE-ului ramane in prim-plan si VFP porneste in fundal —
|
terminalului/IDE-ului ramane in prim-plan si VFP porneste in fundal — `Screenshot`/`Snapshot`
|
||||||
`Screenshot`/`Snapshot` din `windows-mcp` pot raporta "No windows found" desi procesul
|
din `windows-mcp` pot raporta "No windows found" desi procesul si fereastra exista (verificabil
|
||||||
si fereastra exista (verificabil cu `Get-Process vfp9 | Select MainWindowTitle`).
|
cu `Get-Process vfp9 | Select MainWindowTitle`).
|
||||||
|
|
||||||
Fix: inainte de screenshot, adu explicit fereastra in prim-plan dupa titlu:
|
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"
|
mcp__windows-mcp__App mode=switch name="ROA - Gestiuni"
|
||||||
```
|
```
|
||||||
|
|
||||||
apoi `Screenshot`. Nu te baza pe enumerarea implicita de ferestre a `windows-mcp` cand
|
apoi `Screenshot`. Nu te baza pe enumerarea implicita de ferestre a `windows-mcp` cand ai lansat
|
||||||
ai lansat procesul chiar in runda curenta de comenzi.
|
procesul chiar in runda curenta de comenzi.
|
||||||
|
|
||||||
## Curatare dupa test
|
## Curatare dupa test
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
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
|
||||||
@@ -397,7 +397,7 @@ Function verific_partener
|
|||||||
|
|
||||||
ll_l=.F.
|
ll_l=.F.
|
||||||
|
|
||||||
If Empty(tcCont) Or Type('tccont')#'C'
|
If Type('tccont')#'C' Or Empty(Nvl(tcCont,''))
|
||||||
Return ll_l
|
Return ll_l
|
||||||
Else
|
Else
|
||||||
lcCont = Alltrim(tcCont)
|
lcCont = Alltrim(tcCont)
|
||||||
|
|||||||
543
utile/Teste/achizitie_import/test_repro_partener_scc_null.prg
Normal file
543
utile/Teste/achizitie_import/test_repro_partener_scc_null.prg
Normal 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
|
||||||
@@ -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
|
||||||
223
utile/Teste/partener_anaf/test_repro_anaf_path_nfjson.prg
Normal file
223
utile/Teste/partener_anaf/test_repro_anaf_path_nfjson.prg
Normal 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
|
||||||
18
utile/Teste/partener_anaf/test_repro_anaf_path_nfjson.ps1
Normal file
18
utile/Teste/partener_anaf/test_repro_anaf_path_nfjson.ps1
Normal 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
62
utile/context_watch.ps1
Normal 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
|
||||||
27
utile/docs_revizie_check.ps1
Normal file
27
utile/docs_revizie_check.ps1
Normal 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
|
||||||
Reference in New Issue
Block a user