Normalizeaza CRLF in fisierele rescrise constant de SVN (continut identic)
SVN scrie aceste fisiere cu CRLF nativ la fiecare update; blob-urile din git aveau LF, ceea ce cu .gitattributes (* -text) acum activ producea "modificari" reale de CRLF/LF dupa fiecare svn update. Alinierea la CRLF (ce scrie de fapt SVN) elimina divergenta pe viitor. Fara schimbari de continut, doar EOL. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,82 +1,82 @@
|
||||
# Capcană: corupere diacritice la editarea `.sc2`/`.vc2` (encoding cp1252)
|
||||
|
||||
Partajat între proiectele ROA* (similar cu `PROMPT_cautare_vfp.md` din acest folder) — capcana
|
||||
ține de formatul `.sc2`/`.vc2` produs de FoxBin2Prg, nu de un proiect anume.
|
||||
|
||||
Descoperit de 2 ori în aceeași sesiune (2026-07-10, în ROAAUTO): odată în
|
||||
`COMUN/clase/cmd_butoane.vc2` (clasa `cmd_select_adv`), odată în `Clase/ofundal_dev.vc2`
|
||||
(meniul principal) — de fiecare dată un agent anterior a editat text-cache-ul cu un tool care
|
||||
nu scrie cp1252 nativ, și a corupt TOATE caracterele cu diacritice din fișier, nu doar linia
|
||||
pe care voia s-o schimbe.
|
||||
|
||||
## De ce se întâmplă
|
||||
|
||||
Fișierele `.sc2`/`.vc2` generate de FoxBin2Prg sunt **cp1252 (Windows-1252)**, nu UTF-8
|
||||
(vezi antetul fiecărui fișier: `CPID="1252"`). Dacă un editor/tool citește fișierul ca UTF-8
|
||||
(sau alt encoding), fiecare byte >= 0x80 (diacritic) devine invalid ca secvență UTF-8 și e
|
||||
înlocuit cu caracterul de replacement U+FFFD. Dacă apoi tool-ul **salvează rezultatul tot ca
|
||||
UTF-8**, acel U+FFFD e scris ca 3 octeți UTF-8 (`0xEF 0xBF 0xBD`) — care, citiți înapoi ca
|
||||
cp1252 (cum face FoxBin2Prg la write-back), apar ca `�`. Rezultatul: caracterul original e
|
||||
**ireversibil pierdut** (nu mai există în fișier sub nicio formă) — recuperabil DOAR din altă
|
||||
sursă (git history, backup).
|
||||
|
||||
Codebase-ul ROA folosește un hack vechi de "reciclare" a unor caractere cp1252 needependente
|
||||
de Ș/ă/ț (care nu au echivalent direct în cp1252) pentru diacritice românești:
|
||||
|
||||
| Literă românească | Caracter folosit (cp1252) | Byte |
|
||||
|---|---|---|
|
||||
| ă | ã (a-tilde) | `0xE3` |
|
||||
| Ă | Ã | `0xC3` |
|
||||
| ț | þ (thorn minuscul) | `0xFE` |
|
||||
| Ș (majusculă) | ª (ordinal masculin) | `0xAA` |
|
||||
| ș (minusculă) | º (ordinal feminin) | `0xBA` |
|
||||
| î, â | î, â (existente nativ în cp1252) | `0xEE`, `0xE2` |
|
||||
|
||||
Aceste caractere par "gunoi"/typo la prima vedere într-un editor UTF-8 (`ã`, `þ`, `ª`, `º`) —
|
||||
**sunt corecte, nu le "corecta" fără să verifici encoding-ul.**
|
||||
|
||||
## Cum se verifică dacă un fișier `.sc2`/`.vc2` e corupt
|
||||
|
||||
```powershell
|
||||
$bytes = [System.IO.File]::ReadAllBytes("<path>.vc2")
|
||||
$text = [System.Text.Encoding]::GetEncoding(1252).GetString($bytes)
|
||||
$text -split "`r`n" | Select-String ([char]0xFFFD) # cauta caracterul de replacement
|
||||
```
|
||||
|
||||
Dacă apare `�` (sau `$text` conține U+FFFD) în output — fișierul are corupere de encoding.
|
||||
|
||||
## Cum se repară
|
||||
|
||||
1. **Nu edita orbește peste corupere** — caracterul original e deja pierdut din fișierul
|
||||
curent.
|
||||
2. Dacă fișierul e sub control de versiune (git) și corupera s-a întâmplat **într-o sesiune
|
||||
anterioară necomisă** (deci HEAD-ul git încă are versiunea curată): recuperează originalul
|
||||
convertind binarul din HEAD în text și comparând:
|
||||
```bash
|
||||
git show HEAD:<cale>.vcx > /tmp/head.vcx
|
||||
git show HEAD:<cale>.vct > /tmp/head.vct # (sau .VCT, dupa caz)
|
||||
powershell -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source /tmp/head.vcx -CacheRoot /tmp/head_out
|
||||
```
|
||||
apoi decodează ambele fișiere (HEAD curat + curent corupt) ca cp1252 și compară linie cu
|
||||
linie (PowerShell, nu `diff` direct — `diff`/Bash nu decodează cp1252 corect pentru afișare,
|
||||
deși detectează totuși diferența de octeți).
|
||||
3. Reconstruiește fișierul text pornind de la versiunea HEAD (curată), și reaplică DOAR
|
||||
modificările intenționate din sesiunea curentă peste ea (nu invers — nu încerca să "cârpești"
|
||||
fișierul corupt caracter cu caracter, e mai sigur să repornești de la baza curată).
|
||||
4. Scrie rezultatul înapoi ca bytes cp1252 (`[System.Text.Encoding]::GetEncoding(1252).GetBytes(...)`),
|
||||
NU ca string UTF-8/`Out-File` implicit (care scrie UTF-8 sau UTF-16 după caz).
|
||||
5. Rulează write-back (`txt2vcx.ps1 -Force`) și verifică fidelity check = zero diferențe.
|
||||
|
||||
## Cum se evită pe viitor
|
||||
|
||||
Când editezi `.sc2`/`.vc2` cu tool-uri text (Read/Edit/Write), verifică întâi dacă fișierul
|
||||
conține diacritice (`ã`, `þ`, `ª`, `º`, `î`, `â` etc.) — dacă da, **orice rescrie completă a
|
||||
fișierului trebuie făcută la nivel de octeți cu encoding cp1252 explicit**, nu presupunând
|
||||
UTF-8 implicit. Editările punctuale (Edit tool, string replace) sunt sigure DOAR dacă tool-ul
|
||||
păstrează restul fișierului byte-identic (nu rescrie tot fișierul reîncodat).
|
||||
|
||||
## Vezi și
|
||||
|
||||
`PROMPT_cautare_vfp.md` din acest folder, pasul 3.c — menționează deja riscul ("Headerul
|
||||
CPID="1252" poate minți...") pe scurt; acest fișier e detalierea completă (tabel de caractere,
|
||||
pași de recuperare din git).
|
||||
# Capcană: corupere diacritice la editarea `.sc2`/`.vc2` (encoding cp1252)
|
||||
|
||||
Partajat între proiectele ROA* (similar cu `PROMPT_cautare_vfp.md` din acest folder) — capcana
|
||||
ține de formatul `.sc2`/`.vc2` produs de FoxBin2Prg, nu de un proiect anume.
|
||||
|
||||
Descoperit de 2 ori în aceeași sesiune (2026-07-10, în ROAAUTO): odată în
|
||||
`COMUN/clase/cmd_butoane.vc2` (clasa `cmd_select_adv`), odată în `Clase/ofundal_dev.vc2`
|
||||
(meniul principal) — de fiecare dată un agent anterior a editat text-cache-ul cu un tool care
|
||||
nu scrie cp1252 nativ, și a corupt TOATE caracterele cu diacritice din fișier, nu doar linia
|
||||
pe care voia s-o schimbe.
|
||||
|
||||
## De ce se întâmplă
|
||||
|
||||
Fișierele `.sc2`/`.vc2` generate de FoxBin2Prg sunt **cp1252 (Windows-1252)**, nu UTF-8
|
||||
(vezi antetul fiecărui fișier: `CPID="1252"`). Dacă un editor/tool citește fișierul ca UTF-8
|
||||
(sau alt encoding), fiecare byte >= 0x80 (diacritic) devine invalid ca secvență UTF-8 și e
|
||||
înlocuit cu caracterul de replacement U+FFFD. Dacă apoi tool-ul **salvează rezultatul tot ca
|
||||
UTF-8**, acel U+FFFD e scris ca 3 octeți UTF-8 (`0xEF 0xBF 0xBD`) — care, citiți înapoi ca
|
||||
cp1252 (cum face FoxBin2Prg la write-back), apar ca `�`. Rezultatul: caracterul original e
|
||||
**ireversibil pierdut** (nu mai există în fișier sub nicio formă) — recuperabil DOAR din altă
|
||||
sursă (git history, backup).
|
||||
|
||||
Codebase-ul ROA folosește un hack vechi de "reciclare" a unor caractere cp1252 needependente
|
||||
de Ș/ă/ț (care nu au echivalent direct în cp1252) pentru diacritice românești:
|
||||
|
||||
| Literă românească | Caracter folosit (cp1252) | Byte |
|
||||
|---|---|---|
|
||||
| ă | ã (a-tilde) | `0xE3` |
|
||||
| Ă | Ã | `0xC3` |
|
||||
| ț | þ (thorn minuscul) | `0xFE` |
|
||||
| Ș (majusculă) | ª (ordinal masculin) | `0xAA` |
|
||||
| ș (minusculă) | º (ordinal feminin) | `0xBA` |
|
||||
| î, â | î, â (existente nativ în cp1252) | `0xEE`, `0xE2` |
|
||||
|
||||
Aceste caractere par "gunoi"/typo la prima vedere într-un editor UTF-8 (`ã`, `þ`, `ª`, `º`) —
|
||||
**sunt corecte, nu le "corecta" fără să verifici encoding-ul.**
|
||||
|
||||
## Cum se verifică dacă un fișier `.sc2`/`.vc2` e corupt
|
||||
|
||||
```powershell
|
||||
$bytes = [System.IO.File]::ReadAllBytes("<path>.vc2")
|
||||
$text = [System.Text.Encoding]::GetEncoding(1252).GetString($bytes)
|
||||
$text -split "`r`n" | Select-String ([char]0xFFFD) # cauta caracterul de replacement
|
||||
```
|
||||
|
||||
Dacă apare `�` (sau `$text` conține U+FFFD) în output — fișierul are corupere de encoding.
|
||||
|
||||
## Cum se repară
|
||||
|
||||
1. **Nu edita orbește peste corupere** — caracterul original e deja pierdut din fișierul
|
||||
curent.
|
||||
2. Dacă fișierul e sub control de versiune (git) și corupera s-a întâmplat **într-o sesiune
|
||||
anterioară necomisă** (deci HEAD-ul git încă are versiunea curată): recuperează originalul
|
||||
convertind binarul din HEAD în text și comparând:
|
||||
```bash
|
||||
git show HEAD:<cale>.vcx > /tmp/head.vcx
|
||||
git show HEAD:<cale>.vct > /tmp/head.vct # (sau .VCT, dupa caz)
|
||||
powershell -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source /tmp/head.vcx -CacheRoot /tmp/head_out
|
||||
```
|
||||
apoi decodează ambele fișiere (HEAD curat + curent corupt) ca cp1252 și compară linie cu
|
||||
linie (PowerShell, nu `diff` direct — `diff`/Bash nu decodează cp1252 corect pentru afișare,
|
||||
deși detectează totuși diferența de octeți).
|
||||
3. Reconstruiește fișierul text pornind de la versiunea HEAD (curată), și reaplică DOAR
|
||||
modificările intenționate din sesiunea curentă peste ea (nu invers — nu încerca să "cârpești"
|
||||
fișierul corupt caracter cu caracter, e mai sigur să repornești de la baza curată).
|
||||
4. Scrie rezultatul înapoi ca bytes cp1252 (`[System.Text.Encoding]::GetEncoding(1252).GetBytes(...)`),
|
||||
NU ca string UTF-8/`Out-File` implicit (care scrie UTF-8 sau UTF-16 după caz).
|
||||
5. Rulează write-back (`txt2vcx.ps1 -Force`) și verifică fidelity check = zero diferențe.
|
||||
|
||||
## Cum se evită pe viitor
|
||||
|
||||
Când editezi `.sc2`/`.vc2` cu tool-uri text (Read/Edit/Write), verifică întâi dacă fișierul
|
||||
conține diacritice (`ã`, `þ`, `ª`, `º`, `î`, `â` etc.) — dacă da, **orice rescrie completă a
|
||||
fișierului trebuie făcută la nivel de octeți cu encoding cp1252 explicit**, nu presupunând
|
||||
UTF-8 implicit. Editările punctuale (Edit tool, string replace) sunt sigure DOAR dacă tool-ul
|
||||
păstrează restul fișierului byte-identic (nu rescrie tot fișierul reîncodat).
|
||||
|
||||
## Vezi și
|
||||
|
||||
`PROMPT_cautare_vfp.md` din acest folder, pasul 3.c — menționează deja riscul ("Headerul
|
||||
CPID="1252" poate minți...") pe scurt; acest fișier e detalierea completă (tabel de caractere,
|
||||
pași de recuperare din git).
|
||||
|
||||
@@ -1,65 +1,65 @@
|
||||
# Capcană: `ALTER TABLE` pe cursorul întors de `goExecutor.oExecute()`
|
||||
|
||||
Partajat între proiectele ROA* — `goExecutor` (clasa `oExecutor`, definită în
|
||||
`COMUN/programe/oproceduri_comune.prg`, metoda `oExecute`) e utilitarul standard pentru
|
||||
interogări SQL pass-through (`SQLExec`) către Oracle, folosit peste tot în codul ROA*.
|
||||
|
||||
## Ce nu funcționează
|
||||
|
||||
```foxpro
|
||||
lnSucces = goExecutor.oExecute(lcSql, lcCursor)
|
||||
...
|
||||
ALTER TABLE (lcCursor) ADD COLUMN coloananoua L && <- pică
|
||||
```
|
||||
|
||||
Cursorul întors de `oExecute()` (rezultatul unui `SQLExec`) poate refuza comenzi DDL
|
||||
ulterioare, cu erori în lanț (descoperite empiric, în această ordine, în ROAAUTO
|
||||
`autopass_cursor_comenzi`/`autopass_cursor_operatii`):
|
||||
|
||||
1. `Function is not supported on remote tables.` — pe `ALTER TABLE` direct pe cursorul
|
||||
original.
|
||||
2. Chiar și după o încercare de rematerializare (`SELECT * FROM (cursor) INTO CURSOR
|
||||
(acelasi_nume) READWRITE`) → `Alias name is already in use.` (sursa și ținta nu pot
|
||||
avea același nume într-un `SELECT...INTO CURSOR`).
|
||||
3. Cu un alias scratch diferit ca țintă (`SELECT * FROM (cursor) INTO CURSOR
|
||||
(nume_final_diferit_de_sursa) READWRITE`) → tot `Invalid operation for the cursor.` pe
|
||||
`ALTER TABLE`, chiar dacă acum cursorul final teoretic ar trebui să fie unul local
|
||||
obișnuit.
|
||||
|
||||
Nu există niciun alt loc în codul ROA* care să facă `ALTER TABLE` imediat după
|
||||
`goExecutor.oExecute()` — deci acest pattern nu avea niciun precedent testat înainte de
|
||||
funcțiile AUTOPASS.
|
||||
|
||||
## Ce funcționează
|
||||
|
||||
**Nu folosi `ALTER TABLE` deloc pe rezultatul unui `oExecute()`.** Include coloanele
|
||||
suplimentare direct în `SELECT`-ul de rematerializare, ca expresii literale alături de `*`
|
||||
(VFP suportă `SELECT *, expr AS coloana FROM ...`):
|
||||
|
||||
```foxpro
|
||||
lcCursorRaw = lcCursor + '_raw'
|
||||
IF USED(lcCursorRaw)
|
||||
USE IN (lcCursorRaw)
|
||||
ENDIF
|
||||
|
||||
lnSucces = goExecutor.oExecute(lcSql, lcCursorRaw)
|
||||
IF lnSucces < 0
|
||||
* tratare eroare, RETURN
|
||||
ENDIF
|
||||
|
||||
SELECT *, .F. AS coloananoua, SPACE(100) AS altacoloana ;
|
||||
FROM (lcCursorRaw) INTO CURSOR (lcCursor) READWRITE
|
||||
USE IN (lcCursorRaw)
|
||||
|
||||
* de-aici incolo doar REPLACE (date), NICIODATA ALTER TABLE (structura) pe (lcCursor)
|
||||
```
|
||||
|
||||
După acest pas, cursorul (`lcCursor`) e un cursor local obișnuit — `ALTER TABLE` funcționează
|
||||
normal pe el DUPĂ ACEEA (ex. dintr-o altă funcție care primește cursorul deja gata construit,
|
||||
nu direct rezultatul unui `oExecute`), doar comanda imediat următoare unui `oExecute()` e
|
||||
restricționată.
|
||||
|
||||
## Vezi și
|
||||
|
||||
Exemplu complet aplicat: ROAAUTO, `Programe/oproceduri_autopass.prg`,
|
||||
`autopass_cursor_comenzi()`/`autopass_cursor_operatii()`.
|
||||
# Capcană: `ALTER TABLE` pe cursorul întors de `goExecutor.oExecute()`
|
||||
|
||||
Partajat între proiectele ROA* — `goExecutor` (clasa `oExecutor`, definită în
|
||||
`COMUN/programe/oproceduri_comune.prg`, metoda `oExecute`) e utilitarul standard pentru
|
||||
interogări SQL pass-through (`SQLExec`) către Oracle, folosit peste tot în codul ROA*.
|
||||
|
||||
## Ce nu funcționează
|
||||
|
||||
```foxpro
|
||||
lnSucces = goExecutor.oExecute(lcSql, lcCursor)
|
||||
...
|
||||
ALTER TABLE (lcCursor) ADD COLUMN coloananoua L && <- pică
|
||||
```
|
||||
|
||||
Cursorul întors de `oExecute()` (rezultatul unui `SQLExec`) poate refuza comenzi DDL
|
||||
ulterioare, cu erori în lanț (descoperite empiric, în această ordine, în ROAAUTO
|
||||
`autopass_cursor_comenzi`/`autopass_cursor_operatii`):
|
||||
|
||||
1. `Function is not supported on remote tables.` — pe `ALTER TABLE` direct pe cursorul
|
||||
original.
|
||||
2. Chiar și după o încercare de rematerializare (`SELECT * FROM (cursor) INTO CURSOR
|
||||
(acelasi_nume) READWRITE`) → `Alias name is already in use.` (sursa și ținta nu pot
|
||||
avea același nume într-un `SELECT...INTO CURSOR`).
|
||||
3. Cu un alias scratch diferit ca țintă (`SELECT * FROM (cursor) INTO CURSOR
|
||||
(nume_final_diferit_de_sursa) READWRITE`) → tot `Invalid operation for the cursor.` pe
|
||||
`ALTER TABLE`, chiar dacă acum cursorul final teoretic ar trebui să fie unul local
|
||||
obișnuit.
|
||||
|
||||
Nu există niciun alt loc în codul ROA* care să facă `ALTER TABLE` imediat după
|
||||
`goExecutor.oExecute()` — deci acest pattern nu avea niciun precedent testat înainte de
|
||||
funcțiile AUTOPASS.
|
||||
|
||||
## Ce funcționează
|
||||
|
||||
**Nu folosi `ALTER TABLE` deloc pe rezultatul unui `oExecute()`.** Include coloanele
|
||||
suplimentare direct în `SELECT`-ul de rematerializare, ca expresii literale alături de `*`
|
||||
(VFP suportă `SELECT *, expr AS coloana FROM ...`):
|
||||
|
||||
```foxpro
|
||||
lcCursorRaw = lcCursor + '_raw'
|
||||
IF USED(lcCursorRaw)
|
||||
USE IN (lcCursorRaw)
|
||||
ENDIF
|
||||
|
||||
lnSucces = goExecutor.oExecute(lcSql, lcCursorRaw)
|
||||
IF lnSucces < 0
|
||||
* tratare eroare, RETURN
|
||||
ENDIF
|
||||
|
||||
SELECT *, .F. AS coloananoua, SPACE(100) AS altacoloana ;
|
||||
FROM (lcCursorRaw) INTO CURSOR (lcCursor) READWRITE
|
||||
USE IN (lcCursorRaw)
|
||||
|
||||
* de-aici incolo doar REPLACE (date), NICIODATA ALTER TABLE (structura) pe (lcCursor)
|
||||
```
|
||||
|
||||
După acest pas, cursorul (`lcCursor`) e un cursor local obișnuit — `ALTER TABLE` funcționează
|
||||
normal pe el DUPĂ ACEEA (ex. dintr-o altă funcție care primește cursorul deja gata construit,
|
||||
nu direct rezultatul unui `oExecute`), doar comanda imediat următoare unui `oExecute()` e
|
||||
restricționată.
|
||||
|
||||
## Vezi și
|
||||
|
||||
Exemplu complet aplicat: ROAAUTO, `Programe/oproceduri_autopass.prg`,
|
||||
`autopass_cursor_comenzi()`/`autopass_cursor_operatii()`.
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
# Convenție UX pentru formulare VFP (preferința lui Marius, valabilă pe toate proiectele ROA*)
|
||||
|
||||
Partajat între proiectele ROA* (similar cu `PROMPT_cautare_vfp.md`, `prompt_project_insights_docs.md`
|
||||
din acest folder) — pentru că `COMUN\` e clonat/sincronizat în fiecare aplicație ROA, e locul
|
||||
corect pentru o convenție de design care nu ține de un singur proiect.
|
||||
|
||||
Origine: confirmat de Marius pe `frm_autopass.scx` (ROAAUTO) după o rundă de regrupare vizuală
|
||||
(2026-07-10) — "imi place designul acesta" pe layout-ul cu rânduri clar separate pe funcție,
|
||||
butoane grupate la margini, fără elemente lipite unele de altele.
|
||||
|
||||
## Ce înseamnă in practică, pe proprietăți VFP
|
||||
|
||||
- **Fiecare grup funcțional pe rândul lui** — nu înghesui controale fără legătură directă pe
|
||||
același `Top`. Ex: rândul de perioadă (date + Actualizează) separat de rândul de
|
||||
statistici (Declarabile/Transmise/Blocate), separat de panoul de configurare.
|
||||
- **Spațiere vizibilă între grupuri, strânsă în interiorul unui grup** — butoane din
|
||||
aceeași acțiune (ex. Validează dry-run → Transmite → Renunță) la 6-10px unele de altele;
|
||||
gap de 20-30px față de următorul grup funcțional (ex. Selectează tot vs. grupul
|
||||
Validare/Transmitere vs. Actualizează statusuri).
|
||||
- **Butoanele secundare/de configurare aliniate la marginea din dreapta a containerului**,
|
||||
nu lipite imediat după textbox-ul pe care îl controlează — altfel nu se disting vizual ca
|
||||
acțiune separată de câmpul de input.
|
||||
- **Acțiunea principală + oprirea ei alăturate** — un buton de tip "Renunță/Oprește" trebuie
|
||||
poziționat lângă acțiunea pe care o anulează (ex. Transmite + Renunță), nu împrăștiat în
|
||||
altă parte a rândului.
|
||||
- **Un singur rând de acțiuni cât se poate** — dacă mai multe grupuri de butoane încap pe
|
||||
lățimea formei, preferă un singur rând orizontal în loc să adaugi rânduri noi dedesubt;
|
||||
păstrează formele compacte pe verticală.
|
||||
- **Caption-uri scurte, sentence case, nu ALL CAPS** — ex. "Transmite" nu "TRANSMITE";
|
||||
"Dashboard AutoPass" nu "Deschide dashboard AUTOPASS". ALL CAPS/text lung pe un buton
|
||||
citește ca zgomot, nu ca ierarhie.
|
||||
- **Culoare = semnal, nu decor** — folosește culoare distinctă doar pentru acțiuni cu
|
||||
semnificație clară (verde = acțiune pozitivă/transmite, roșu = oprire/pericol, albastru =
|
||||
navigare/deschidere link extern); restul butoanelor rămân stilul implicit din `_baza.vcx`.
|
||||
|
||||
## Vocabular
|
||||
|
||||
Funcțional, compact, aerisit, minimalist, grupat, ușor de înțeles de utilizatori, aer aerisit,
|
||||
modern — asta e reperul calitativ pentru orice formular nou sau refacere de layout, dincolo de
|
||||
regulile mecanice de mai sus, pe orice aplicație ROA*.
|
||||
|
||||
## Vezi și
|
||||
|
||||
- `PROMPT_cautare_vfp.md` din acest folder — cum se caută/editează cod în binarele VFP text-cache
|
||||
(relevant când aplici aceste reguli prin fluxul `.sc2`/`.vc2` + write-back).
|
||||
- Capcana de encoding cp1252 la editarea `.sc2`/`.vc2` (corupere diacritice) — documentată în
|
||||
proiectul unde a fost descoperită (ROAAUTO `docs/conventie_encoding_cp1252.md`); relevantă ori
|
||||
de câte ori editezi text-cache-ul unui formular/librărie pentru a aplica aceste reguli de UX.
|
||||
# Convenție UX pentru formulare VFP (preferința lui Marius, valabilă pe toate proiectele ROA*)
|
||||
|
||||
Partajat între proiectele ROA* (similar cu `PROMPT_cautare_vfp.md`, `prompt_project_insights_docs.md`
|
||||
din acest folder) — pentru că `COMUN\` e clonat/sincronizat în fiecare aplicație ROA, e locul
|
||||
corect pentru o convenție de design care nu ține de un singur proiect.
|
||||
|
||||
Origine: confirmat de Marius pe `frm_autopass.scx` (ROAAUTO) după o rundă de regrupare vizuală
|
||||
(2026-07-10) — "imi place designul acesta" pe layout-ul cu rânduri clar separate pe funcție,
|
||||
butoane grupate la margini, fără elemente lipite unele de altele.
|
||||
|
||||
## Ce înseamnă in practică, pe proprietăți VFP
|
||||
|
||||
- **Fiecare grup funcțional pe rândul lui** — nu înghesui controale fără legătură directă pe
|
||||
același `Top`. Ex: rândul de perioadă (date + Actualizează) separat de rândul de
|
||||
statistici (Declarabile/Transmise/Blocate), separat de panoul de configurare.
|
||||
- **Spațiere vizibilă între grupuri, strânsă în interiorul unui grup** — butoane din
|
||||
aceeași acțiune (ex. Validează dry-run → Transmite → Renunță) la 6-10px unele de altele;
|
||||
gap de 20-30px față de următorul grup funcțional (ex. Selectează tot vs. grupul
|
||||
Validare/Transmitere vs. Actualizează statusuri).
|
||||
- **Butoanele secundare/de configurare aliniate la marginea din dreapta a containerului**,
|
||||
nu lipite imediat după textbox-ul pe care îl controlează — altfel nu se disting vizual ca
|
||||
acțiune separată de câmpul de input.
|
||||
- **Acțiunea principală + oprirea ei alăturate** — un buton de tip "Renunță/Oprește" trebuie
|
||||
poziționat lângă acțiunea pe care o anulează (ex. Transmite + Renunță), nu împrăștiat în
|
||||
altă parte a rândului.
|
||||
- **Un singur rând de acțiuni cât se poate** — dacă mai multe grupuri de butoane încap pe
|
||||
lățimea formei, preferă un singur rând orizontal în loc să adaugi rânduri noi dedesubt;
|
||||
păstrează formele compacte pe verticală.
|
||||
- **Caption-uri scurte, sentence case, nu ALL CAPS** — ex. "Transmite" nu "TRANSMITE";
|
||||
"Dashboard AutoPass" nu "Deschide dashboard AUTOPASS". ALL CAPS/text lung pe un buton
|
||||
citește ca zgomot, nu ca ierarhie.
|
||||
- **Culoare = semnal, nu decor** — folosește culoare distinctă doar pentru acțiuni cu
|
||||
semnificație clară (verde = acțiune pozitivă/transmite, roșu = oprire/pericol, albastru =
|
||||
navigare/deschidere link extern); restul butoanelor rămân stilul implicit din `_baza.vcx`.
|
||||
|
||||
## Vocabular
|
||||
|
||||
Funcțional, compact, aerisit, minimalist, grupat, ușor de înțeles de utilizatori, aer aerisit,
|
||||
modern — asta e reperul calitativ pentru orice formular nou sau refacere de layout, dincolo de
|
||||
regulile mecanice de mai sus, pe orice aplicație ROA*.
|
||||
|
||||
## Vezi și
|
||||
|
||||
- `PROMPT_cautare_vfp.md` din acest folder — cum se caută/editează cod în binarele VFP text-cache
|
||||
(relevant când aplici aceste reguli prin fluxul `.sc2`/`.vc2` + write-back).
|
||||
- Capcana de encoding cp1252 la editarea `.sc2`/`.vc2` (corupere diacritice) — documentată în
|
||||
proiectul unde a fost descoperită (ROAAUTO `docs/conventie_encoding_cp1252.md`); relevantă ori
|
||||
de câte ori editezi text-cache-ul unui formular/librărie pentru a aplica aceste reguli de UX.
|
||||
|
||||
@@ -1,61 +1,61 @@
|
||||
# Export surse Oracle (PACK_CONTAFIN & co.) — cum se face
|
||||
|
||||
`PACK_CONTAFIN.pck` din acest folder este exportul sursei pachetului PL/SQL `PACK_CONTAFIN`.
|
||||
**Claude Code își face singur exportul/reîmprospătarea** — nu mai e nevoie de export manual din
|
||||
PL/SQL Developer.
|
||||
|
||||
## Conexiune
|
||||
|
||||
- Client: `D:\ROA\instantclient_19_18\sqlplus.exe` (`TNS_ADMIN` e deja setat spre același folder).
|
||||
- Alias TNS: `ROA_CENTRAL` → `10.0.20.121:1521`, `SERVICE_NAME=ROA` (vezi `tnsnames.ora`).
|
||||
- Schema/utilizator: `MARIUSM_AUTO` (schema de dezvoltare a lui Marius).
|
||||
- **Parola nu e versionată** — se află local, în `D:\ROA\ROAGEST\docs\local\oracle.md`
|
||||
(folder ignorat de git), pe mașina de lucru.
|
||||
|
||||
`PACK_CONTAFIN` există în schemele `MARIUSM_AUTO` (dev) și `ACN`, plus un sinonim `PUBLIC`.
|
||||
Exportul de referință se face din `MARIUSM_AUTO`.
|
||||
|
||||
## Gotcha sqlplus pe Windows/PowerShell
|
||||
|
||||
Nu trimite SQL prin pipe din PowerShell (`'select...' | sqlplus`) — BOM-ul UTF-16 sparge parserul
|
||||
(`SP2-0734: unknown command beginning "select..."`). Scrie un fișier `.sql` cu encoding **ASCII**
|
||||
și rulează-l cu `@fisier.sql`.
|
||||
|
||||
## Comanda de export (re-generare .pck)
|
||||
|
||||
```sql
|
||||
-- export_pack.sql
|
||||
set pagesize 0 linesize 400 trimspool on feedback off heading off termout off
|
||||
spool D:\ROA\ROAGEST\COMUN\docs\PACK_CONTAFIN.pck
|
||||
select text from all_source where owner='MARIUSM_AUTO' and name='PACK_CONTAFIN' and type='PACKAGE' order by line;
|
||||
select '/' from dual;
|
||||
select text from all_source where owner='MARIUSM_AUTO' and name='PACK_CONTAFIN' and type='PACKAGE BODY' order by line;
|
||||
select '/' from dual;
|
||||
spool off
|
||||
exit
|
||||
```
|
||||
|
||||
```powershell
|
||||
& 'D:\ROA\instantclient_19_18\sqlplus.exe' -L -S 'MARIUSM_AUTO/<parola>@ROA_CENTRAL' '@export_pack.sql'
|
||||
```
|
||||
|
||||
Același tipar merge pentru orice alt pachet/procedură (`PACK_SESIUNE`, `PACK_PRETURI`, …) sau pentru
|
||||
DDL de tabele/view-uri (`all_tab_columns`, `dbms_metadata.get_ddl`).
|
||||
|
||||
## Ce e strict necesar de știut despre PACK_CONTAFIN
|
||||
|
||||
Pachetul central de **scriere a documentelor** — clientul VFP populează tabelele temporare
|
||||
`ACT_TEMP`/`RUL_TEMP` (prin `oscrie_in_fisiere`-ul din COMUN), apoi pachetul distribuie:
|
||||
|
||||
- `SCRIE_IN_FISIERE` — orchestratorul (apelat per document).
|
||||
- `SCRIE_IN_ACT` — `ACT_TEMP` → `ACT` (notele contabile).
|
||||
- `SCRIE_IN_RUL` — `RUL_TEMP` → `RUL` (mișcările de stoc); completează `COD`, `DATAORA`, `ID_FACT`
|
||||
(min. `id_fact` fără conturi 5xx), `ID_SUCURSALA`, `DATAIN`/`DATAOUT` din `dataact`, opțional
|
||||
`ID_RUL_AUX` pe furnizor (opțiunea de firmă `RULAJFURNIZOR`). **Scrie exact ce e în RUL_TEMP — nu
|
||||
derivă rulaje din ACT**, deci filtrarea liniilor de rulaj se face în clientul VFP.
|
||||
- `SCRIE_IN_RUL_OBINV` / `SCRIE_IN_STOC` / `SCRIE_IN_STOC_OBINV` — variantele pentru obiecte de
|
||||
inventar și actualizarea stocului.
|
||||
- `VERIFICA_NOTE_CONTABILE`, `SCRIE_JC_2007`/`SCRIE_JV_2007` (jurnale TVA),
|
||||
`SCRIE_IN_BALANTA(_PARTENERI)`, `sterge_document`, `finalizeaza_document_*`.
|
||||
- Stare de sesiune prin settere/gettere (`SET_COD`/`GET_COD`, `SET_IDFACT`, `SET_ID_SUCURSALA`, …)
|
||||
+ `PACK_SESIUNE` (an/lună, opțiuni firmă).
|
||||
# Export surse Oracle (PACK_CONTAFIN & co.) — cum se face
|
||||
|
||||
`PACK_CONTAFIN.pck` din acest folder este exportul sursei pachetului PL/SQL `PACK_CONTAFIN`.
|
||||
**Claude Code își face singur exportul/reîmprospătarea** — nu mai e nevoie de export manual din
|
||||
PL/SQL Developer.
|
||||
|
||||
## Conexiune
|
||||
|
||||
- Client: `D:\ROA\instantclient_19_18\sqlplus.exe` (`TNS_ADMIN` e deja setat spre același folder).
|
||||
- Alias TNS: `ROA_CENTRAL` → `10.0.20.121:1521`, `SERVICE_NAME=ROA` (vezi `tnsnames.ora`).
|
||||
- Schema/utilizator: `MARIUSM_AUTO` (schema de dezvoltare a lui Marius).
|
||||
- **Parola nu e versionată** — se află local, în `D:\ROA\ROAGEST\docs\local\oracle.md`
|
||||
(folder ignorat de git), pe mașina de lucru.
|
||||
|
||||
`PACK_CONTAFIN` există în schemele `MARIUSM_AUTO` (dev) și `ACN`, plus un sinonim `PUBLIC`.
|
||||
Exportul de referință se face din `MARIUSM_AUTO`.
|
||||
|
||||
## Gotcha sqlplus pe Windows/PowerShell
|
||||
|
||||
Nu trimite SQL prin pipe din PowerShell (`'select...' | sqlplus`) — BOM-ul UTF-16 sparge parserul
|
||||
(`SP2-0734: unknown command beginning "select..."`). Scrie un fișier `.sql` cu encoding **ASCII**
|
||||
și rulează-l cu `@fisier.sql`.
|
||||
|
||||
## Comanda de export (re-generare .pck)
|
||||
|
||||
```sql
|
||||
-- export_pack.sql
|
||||
set pagesize 0 linesize 400 trimspool on feedback off heading off termout off
|
||||
spool D:\ROA\ROAGEST\COMUN\docs\PACK_CONTAFIN.pck
|
||||
select text from all_source where owner='MARIUSM_AUTO' and name='PACK_CONTAFIN' and type='PACKAGE' order by line;
|
||||
select '/' from dual;
|
||||
select text from all_source where owner='MARIUSM_AUTO' and name='PACK_CONTAFIN' and type='PACKAGE BODY' order by line;
|
||||
select '/' from dual;
|
||||
spool off
|
||||
exit
|
||||
```
|
||||
|
||||
```powershell
|
||||
& 'D:\ROA\instantclient_19_18\sqlplus.exe' -L -S 'MARIUSM_AUTO/<parola>@ROA_CENTRAL' '@export_pack.sql'
|
||||
```
|
||||
|
||||
Același tipar merge pentru orice alt pachet/procedură (`PACK_SESIUNE`, `PACK_PRETURI`, …) sau pentru
|
||||
DDL de tabele/view-uri (`all_tab_columns`, `dbms_metadata.get_ddl`).
|
||||
|
||||
## Ce e strict necesar de știut despre PACK_CONTAFIN
|
||||
|
||||
Pachetul central de **scriere a documentelor** — clientul VFP populează tabelele temporare
|
||||
`ACT_TEMP`/`RUL_TEMP` (prin `oscrie_in_fisiere`-ul din COMUN), apoi pachetul distribuie:
|
||||
|
||||
- `SCRIE_IN_FISIERE` — orchestratorul (apelat per document).
|
||||
- `SCRIE_IN_ACT` — `ACT_TEMP` → `ACT` (notele contabile).
|
||||
- `SCRIE_IN_RUL` — `RUL_TEMP` → `RUL` (mișcările de stoc); completează `COD`, `DATAORA`, `ID_FACT`
|
||||
(min. `id_fact` fără conturi 5xx), `ID_SUCURSALA`, `DATAIN`/`DATAOUT` din `dataact`, opțional
|
||||
`ID_RUL_AUX` pe furnizor (opțiunea de firmă `RULAJFURNIZOR`). **Scrie exact ce e în RUL_TEMP — nu
|
||||
derivă rulaje din ACT**, deci filtrarea liniilor de rulaj se face în clientul VFP.
|
||||
- `SCRIE_IN_RUL_OBINV` / `SCRIE_IN_STOC` / `SCRIE_IN_STOC_OBINV` — variantele pentru obiecte de
|
||||
inventar și actualizarea stocului.
|
||||
- `VERIFICA_NOTE_CONTABILE`, `SCRIE_JC_2007`/`SCRIE_JV_2007` (jurnale TVA),
|
||||
`SCRIE_IN_BALANTA(_PARTENERI)`, `sterge_document`, `finalizeaza_document_*`.
|
||||
- Stare de sesiune prin settere/gettere (`SET_COD`/`GET_COD`, `SET_IDFACT`, `SET_ID_SUCURSALA`, …)
|
||||
+ `PACK_SESIUNE` (an/lună, opțiuni firmă).
|
||||
|
||||
Reference in New Issue
Block a user