#6 editare factura emisa: S4 runda 3 completa (pagina de articole editabila)

frm_modific2024, pgfArticole.PAGE3 - editare in memorie, fara scriere in Oracle
(aceea ramane S5).

- sub-blocul A: cantitate/pret/pret_cu_tva editabile inline, marcaj lmodificat
  pe linie, coloana valoare pe linie
- sub-blocul B: stergere logica de linii (sters/DynamicForeColor gri) si adaugare
  de linii prin frm_articol_factura, cu alegerea articolului prin caut_articol()
- sub-blocul C: bara de totaluri sub grid (total linii convertit RON la cursul
  documentului, discount de antet editabil, total net), ascunsa pe
  transfer/custodie; verdict de corelatie ACT/RUL informativ, cu 3 stari
- suma ACT: sold net debit-credit, cont pe tip de document (4111 / 418 / 461,
  iar pe rate/contract 4111, 411 sau 461)
- suma RUL: doar ID_TIP_RULAJ = 0, adica miscarile reale; perechile
  ID_TIP_RULAJ = 3 sunt virtuale (tin locul procesului verbal de schimbare de
  pret) si nu intra in suma. Corectie cu liniile nestocate, marcata "ajustat"
- adaugarea de linii pe document in valuta: dialogul primeste tip_valuta si
  cursul documentului de pe tvanz, deci pretul se introduce direct in valuta;
  ofacturare.vc2 ramane neatins
- cei 5 apelanti frm_modific2024 (afisjurcom, anaf_efactura, cele doua .sc2 de
  import) pregatesc cursorul de articole inainte de Createobject, gardat pe
  SET PROCEDURE - registrul jurnal din ROACONT/ROAGEST ramane neschimbat

Teste headless pe MARIUSM_AUTO, suite care isi descopera singure documentele:
test_page3_articole 14/2 (cele 2 = artefact de grid nematerializat headless,
acoperit pe ecran), test_incarca_vanzare_din_nota 5/0,
test_adauga_linie_articol 20/0, test_adauga_linie_valuta 16/0,
test_ui_sterge_linie 8/0, test_verdict_act_rul 26/0.

docs/todos.txt: punctele 13 si 20, scrise de Marius.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
This commit is contained in:
2026-08-09 20:48:42 +03:00
parent 13b4f65723
commit b9eba29ebe
26 changed files with 3310 additions and 172 deletions

View File

@@ -1,40 +1,66 @@
# Capcană: corupere diacritice la editarea `.sc2`/`.vc2` (encoding cp1252)
# Capcană: corupere diacritice la editarea `.sc2`/`.vc2`
Partajat între proiectele ROA* — capcana ține de formatul `.sc2`/`.vc2` produs de FoxBin2Prg,
nu de un proiect anume.
## De ce se întâmplă
Fișierele `.sc2`/`.vc2` sunt **cp1252** (Windows-1252), nu UTF-8 (vezi antetul: `CPID="1252"`).
Fișierele `.sc2`/`.vc2` sunt **cp1250** (Windows-1250, Europa Centrală), nu UTF-8 — deși
antetul FoxBin2Prg declară `CPID="1252"`. Eticheta din antet nu corespunde conținutului:
controalele care poartă text cu diacritice au `FontCharSet = 238` (Europa de Est), adică VFP
le randează tot ca cp1250. Diferența nu e cosmetică — un `ă` real scris prin cp1252 nu are
echivalent în acel codepage și s-ar pierde; scris prin cp1250 (encoding-ul real al fișierului)
e pur și simplu octetul `0xE3`, corect și stabil.
Dacă un editor/tool citește fișierul ca UTF-8, fiecare byte >= 0x80 (diacritic) devine invalid
ca secvență UTF-8 și e înlocuit cu U+FFFD. Dacă tool-ul apoi **salvează tot ca UTF-8**, acel
U+FFFD e scris ca 3 octeți (`0xEF 0xBF 0xBD`) — care, citiți înapoi ca cp1252 (cum face
U+FFFD e scris ca 3 octeți (`0xEF 0xBF 0xBD`) — care, citiți înapoi ca cp1250 (cum face
FoxBin2Prg la write-back), apar ca `�`. Caracterul original e **ireversibil pierdut**
(recuperabil DOAR din altă sursă: git history, backup).
Codebase-ul ROA "reciclează" caractere cp1252 fără echivalent direct pentru Ș/ă/ț:
Octeții diacriticelor din codebase-ul ROA, cu adevărul (cp1250) și aparența dacă îi decodezi
greșit ca cp1252:
| Literă românească | Caracter folosit (cp1252) | Byte |
| Literă românească | Byte | Aparență dacă decodezi ca cp1252 |
|---|---|---|
| ă | ã (a-tilde) | `0xE3` |
| Ă | Ã | `0xC3` |
| ț | þ (thorn minuscul) | `0xFE` |
| Ș (majusculă) | ª (ordinal masculin) | `0xAA` |
| ș (minusculă) | º (ordinal feminin) | `0xBA` |
| î, â | î, â (native cp1252) | `0xEE`, `0xE2` |
| ă | `0xE3` | ã (a-tilde) |
| Ă | `0xC3` | Ã |
| î | `0xEE` | î (identic — zonă comună cp1250/cp1252) |
| Î | `0xCE` | Î (identic — zonă comună cp1250/cp1252) |
| â | `0xE2` | â (identic — zonă comună cp1250/cp1252) |
| ț | `0xFE` | þ (thorn minuscul) |
| Ș (majusculă) | `0xAA` | ª (ordinal masculin) |
| ș (minusculă) | `0xBA` | º (ordinal feminin) |
Par "gunoi"/typo într-un editor UTF-8 (`ã`, `þ`, `ª`, `º`) — **sunt corecte, nu le "corecta"
fără să verifici encoding-ul.**
Decodate cp1250 (encoding-ul real), aceste litere sunt diacritice românești normale — exact
ce apare în formular când fișierul e sănătos. Par "gunoi"/typo (`ã`, `þ`, `ª`, `º`) **doar
dacă le decodezi cu codepage-ul greșit** — nu le "corecta" fără să verifici encoding-ul real.
## Cum se verifică dacă un fișier `.sc2`/`.vc2` e corupt
Verificarea se face **pe octeți**, nu pe text decodat: un codepage single-byte (1250 sau 1252)
mapează fiecare octet la un caracter, deci nu produce niciodată U+FFFD — o căutare de
`[char]0xFFFD` în textul decodat nu găsește nimic nici pe un fișier stricat. Ce se caută e
secvența de trei octeți pe care a lăsat-o tool-ul care a stricat fișierul:
```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
$b = [System.IO.File]::ReadAllBytes("<path>.vc2")
$n = 0
for ($i = 0; $i -lt $b.Length - 2; $i++) {
if ($b[$i] -eq 0xEF -and $b[$i+1] -eq 0xBF -and $b[$i+2] -eq 0xBD) { $n++; $i += 2 }
}
"EF BF BD (U+FFFD) x $n" # orice valoare > 0 = fisier stricat
```
Dacă apare `�` (sau `$text` conține U+FFFD) — fișierul are corupere de encoding.
Echivalentul din Bash, util și pentru censul complet înainte/după orice editare (vezi
`reguli_lucru.md`, punctul 7):
```bash
od -An -tx1 <path>.vc2 | tr ' ' '\n' | grep -v '^$' | awk '$1>"7f"' | sort | uniq -c
```
Censul **crește** la stricare — un octet cp1250 devine trei octeți de U+FFFD — deci nu urmări
doar scăderile. Decodat cp1250, `EF BF BD` apare ca `ďż˝` în caption.
## Cum se repară
@@ -46,22 +72,26 @@ Dacă apare `�` (sau `$text` conține U+FFFD) — fișierul are corupere de
git show HEAD:<cale>.vct > /tmp/head.vct # (sau .VCT, dupa caz)
powershell -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 -Source /tmp/head.vcx -CacheRoot /tmp/head_out
```
apoi decodează ambele fișiere (HEAD curat + curent corupt) ca cp1252 și compară linie cu
linie (PowerShell, nu `diff`/Bash direct — nu decodează cp1252 corect la afișare, deși
Dacă și HEAD e deja corupt (corupera a fost comisă), caută ultima versiune curată cu
`git cat-file blob <commit>:<cale>` (din Bash, niciodată cu `>` din PowerShell 5.1 — adaugă
BOM și re-encodează) sau `svn cat <fișier>` — ambele surse independente de encoding-ul
curent al fișierului.
Apoi decodează ambele fișiere (versiunea curată + curent corupt) ca cp1250 și compară linie
cu linie (PowerShell, nu `diff`/Bash direct — nu decodează cp1250 corect la afișare, deși
detectează totuși diferența de octeți).
3. Reconstruiește fișierul text pornind de la versiunea HEAD (curată), reaplicând DOAR
modificările intenționate din sesiunea curentă (nu invers — nu cârpi fișierul corupt
caracter cu caracter).
4. Scrie rezultatul înapoi ca bytes cp1252
(`[System.Text.Encoding]::GetEncoding(1252).GetBytes(...)`), NU ca string UTF-8/`Out-File`
3. Reconstruiește fișierul text pornind de la versiunea curată, reaplicând DOAR modificările
intenționate din sesiunea curentă (nu invers — nu cârpi fișierul corupt caracter cu
caracter).
4. Scrie rezultatul înapoi ca bytes cp1250
(`[System.Text.Encoding]::GetEncoding(1250).GetBytes(...)`), NU ca string UTF-8/`Out-File`
implicit.
5. Rulează write-back (`txt2vcx.ps1 -Force`) și verifică fidelity check = zero diferențe.
## Cum se evită pe viitor
Când editezi `.sc2`/`.vc2` cu tool-uri text (Read/Edit/Write), verifică întâi dacă fișierul
conține diacritice (`ã`, `þ`, `ª`, `º`, `î`, `â` etc.) — dacă da, **orice rescrie completă
trebuie făcută la nivel de octeți cu encoding cp1252 explicit**, nu presupunând UTF-8.
conține diacritice (`ă`, `ț`, `Ș`, `ș`, `î`, `â` etc.) — dacă da, **orice rescrie completă
trebuie făcută la nivel de octeți cu encoding cp1250 explicit**, nu presupunând UTF-8.
Editările punctuale (Edit tool, string replace) sunt sigure DOAR dacă tool-ul păstrează restul
fișierului byte-identic (nu rescrie tot fișierul reîncodat).