achizitie import: verificarea ANAF la alegerea partenerului merge si necompilat

COMUN\UTILE\NFJSON lipsea din SET PATH, deci VerificareANAF.Init nu se putea
instantia si verificarea raporta "ANAF nu a raspuns" la rularea din IDE (in exe
se rezolva din modulele compilate). Test: COMUN\utile\Teste\partener_anaf\
test_repro_anaf_path_nfjson.prg.

Changelog 2.11.13 compactat. versiune_db la ff_2026_08_02_06 (completare scc pe
seturile de achizitie import interna). Documentatia din docs\ compactata.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYbiinqXxdEqXi53x4Ro7K
This commit is contained in:
2026-08-02 22:30:33 +03:00
parent 3b20196308
commit 4c71592edc
8 changed files with 233 additions and 263 deletions

2
.gitignore vendored
View File

@@ -100,6 +100,8 @@ bash.exe.stackdump
# --- Notite locale neversionate (credentiale, specifice masinii) ---
docs/local/
docs/progres.md
docs/diff_runda*.patch
# --- Subversion (working copy paralela) ---
.svn/

View File

@@ -128,6 +128,7 @@ lcPath = gcAppPath + 'Date;' + ;
gcAppPath + 'COMUN\UTILE\HPDF\REPORTOUTPUT;' + ;
gcAppPath + 'COMUN\UTILE\WEB;' + ;
gcAppPath + 'COMUN\UTILE\EXCEL;' + ;
gcAppPath + 'COMUN\UTILE\NFJSON;' + ;
Addbs(Substr(gcAppPath,1,Rat([\],gcAppPath,2)))+[COMUNROA\]
*!*Set Path To Date;Include;FERESTRE;GRAFICE;Help;CLASE;MENIURI;PROGRAME;RAPOARTE;PROGS;LIBS

View File

@@ -3,8 +3,11 @@
ROAGEST - 2.11.13
:nou:
La alegerea partenerului, sub lista de cautare apare starea codului fiscal la ANAF pentru partenerul de pe randul curent: cod invalid, cod inexistent la ANAF sau diferenta fata de starea din program (platitor de TVA, inactiv). F4 deschide detaliile, iar cand exista un partener cu codul corect se propune alegerea lui.
Verificarea se face si la achizitia de import (furnizorul facturii si partenerul de pe DVI), la finalizarea NIR-ului, la schimbarea furnizorului pe rulaj si la completarea partenerului lipsa cand se salveaza documentul.
La alegerea partenerului se verifica codul fiscal la ANAF si se arata starea lui: cod invalid, cod inexistent sau diferenta fata de datele din program (platitor de TVA, inactiv). F4 deschide detaliile.
Verificarea apare si la achizitia din import, la finalizarea NIR-ului si la schimbarea furnizorului pe rulaj.
:eroare:
Achizitie import. Alegerea partenerului pe randul notei nu mai da eroare cand contul creditor nu e configurat pe nota.
-->
<!--
01/08/2026

View File

@@ -2,31 +2,30 @@
## Modificare cod VFP binar (.vcx/.scx) — flux write-back pe text
Din 07.2026 Claude aplică singur modificările pe `.vcx`/`.scx` prin fluxul text→bin.
Pașii per rundă (refresh cache, baseline `.pre_runda<N>.bak`, editare byte-safe CP1252,
patch de review, write-back cu fidelity-check) + capcanele + parametrii per proiect (inclusiv
ROAGEST): **`COMUN\docs\flux-editare-vfp-text.md`**.
Claude aplică singur modificările pe `.vcx`/`.scx` prin fluxul text→bin. Pașii per rundă (refresh
cache, baseline `.pre_runda<N>.bak`, editare byte-safe CP1252, patch de review, write-back cu
fidelity-check) + capcanele + parametrii per proiect (inclusiv ROAGEST): **`COMUN\docs\flux-editare-vfp-text.md`**.
1. Claude investighează pe cache-ul text, propune modificarea și **așteaptă acordul lui Marius
pe abordare** înainte să editeze.
La propunere/plan: scaneaza intai conventiile si functiile/clasele COMUNE existente si
foloseste-le cu prioritate (nu reinventa) - inventar compact: COMUN\docs\inventar-comun.md.
pe abordare** înainte să editeze. La propunere/plan: scaneaza intai conventiile si
functiile/clasele COMUNE existente si foloseste-le cu prioritate — inventar:
COMUN\docs\inventar-comun.md.
2. **Commit doar după ce Marius confirmă pe diff și testează în IDE.** Editările de volum se
deleagă la subagenți Sonnet în background; sesiunea principală orchestrează și verifică.
3. **Teste finale obligatorii pe cerința inițială**regulă comună tuturor proiectelor VFP,
pasul 6 din `COMUN\docs\flux-editare-vfp-text.md`; pe ROAGEST cu harness-ul din
`COMUN\utile\Teste` (`COMUN\docs\testare-ui-vfp.md`).
4. După implementare: changelog, ștergerea fișierului de propunere/patch-ului, iar insight-urile
durabile se mută în notițe `docs/flux-*.md` / `docs/pachet-*.md`.
3. **Teste finale obligatorii pe cerința inițială**pasul 6 din
`COMUN\docs\flux-editare-vfp-text.md`; pe ROAGEST cu harness-ul din `COMUN\utile\Teste`
(`COMUN\docs\testare-ui-vfp.md`).
4. După implementare: changelog, ștergerea fișierului de propunere/patch-ului, insight-urile
durabile mutate în `docs/flux-*.md` / `docs/pachet-*.md`.
Excepții rămase pe VFP IDE: `.mnx` (GENMENU) și `.frx` (fragile la round-trip) — pentru ele
rămâne valabil fluxul vechi cu fișier de propunere `docs/propuneri_<subiect>.md` aplicat de
Marius în IDE. Când Marius a început deja o implementare, Claude compară codul lui cu originalul
și listează explicit diferențele/cazurile netratate (nu rescrie orbește).
Excepții pe VFP IDE: `.mnx` (GENMENU) și `.frx` (fragile la round-trip) — flux vechi cu fișier de
propunere `docs/propuneri_<subiect>.md` aplicat de Marius în IDE. Când Marius a început deja o
implementare, Claude compară codul lui cu originalul și listează explicit diferențele/cazurile
netratate (nu rescrie orbește).
## Acces direct la baza de date Oracle
Claude are acces read la baza de date de dezvoltare și **își face singur exporturile** de surse
PL/SQL (pachete, view-uri) — nu se mai cer exporturi manuale. Detalii de conexiune și comanda de
export: `COMUN\docs\oracle_export.md`. Parola: `docs/local/oracle.md` (neversionat).
Exportul de referință `PACK_CONTAFIN.pck` stă în `COMUN\docs\` și se reîmprospătează la nevoie.
PL/SQL (pachete, view-uri). Detalii de conexiune și comanda de export: `COMUN\docs\oracle_export.md`.
Parola: `docs/local/oracle.md` (neversionat). Exportul de referință `PACK_CONTAFIN.pck` stă în
`COMUN\docs\` și se reîmprospătează la nevoie.

View File

@@ -1,6 +1,6 @@
# Documentatie tehnica ROAGEST
Notite concise despre structura interna a proiectului (fluxuri, pachete, tabele), descoperite in timp ce se lucreaza la sarcini concrete. Completeaza CLAUDE.md — nu il inlocuieste si nu duplica ce e deja evident din cod.
Notite concise despre structura interna a proiectului (fluxuri, pachete, tabele), descoperite lucrand la sarcini concrete. Completeaza CLAUDE.md — nu duplica ce e deja evident din cod.
## Index
@@ -9,15 +9,15 @@ Notite concise despre structura interna a proiectului (fluxuri, pachete, tabele)
- [git-svn-crlf.md](git-svn-crlf.md) — modificari fantoma in git dupa svn update (CRLF/mtime); fix cu `.gitattributes` (`* -text`) la radacina fiecarui repo.
- `local/` — notite neversionate (credentiale Oracle etc., in .gitignore).
Vezi si, in `COMUN\docs\` (instructiuni general valabile pentru proiectele VFP):
`flux-editare-vfp-text.md` (fluxul de editare pe text .vc2/.sc2 — pasi per runda, capcane,
parametri per proiect inclusiv ROAGEST), `testare-vfp-mcp.md` (testare vizuala prin vfp9.exe
interpretat + windows-mcp), `testare-ui-vfp.md` (harness headless pentru teste UI pe o singura
clasa, cu screenshots), `oracle_export.md` (export surse PL/SQL, PACK_CONTAFIN.pck) si
`scripturi-migrare-db.md` (unde stau scripturile de migrare a schemei Oracle si modelele lor).
Vezi si, in `COMUN\docs\` (valabile pentru toate proiectele VFP): `flux-editare-vfp-text.md`
(editare text .vc2/.sc2 — pasi per runda, capcane, parametri per proiect inclusiv ROAGEST),
`testare-vfp-mcp.md` (testare vizuala vfp9.exe interpretat + windows-mcp), `testare-ui-vfp.md`
(harness headless teste UI pe o singura clasa, screenshots), `oracle_export.md` (export surse
PL/SQL, PACK_CONTAFIN.pck), `scripturi-migrare-db.md` (scripturile de migrare a schemei Oracle).
## Cand actualizezi
Adauga sau corecteaza o notita aici ori de cate ori descoperi ceva nou si ne-evident despre structura proiectului in timpul rezolvarii unei sarcini (un flux ascuns, o capcana, o conventie, un pachet sau tabel cheie). Nu documenta ce oricine ar afla citind codul in 30 de secunde — scopul e sa scurtezi investigatii viitoare similare, nu sa duplici codul.
Adauga/corecteaza o notita cand descoperi ceva nou si ne-evident despre structura proiectului (flux ascuns, capcana, conventie, pachet sau tabel cheie) rezolvand o sarcina. Nu documenta ce oricine ar afla citind codul in 30 de secunde — scopul e sa scurtezi investigatii viitoare, nu sa duplici codul.
Organizeaza notitele in fisiere separate pe subiect (nu un singur fisier uriaș), ex: `flux-<nume-flux>.md`, `pachet-<nume-pachet>.md`, `tabele.md`.
Fisiere separate pe subiect (nu un singur fisier uriaș): `flux-<nume-flux>.md`, `pachet-<nume-pachet>.md`, `tabele.md`.
- [progres.md](progres.md) — fisier master de progres: de unde se reia lucrarea curenta (regula 10 din COMUN/docs/reguli_lucru.md)

View File

@@ -1,65 +1,58 @@
# Flux: Achiziție din import (NIR import)
Lanțul complet (descoperit la sesizarea „achiziție import", 07.2026):
- **Intrare**: `Clase\gestiuni.vcx` (`gestiuni.vc2:2045-2171`) → meniu „Achizitie din import /
Achizitie interna" → `DO achizitie_import WITH <id_set>, llIntern IN ointroduceri.prg`.
Id-uri de set: **208/209 = import**, **220/221 = intern** (perechi pe tip de operație).
Id-uri de set: **208/209 = import**, **220/221 = intern**.
- **`achizitie_import`** (`COMUN\programe\ointroduceri.prg:1435-1617`):
- antetul facturii = `poAct` (SCATTER din `actactan`, structura din `pmenu.prg:281-307`,
tabelul `ACT`) — o singură pereche `id_valuta` + `curs` pe act;
- antetul facturii = `poAct` (SCATTER din `actactan`, structură `pmenu.prg:281-307`, tabelul
`ACT`) — o singură pereche `id_valuta`+`curs` pe act;
- liniile de notă = cursorul **`introdc`** (din view `vnote_contabile` filtrat pe `id_set`),
fiecare rând moștenește `id_valuta`/`curs`/`dataact`/`tva_incasare` din `poAct`; rândurile merg
în perechi **impar = linia de bază, par = linia de TVA**;
- cursorul **`jtva_coloane2`** (explicații TVA, cu rând 0 gol) sursa dropdown-ului de explicație;
- deschide forma **`import_nota`** (`COMUN\clase\ointroduceri.vcx`). Atenție:
**`import_nota_original` din același .vcx NU e instanțiat nicăieri — e copie de rezervă.**
- **Modelul de documente**: un NIR de import = factura principală de achiziție (marfă și/sau
imobilizări; valuta/cursul ei = `poAct.id_valuta`/`poAct.Curs`, referința de conversie) + opțional
factura de transport (poate fi altă valută/curs) + opțional factura de taxe vamale + DVI
(declarația vamală, cu TVA-urile fiecărei facturi, plătite în lei). Toate devin linii în `introdc`,
apartenența la document fiind per rând: `nract`/`serie_act`/`id_fact` (rândurile au și `id_valuta`/
`curs` proprii, dar istoric codul folosește doar `poAct.Curs`).
- **`import_nota`** (nota contabilă a facturii): grila pe `introdc`; transport/alte taxe se introduc
ca linii de notă suplimentare cu flagurile `in_valuta` (suma e în valută) și `participa_valuta`
(linia intră în valoarea de intrare a mărfii). `do_executa` calculează procentele de repartizare
(stocate în `explicatia4`/`explicatia5`); `inainte_de_do_termin` sumează bazele
(lei/valută, liniile în lei se împart la `poAct.Curs`) și lansează **`import_nir`** cu
`procent_lei/procent_val/ncurs`.
- **`import_nir`** (grila de articole): `do_adauga``viz_catalog_articole()`
(`oproceduri_articole.prg:62`, câmpul `in_stoc` = „Gestionabil") filtrat pe conturile `scd` din
notă; prețul de intrare per articol = preț valută × `procent_val`, apoi × `ncurs` × `procent_lei`
(transportul „umflă" procentele peste 100). Diferența reziduală devine linia „DIFERENTE".
`do_modiparam` = preluare articole din XLS (creează articole noi prin `pack_preturi.adauga_articol`,
cont implicit 371).
- **Salvare**: `oscrie_in_fisiere` → tabelele temporare `ACT_TEMP`/`RUL_TEMP` → pachetul Oracle
**`PACK_CONTAFIN`** (`SCRIE_IN_ACT`, `SCRIE_IN_RUL`, `SCRIE_IN_STOC`, …). `SCRIE_IN_RUL` inserează
în `RUL` **exact** conținutul `RUL_TEMP` (nu derivă din ACT) — orice filtrare de rulaje se face în
clientul VFP. Sursa pachetului: `COMUN\docs\PACK_CONTAFIN.pck` (vezi `COMUN\docs\oracle_export.md`).
- **Articole negestionabile** (`nom_articole.in_stoc = 0`): modelul canonic e în clasa **`nir`**
(NIR-ul obișnuit, același `ointroduceri.vcx`), mecanism din 2009 — articolul intră normal în grilă
și participă la calcule, iar în `inainte_de_do_termin`, chiar înainte de scriere, se face
`Delete From rul_temp Where in_stoc = 0` (valoarea rămâne doar pe nota contabilă, nu ajunge în
`RUL`/`STOC`). Din v2.11.6 `import_nir` e aliniat la același model, cu un cursor temporar
(`crsNegest`) care readaugă rândurile șterse în grilă dacă `oscrie_in_fisiere` eșuează.
Cursorul `rul_temp` are coloana `in_stoc` pentru că e creat din view-ul `vrul` (`where 1=2`);
la `do_adauga` coloana se umple prin `GATHER NAME loArt` din cursorul catalogului, la
`do_modiparam` (XLS) explicit din selectul pe `nom_articole`.
- **Explicație TVA**: dropdown istoric `Grid1.cExplicatieTva.Combo1` (RowSource `jtva_coloane2`);
modelul alternativ cu formular de căutare = `frm_modific2024.do_modifica_explicatie_tva`
(`omodificari.vcx`) → `caut_explicatie_tva()` (`ocautare.prg:1934`, view `vjtva_coloane`,
întoarce DOAR `id_jtva_coloana, denumire, cota_tva`). Capcane: în `introdc.ptva` se ține **cota
brută** (21), pe când în registru jurnal `proc_tva` = (cota+100)/100; comutarea 4427/401 pe linia
de TVA se face prin SEEK în cursorul `cJtvaCol4427`.
fiecare rând moștenește `id_valuta`/`curs`/`dataact`/`tva_incasare` din `poAct`; rândurile
merg în perechi **impar = linia de bază, par = linia de TVA**;
- cursorul **`jtva_coloane2`** (explicații TVA, rând 0 gol) = sursa dropdown-ului de explicație;
- deschide forma **`import_nota`** (`COMUN\clase\ointroduceri.vcx`). **`import_nota_original`**
din același .vcx NU e instanțiat nicăieri — copie de rezervă.
- **Modelul de documente**: un NIR de import = factura principală (marfă și/sau imobilizări;
valuta/cursul ei = `poAct.id_valuta`/`poAct.Curs`, referința de conversie) + opțional factură de
transport (poate fi altă valută/curs) + opțional factură de taxe vamale + DVI (TVA-urile fiecărei
facturi, plătite în lei). Toate devin linii în `introdc`, apartenența pe document = per rând
(`nract`/`serie_act`/`id_fact`; rândurile au și `id_valuta`/`curs` proprii, dar codul istoric
folosește doar `poAct.Curs`).
- **`import_nota`**: grilă pe `introdc`; transport/taxe = linii de notă suplimentare cu flagurile
`in_valuta` (suma e în valută) și `participa_valuta` (linia intră în valoarea de intrare a
mărfii). `do_executa` calculează procentele de repartizare (`explicatia4`/`explicatia5`);
`inainte_de_do_termin` sumează bazele (liniile în lei se împart la `poAct.Curs`) și lansează
**`import_nir`** cu `procent_lei/procent_val/ncurs`.
- **`import_nir`**: `do_adauga``viz_catalog_articole()` (`oproceduri_articole.prg:62`, câmp
`in_stoc`="Gestionabil") filtrat pe conturile `scd` din notă; preț de intrare = preț valută ×
`procent_val`, apoi × `ncurs` × `procent_lei` (transportul „umflă" procentele peste 100).
Diferența reziduală → linia „DIFERENTE". `do_modiparam` = preluare articole din XLS (creează
articole noi prin `pack_preturi.adauga_articol`, cont implicit 371).
- **Salvare**: `oscrie_in_fisiere``ACT_TEMP`/`RUL_TEMP` → pachet Oracle **`PACK_CONTAFIN`**
(`SCRIE_IN_ACT`, `SCRIE_IN_RUL`, `SCRIE_IN_STOC`). `SCRIE_IN_RUL` inserează în `RUL` **exact**
`RUL_TEMP` (nu derivă din ACT) — filtrarea de rulaje se face în clientul VFP. Sursă pachet:
`COMUN\docs\PACK_CONTAFIN.pck` (`COMUN\docs\oracle_export.md`).
- **Articole negestionabile** (`nom_articole.in_stoc=0`): model canonic în clasa **`nir`** (NIR
obișnuit) — articolul intră normal în grilă, iar `inainte_de_do_termin` face
`Delete From rul_temp Where in_stoc=0` (valoarea rămâne doar pe nota contabilă). Din v2.11.6
`import_nir` e aliniat la același model, cu cursor temporar `crsNegest` care readaugă rândurile
șterse în grilă dacă `oscrie_in_fisiere` eșuează. `rul_temp` are coloana `in_stoc` din view-ul
sursă `vrul`; la `do_adauga` se umple prin `GATHER NAME loArt`, la `do_modiparam` (XLS) din
select pe `nom_articole`.
- **Explicație TVA**: dropdown `Grid1.cExplicatieTva.Combo1` (RowSource `jtva_coloane2`); variantă
cu căutare = `frm_modific2024.do_modifica_explicatie_tva` (`omodificari.vcx`)
`caut_explicatie_tva()` (`ocautare.prg:1934`, view `vjtva_coloane`, întoarce DOAR
`id_jtva_coloana, denumire, cota_tva`). Capcane: `introdc.ptva` ține **cota brută** (21), în
registru jurnal `proc_tva`=(cota+100)/100; comutarea 4427/401 pe linia de TVA = SEEK în
`cJtvaCol4427`.
Căutarea generică: `cauta_alfa()` (`COMUN\programe\cauta_alfa.prg`) → forma `cauta_alfa_form_plus`.
Căutare generică: `cauta_alfa()` (`COMUN\programe\cauta_alfa.prg`) → forma `cauta_alfa_form_plus`.
## Structura reală a șablonului `vnote_contabile` (verificat 11.07.2026)
## Șablon `vnote_contabile`
Cursorul `introdc` NU pornește cu „2 linii" — se încarcă cu **toate** perechile-șablon din
`vnote_contabile` pentru `id_set`. Numărul de linii pe baza de dev (`MARIUSM_AUTO`):
**208 = 10 linii, 209 = 10, 220 = 10, 221 = 6**. Cele 10 linii ale setului de import (208) =
**5 perechi pre-alocate (bază+TVA) = 5 sloturi de document**:
Cursorul `introdc` NU pornește cu „2 linii" — se încarcă cu toate perechile-șablon din
`vnote_contabile` pentru `id_set`. Pe dev (`MARIUSM_AUTO`): **208=10 linii, 209=10, 220=10,
221=6**. Cele 10 linii ale setului 208 = **5 perechi pre-alocate (bază+TVA) = 5 sloturi**:
| Pereche (ordine) | SCD/SCC bază | SCD/SCC TVA | Ce e |
|---|---|---|---|
@@ -69,205 +62,178 @@ Cursorul `introdc` NU pornește cu „2 linii" — se încarcă cu **toate** per
| 4 (7-8) | 3028/446 | 4426/446 | vamă/DVI (pe dev) |
| 5 (9-10) | 3028/446 | 4426/446 | slot repetat (gol) |
Model CONT2000: în loc să adaugi rânduri, ai **sloturi goale pre-alocate** pe care le completezi.
Factura principală = perechea 1 (2 linii); restul sunt sloturi pentru facturi suplimentare (3 marfă)
+ DVI (2). Un „document" = o pereche cu date.
Model CONT2000: sloturi goale pre-alocate, nu rânduri adăugate. Factura principală = perechea 1;
restul = sloturi pentru facturi suplimentare (3 marfă) + DVI (2). Un „document" = o pereche cu date.
**Corecție importantă (Marius, verificat pe bază reală de producție):** conturile 446 din setul 208
de pe dev **NU sunt reprezentative**. În realitate și DVI-ul vamă folosește **4426 = 401** (nu 446).
`vnote_contabile` e **configurabil per firmă**, deci șablonul variază — nu hardcoda conturile, ci
clonează perechea-șablon reală a setului. Practic: **un singur pattern de conturi** (bază 3028/401 +
TVA 4426/4427 sau 4426/401) acoperă și marfă, și DVI (DVI diferă doar prin partener/unde e plătit
TVA, nu prin conturi).
**Conturile 446 din setul 208 de pe dev NU sunt reprezentative** — pe producție DVI-ul vamă
folosește **4426=401** (nu 446). `vnote_contabile` e configurabil per firmă, nu hardcoda conturile:
clonează perechea-șablon reală a setului (un singur pattern 3028/401 + 4426/4427 sau 4426/401
acoperă și marfă și DVI — DVI diferă doar prin partener/unde e plătit TVA).
## DECIZIE 11.07.2026 — pivot la „Direcția A" (rescriere flux introducere)
## Plan: pivot la „Direcția A" (rescriere flux introducere, scop M2, neimplementat)
Marius a decis să se **abandoneze modelul cu 10 sloturi pre-alocate**. Noul model (de implementat
într-o sesiune viitoare, e scop **M2**, mai mare decât runda 1 M1/M3/M6):
Model țintă, abandonează cele 10 sloturi pre-alocate:
1. **`achizitie_import`**: `introdc` pornește **gol** (0 rânduri de document); se păstrează perechea-
șablon (bază+TVA, cu conturile reale din `vnote_contabile` ale setului) ca **sursă de clonare**.
Nu se mai încarcă cele 10 sloturi.
2. **Buton „Adaugă factură" + dialog (M2)**: clonează perechea-șablon, o completează cu datele
facturii, o adaugă în `introdc`. Se folosește **și pentru factura principală**, și pentru DVI
(radio-ul furnizor/DVI/fără schimbă doar partenerul/unde e plătit TVA, nu conturile).
3. **M1 (culori)**: rămâne cum e — fiecare factură adăugată = o pereche = un document = o culoare
(F1, F2, …), incremental, cheie `serie+nr+id_fdoc`. Codul M1 deja aplicat merge neschimbat pe
acest model.
1. `achizitie_import`: `introdc` pornește **gol**; se păstrează perechea-șablon (bază+TVA, conturi
reale din `vnote_contabile`) doar ca sursă de clonare.
2. Buton „Adaugă factură" + dialog: clonează perechea-șablon, o completează, o adaugă în
`introdc`. Folosit și pentru factura principală, și pentru DVI (radio-ul furnizor/DVI/fără
schimbă doar partenerul/unde e plătit TVA, nu conturile).
3. M1 (culori) rămâne neschimbat: fiecare factură adăugată = o pereche = un document = o culoare
(F1, F2, …), cheie `serie+nr+id_fdoc`.
Avertismente: atinge `COMUN` (blast radius: 22 `.pjx` referă `ointroduceri`) și **schimbă
comportamentul pentru toți userii de import** (nu mai văd sloturi pre-completate) — testare atentă,
dare în funcțiune deliberată.
Atinge `COMUN` (22 `.pjx` referă `ointroduceri`) și schimbă comportamentul pentru toți userii de
import (nu mai văd sloturi pre-completate) — testare atentă.
## Model curent `import_nota` (după rundele 812, 07.2026, necomis)
## Model curent `import_nota`
- **`doc_key` e unic per document**: prefix `nr_doc` (contor intern) + câmpurile de business
- **`doc_key` unic per document**: prefix `nr_doc` (contor intern) + câmpuri business
(`calc_doc_key`). Rândul T al unei facturi cu TVA pe DVI poartă câmpurile vamei
(partener/nract/4426) dar **păstrează doc_key-ul facturii-mamă** — identitatea nu se mai
amestecă între documentele care partajează același nr. DVI (cauza istorică a: explicație TVA
scrisă pe T-ul altui document, suma T=0, ștergere în grup, propagare `copiaza_valoare` între
documente străine).
(partener/nract/4426) dar **păstrează doc_key-ul facturii-mamă** — identitatea nu se amestecă
între documente care partajează același nr. DVI.
- **Spargerea principalei** (`sparge_document`/`creeaza_rand_s`): grupare `rul_temp` pe
`cont+acont`; analiticul articolului merge direct în `ascd` al rândului S (fallback
`assign_analitic` doar când nu e furnizat).
- **Procentele per rând** (`explicatia4`/`explicatia5` = coloanele "Procent lei/valuta"): scrise
de `sincronizeaza()` după spargere (nu de `do_executa`, care nu mai scrie procente), numitor =
baza documentului principal (`This.nbazaprincipala_lei/_val`, calculate în `recalculeaza`).
Principala = 100.00; celelalte = pondere lei și valută (convertit la `oact.Curs` dacă e în lei).
- **Procentele per rând** (`explicatia4`/`explicatia5` = Procent lei/valuta"): scrise de
`sincronizeaza()` după spargere (nu de `do_executa`), numitor = baza documentului principal
(`This.nbazaprincipala_lei/_val`, din `recalculeaza`). Principala=100.00; celelalte = pondere
lei/valută (convertit la `oact.Curs` dacă e în lei).
- **Ștergere/copiere**: `do_sterge` = meniu Da(document, pe doc_key)/Nu(doar linia)/Cancel;
`do_copiaza_nota` (buton „Copiază") = același meniu; copiază doar B+T cu `nr_doc`/`doc_key`
noi (S/D se regenerează la sincronizare). Capcană rezolvată acolo: `Calculate` mută pointerul
la EOF → poziția sursă se salvează/restaurează înainte de `Scatter`.
- **Rândul TOTAL** de sub grila notelor: `TxtFtvaLei`/`TxtFtvaVal` (fără TVA) lângă
`Text2`/`Text3` (cu TVA), setate în `actualizeaza_banda`.
- **Test e2e de referință**: `COMUN\utile\Teste\test_scenariu_dvi_complet.prg` (scenariul complet
cu 3 documente pe același DVI + articole 212/1 și 371/4 + ștergere/copiere).
- **Valori manuale protejate (r16)**: `mod_manual=1` se setează și pe rândul T (Valid-urile
`cSuma`/`cSumaVal`); `do_executa` nu rescrie T manual, `sparge_document` nu-l șterge și nu
creează duplicat pe aceeași cotă (`ptva`). Nimic nu resetează `mod_manual` pe rând existent.
- **`nOldVal` unic (r15)**: o singură proprietate pentru valoarea la intrarea în celulă
(GotFocus) — Valid/LostFocus ies devreme la valoare nemodificată (`cSuma`, `cSumaVal`,
`cCotaTva`, `cPretFactura`). `do_calculeaza_diferente` restaurează poziția `rul_temp` de la
intrarea în procedură (`tnRecNo` nu mai poziționează); `do_reface` repoziționează explicit.
- **Totaluri articole (r17)**: `_grdfooter1` (clasa `_grdfooter` din `_grd_base.vcx`) atașat la
`do_copiaza_nota` (buton „Copiază") = același meniu; copiază doar B+T cu `nr_doc`/`doc_key` noi
(S/D se regenerează la sincronizare). `Calculate` mută pointerul la EOF → poziția sursă se
salvează/restaurează înainte de `Scatter`.
- **Rândul TOTAL** sub grila notelor: `TxtFtvaLei`/`TxtFtvaVal` (fără TVA) lângă `Text2`/`Text3`
(cu TVA), setate în `actualizeaza_banda`.
- **Test e2e de referință**: `COMUN\utile\Teste\test_scenariu_dvi_complet.prg` (3 documente pe
același DVI + articole 212/1 și 371/4 + ștergere/copiere).
- **Valori manuale protejate**: `mod_manual=1` se setează și pe rândul T (Valid-urile
`cSuma`/`cSumaVal`); `do_executa` nu-l rescrie, `sparge_document` nu-l șterge/duplică pe aceeași
cotă (`ptva`). Nimic nu resetează `mod_manual` pe rând existent.
- **`nOldVal` unic**: o singură proprietate pentru valoarea la GotFocus — Valid/LostFocus ies
devreme la valoare nemodificată (`cSuma`, `cSumaVal`, `cCotaTva`, `cPretFactura`).
`do_calculeaza_diferente` restaurează poziția `rul_temp` de la intrare; `do_reface`
repoziționează explicit.
- **Totaluri articole**: `_grdfooter1` (clasa `_grdfooter` din `_grd_base.vcx`) atașat la
`GridArt` la finalul `Init`; sume pe `cValoareValutaFactura`/`cValoareValutaCalculat`/
`cValoareLeiCalculat` din `rul_temp`, recalculate în `actualizeaza_banda` +
`do_calculeaza_diferente`. Vechile `Clb_leiftva/leitva/valftva/valtva` (dublau totalurile
notelor) au fost eliminate de pe `import_nota`. Totalurile de sub grila notelor rămân din
`introdc`; Diferențe lei = bază note Σ articole.
- **Test scenariul TVA manual + footer**: `COMUN\utile\Teste\test_manual_tva_footer.prg`.
- **TVA pe creditori și la secundare (r30)**: `sparge_document` regrupează T-urile nemanuale ale
`do_calculeaza_diferente`. Totalurile de sub grila notelor rămân din `introdc`; Diferențe lei =
bază note Σ articole.
- **Test TVA manual + footer**: `COMUN\utile\Teste\test_manual_tva_footer.prg`.
- **TVA pe creditori și la secundare**: `sparge_document` regrupează T-urile nemanuale ale
documentelor secundare pe creditorii (scc/ascc) rândurilor S proprii, proporțional cu sumele S
(conservă totalul T, inclusiv TVA tastat la DVI); `recalc_tva_document` aplică aceeași pondere
(fără S-uri: împărțire egală 1/N); `uneste_document` reunește T-urile sparte când documentul
revine la B. Armarea resincronizării din `cScc/cAscc.Valid` se face pe garda `nOldVal` (nu pe
comparația cu câmpul — grila poate scrie câmpul înaintea Valid-ului, ex. Enter) + gardă `lInSync`
contra Valid-urilor re-declanșate de regenerare. Test: `COMUN\utile\Teste\test_tva_secundare.prg`.
revine la B. Resincronizarea din `cScc/cAscc.Valid` se armează pe garda `nOldVal` (nu pe
comparația cu câmpul — grila poate scrie câmpul înaintea Valid-ului, ex. Enter) + gardă
`lInSync` contra Valid-urilor re-declanșate de regenerare. Test:
`COMUN\utile\Teste\test_tva_secundare.prg`.
## TVA DVI cu valută proprie + discount financiar (07-08.2026)
## TVA DVI cu valută proprie + discount financiar
- **Două coloane noi client-side pe `introdc`** (fără migrare Oracle): `rand_dvi` (identitate —
1 pe rândul T scris de ramura DVI a `do_adauga_factura`) și `valuta_proprie` (autonomie — 1
când acel rând T are valută/curs diferite de ale documentului, setat la creare sau din grilă).
Nu s-a refolosit `mod_manual` — e supraîncărcat semantic (`sparge_document` face match și pe
el pentru alte scopuri, ar fi dat duplicate/omisiuni de rânduri T).
- **Rând „protejat"** = `Nvl(valuta_proprie,0)=1` (helper unic `rand_protejat()`, folosit
peste tot ca `Thisform.rand_protejat()`). E ocolit de `copiaza_valoare` (câmpurile valutare nu
se propagă pe el, câmpurile de identitate nu se propagă pe orice rând `rand_dvi=1`),
`do_executa`, `recalc_tva_document`, `uneste_document`, `sparge_document` (vezi mai jos)
și handlerele de grilă `cCurs`/`cInValuta`/`cValuta` (editare LOCALĂ, fără
- **Două coloane client-side pe `introdc`** (fără migrare Oracle): `rand_dvi` (identitate — 1 pe
rândul T scris de ramura DVI a `do_adauga_factura`) și `valuta_proprie` (1 când acel rând T are
valută/curs diferite de ale documentului, setat la creare sau din grilă). Nu s-a refolosit
`mod_manual` — e supraîncărcat semantic (`sparge_document` face match pe el pentru alte
scopuri, ar da duplicate/omisiuni de rânduri T).
- **Rând „protejat"** = `Nvl(valuta_proprie,0)=1` (helper `Thisform.rand_protejat()`). Ocolit de
`copiaza_valoare` (câmpurile valutare nu se propagă pe el, câmpurile de identitate nu se propagă
pe orice rând `rand_dvi=1`), `do_executa`, `recalc_tva_document`, `uneste_document`,
`sparge_document` și handlerele de grilă `cCurs`/`cInValuta`/`cValuta` (editare locală, fără
propagare). Re-alegerea valutei documentului pe rândul protejat resetează `valuta_proprie=0`
(revert — reintră în propagări). Un DVI cu valuta facturii rămâne `valuta_proprie=0` și
urmează factura la propagări, identic cu azi.
- **Spargerea T-ului protejat** (`sparge_tva_protejat`, apelată din `sparge_document`): când
TOATE rândurile T ale documentului sunt protejate, TVA-ul facturii e integral cel de pe DVI —
nu se mai fabrică rânduri T din rândul de bază. Varianta inițială (`loRandT = loBaza`) dădea
**TVA dublă**: rândul protejat rămânea, plus un T nou cu conturile bazei (371 în loc de 4426),
în valuta facturii. Acum totalul protejat se sparge pe cotele articolelor (pondere
`bază_cotă × cotă`, rest de rotunjire pe |suma| maximă), păstrând prin `Gather` identitatea
vamală, valuta proprie și `rand_dvi`/`valuta_proprie` — deci rândurile rezultate rămân
protejate. O singură cotă = niciun rând atins (ieșire devreme). Analogul lui B → S, dar pe T.
- **Discount financiar pe factură**: un singur rând `tip_rand='G'` (401=767, suma = discountul
fără TVA), același `doc_key`/`nr_doc` cu factura, `participa_valuta=.F.`. Marfa (3028) și
prețurile articolelor rămân pe valoarea integrală — discountul schimbă doar baza de calcul a
TVA-ului: `T = (b-d)*p/100`, sold 401 = `b + (b-d)*p/100 - d`. Ordinea la creare e B → G → T.
Excluse structural din bazele TVA/diferență/spargere prin filtrele deja existente pe
`Inlist(tip_rand,'B','S')`/`'T'` — un singur loc nu filtra pe `tip_rand` (suma în valută din
footer, `do_executa`) și a primit `And tip_rand<>'G'`.
Punct unic de adevăr: `disc_document(doc_key, tlValuta)`. Se scade DIRECT în `do_executa` și
`recalc_tva_document` (același `doc_key`, exact), dar se REPARTIZEAZĂ prin factor în
`sparge_document`, unde bazele vin din `crsGrupCota` (articole), nu din `suma_doc`. Factorul e
clampat la 0: validarea din dialog compară discountul cu suma facturii, care poate fi mai mare
decât baza articolelor când rămâne rest pe rândul de diferențe → altfel ar ieși TVA negativă.
`suma_doc`/`suma_doc_val` rămân BRUTE (`sparge_document` repartizează toată baza pe rândurile
S, iar `verifica_sincronizare` compară `Suma(S)` cu `suma_doc`).
`do_adauga_factura` citește `toDlg.disc_baza_lei` sub gardă `Type(...)<>'U'` — e apelabil
programatic cu un `toDlg` minimal (import e-Factura/XLS), iar `Nvl` singur nu apără de o
proprietate inexistentă.
Limită cunoscută: rândurile create ulterior de `sparge_document`/`recalc_tva_document` se
adaugă la finalul cursorului, deci după sincronizare ordinea vizuală B/G/T nu mai e garantată
(grila nu are sortare).
(revert). Un DVI cu valuta facturii rămâne `valuta_proprie=0` și urmează factura la propagări.
- **Spargerea T-ului protejat** (`sparge_tva_protejat`, din `sparge_document`): când TOATE
rândurile T ale documentului sunt protejate, TVA-ul facturii e integral cel de pe DVI — nu se
fabrică rânduri T din rândul de bază. Varianta `loRandT = loBaza` dădea TVA dublă (rândul
protejat rămânea, plus un T nou cu conturile bazei în valuta facturii). Acum totalul protejat se
sparge pe cotele articolelor (pondere `bază_cotă × cotă`, rest de rotunjire pe |suma| maximă),
păstrând prin `Gather` identitatea vamală/valuta proprie/`rand_dvi`/`valuta_proprie`. O singură
cotă = niciun rând atins.
- **Discount financiar pe factură**: un rând `tip_rand='G'` (401=767, suma=discount fără TVA),
același `doc_key`/`nr_doc` cu factura, `participa_valuta=.F.`. Marfa (3028) și prețurile
articolelor rămân la valoarea integrală — discountul schimbă doar baza TVA: `T=(b-d)*p/100`,
sold 401 = `b + (b-d)*p/100 - d`. Ordine la creare: B → G → T. Excluse din bazele
TVA/diferență/spargere prin filtrele deja existente pe `Inlist(tip_rand,'B','S')`/`'T'` — un
singur loc nu filtra pe `tip_rand` (suma valută din footer, `do_executa`), a primit
`And tip_rand<>'G'`. Punct unic de adevăr: `disc_document(doc_key, tlValuta)`. Se scade DIRECT
în `do_executa`/`recalc_tva_document` (același `doc_key`), dar se REPARTIZEAZĂ prin factor în
`sparge_document` (bazele vin din `crsGrupCota`, nu din `suma_doc`). Factorul e clampat la 0
(discountul poate depăși baza articolelor când rămâne rest pe rândul de diferențe → altfel TVA
negativă). `suma_doc`/`suma_doc_val` rămân BRUTE (`sparge_document` repartizează toată baza pe
S, `verifica_sincronizare` compară `Suma(S)` cu `suma_doc`). `do_adauga_factura` citește
`toDlg.disc_baza_lei` sub gardă `Type(...)<>'U'` — apelabil programatic cu `toDlg` minimal
(import e-Factura/XLS). Limită cunoscută: rândurile create ulterior de
`sparge_document`/`recalc_tva_document` se adaugă la finalul cursorului — ordinea vizuală B/G/T
nu mai e garantată (grila nu are sortare).
- **Bifa „Valuta" pe secțiunea TVA DVI** (`chkDviInValuta`): pornește după factură (bifată când
factura e în valută) și rămâne pe alegerea manuală prin `ldviinvalutadirty`, ca `linvalutadirty`
la bază. Scoasă, ascunde valuta/cursul/TVA-ul valutar al DVI-ului și forțează `nDviCurs=1`,
`nDviTvaVal=0`. Condiția de ramură din `recalc_tva` trebuie să includă bifa, nu doar
`dvi_valuta_efectiva()` — aceasta din urmă întoarce valuta facturii și nu știe de bifă, deci
fără ea se scrie `dvi_tva_val` nenul împreună cu `dvi_in_valuta=.F.`. Cazul nou „factură în
valută, DVI doar în lei" dă `dvi_valuta_proprie=1`.
- **Concordanța cotelor pe factură multi-cotă**: rândurile S se generează pe `cont+analitic+cota_tva`
(doar la documentul principal) și primesc cota articolelor lor `creeaza_rand_s` are parametrul
`tnCota`, care scrie `ptva` + `id_jtva_coloana`/`explicatie_tva` prin `gaseste_jtva_cota` (familia =
coloana bazei). Rândul G se sparge la fel, proporțional cu bazele pe cotă (`sparge_discount`, apelat
din `sparge_document` imediat după `calc_baze_cota_creditor`), păstrând totalul discountului;
e idempotentă (recalculează din suma rândurilor G existente). Fără astea, baza (S) și discountul (G)
rămâneau pe cota facturii în timp ce T-urile erau deja sparte pe cotele articolelor — în jurnalul de
TVA baza ieșea pe altă cotă decât TVA-ul. Articolele fără cotă proprie preiau cota documentului
înainte de grupare (altfel apare un grup tranzitoriu „cota 0").
- **`nOldVal` e NUMERIC**: coloanele caracter din grila notelor (`cScc`/`cAscc`) folosesc `cOldVal`.
O singură proprietate partajată între coloane numerice și caracter dădea „Operator/operand type
mismatch" în `cSuma.Text1.Valid` când Valid se re-declanșa fără GotFocus (refresh de grilă din
`sincronizeaza`). `cSuma`/`cSumaVal.Valid` au primit și garda `lInSync`, ca `cScc`/`cAscc`.
- **Două reprezentări ale „RON"** — capcană reală, ușor de reintrodus: rândul din picker
(`caut_valuta`/`vnom_valute`) e un rând REAL cu `id_valuta` nenul (`moneda_nationala=1`);
sentinela „fără valută" din `introdc`/`ACT` e `id_valuta=0`, `nume_val=''`. Comparațiile
trebuie făcute pe valuta EFECTIVĂ (`Empty(nume) Or Upper(nume)=='RON'`), nu pe id brut — o
factură fără valută + RON ales explicit pe DVI sunt ambele „fără valută", dar o comparație
de id-uri brute le-ar vedea ca diferite (`dvi_valuta_proprie` ar da fals 1).
- **`copiaza_valoare` și rândul DVI — gardă în ambele sensuri**: rândul T al DVI-ului păstrează
`doc_key`-ul facturii-mamă, deci propagarea pe grup îl include. Trebuie sărit și ca **țintă**
(identitatea facturii nu-l atinge) și ca **sursă** (numărul/data/partenerul vamal nu ajung pe
factură). Fără garda pe sursă, o simplă trecere prin celula „Nr" a rândului DVI scria numărul
DVI-ului peste toată factura (B/G/S) și, la Terminat, în `ACT` și `RUL.nract`. Rândul D scapă,
pentru că își moștenește antetul o singură dată, la creare. `copiaza_valoare` nu face refresh de
grilă, deci pe ecran rămân valorile vechi — coruperea e invizibilă până la salvare.
Propagarea de partener are flux propriu (`Grid1.cPartC.Text1.Valid`), cu aceeași gardă.
- **`ControlSource`-ul unei coloane de grid e CALIFICAT la runtime**: `This.Parent.ControlSource`
întoarce `introdc.nract`, nu `nract` (cum apare în `.vc2`). Orice `Inlist`/comparație pe nume de
câmp cu valoarea primită din `Valid`-urile de grilă trebuie să normalizeze întâi (taie prefixul
până la ultimul punct) — altfel garda arată corect scrisă și nu se activează niciodată. Regresie:
factura e în valută), rămâne pe alegerea manuală prin `ldviinvalutadirty` (ca `linvalutadirty`
la bază). Scoasă ascunde valuta/cursul/TVA-ul valutar al DVI, forțează `nDviCurs=1`,
`nDviTvaVal=0`. Ramura din `recalc_tva` trebuie să includă bifa, nu doar
`dvi_valuta_efectiva()` (întoarce valuta facturii, nu știe de bifă — fără ea se scrie
`dvi_tva_val` nenul cu `dvi_in_valuta=.F.`). „Factură în valută, DVI doar în lei" dă
`dvi_valuta_proprie=1`.
- **Concordanța cotelor pe factură multi-cotă**: rândurile S se generează pe
`cont+analitic+cota_tva` (doar la documentul principal), primesc cota articolelor —
`creeaza_rand_s` are parametrul `tnCota`, scrie `ptva`+`id_jtva_coloana`/`explicatie_tva` prin
`gaseste_jtva_cota` (familia = coloana bazei). Rândul G se sparge la fel, proporțional pe bazele
pe cotă (`sparge_discount`, din `sparge_document` după `calc_baze_cota_creditor`), păstrând
totalul discountului; idempotentă. Fără astea, baza (S) și discountul (G) rămâneau pe cota
facturii în timp ce T-urile erau deja sparte pe cotele articolelor — jurnalul de TVA ieșea cu
baza pe altă cotă decât TVA-ul. Articolele fără cotă proprie preiau cota documentului înainte de
grupare.
- **`nOldVal` e NUMERIC**: coloanele caracter din grilă (`cScc`/`cAscc`) folosesc `cOldVal`. O
singură proprietate partajată dădea „Operator/operand type mismatch" în `cSuma.Text1.Valid`
când Valid se re-declanșa fără GotFocus. `cSuma`/`cSumaVal.Valid` au primit și garda `lInSync`.
- **Două reprezentări ale „RON"**: rândul din picker (`caut_valuta`/`vnom_valute`) e REAL cu
`id_valuta` nenul (`moneda_nationala=1`); sentinela „fără valută" din `introdc`/`ACT` e
`id_valuta=0`, `nume_val=''`. Comparațiile trebuie pe valuta EFECTIVĂ
(`Empty(nume) Or Upper(nume)=='RON'`), nu pe id brut — altfel `dvi_valuta_proprie` ar da fals 1.
- **`copiaza_valoare` și rândul DVI — gardă în ambele sensuri**: rândul T al DVI păstrează
`doc_key`-ul facturii-mamă, deci propagarea pe grup îl include. Trebuie sărit ca țintă
(identitatea facturii nu-l atinge) și ca sursă (numărul/data/partenerul vamal nu ajung pe
factură) — fără garda pe sursă, o trecere prin celula „Nr" a rândului DVI scria numărul DVI
peste toată factura (B/G/S) și, la Terminat, în `ACT`/`RUL.nract`. Rândul D scapă (își moștenește
antetul o singură dată, la creare). `copiaza_valoare` nu face refresh de grilă — coruperea e
invizibilă până la salvare. Propagarea de partener are flux propriu
(`Grid1.cPartC.Text1.Valid`), aceeași gardă.
- **`ControlSource` calificat la runtime**: `This.Parent.ControlSource` întoarce `introdc.nract`,
nu `nract`. Orice `Inlist`/comparație pe nume de câmp cu valoarea din Valid-urile de grilă
trebuie să normalizeze întâi (taie prefixul până la ultimul punct) — altfel garda arată corect
scrisă și nu se activează niciodată. Test:
`COMUN\utile\Teste\achizitie_import\test_diag_controlsource_calificat.prg`.
## Ștergere note — model istoric pe paritate (înlocuit de rundele de mai sus)
## Ștergere note — model VECHI pe paritate, înlocuit de `doc_key`
- Butonul `But_sterge1` (clasa `but_sterge`) șterge nota curentă = **perechea bază+TVA**, de pe
oricare din cele două linii (`lnBaza = Recno() - Iif(Mod(Recno(),2)=0,1,0)`, apoi `Delete Next 2`).
Dispatch-ul butonului trece prin `inainte_de_do_sterge`, condiționat de `lactiv4` — setat `.T.`
în `Init`.
- Ștergerea e **logică**, nu fizică: `SET DELETED ON` (roagest.prg:28) ascunde perechea din grid și
din toate `Scan`/`Sum`-urile fluxului, iar Recno-urile rămase nu se schimbă → paritatea impar/par
se păstrează (perechile se șterg mereu împreună, deci și `Skip`-urile peste liniile șterse cad
corect). `Append Blank` ulterior continuă tot pe paritate corectă.
- **Capcană generală VFP: niciodată `ZAP` (sau închidere/recreare) pe cursorul-sursă al unui
grid** — Zap închide și recreează cursorul, grid-ul își pierde sursa și rămâne blank. Varianta
„copiez rândurile rămase + Zap + Append la loc" e greșită exact din acest motiv.
- `But_sterge1` (clasa `but_sterge`) șterge perechea bază+TVA curentă, de pe oricare linie
(`lnBaza = Recno() - Iif(Mod(Recno(),2)=0,1,0)`, apoi `Delete Next 2`), prin
`inainte_de_do_sterge` sub `lactiv4` (`.T.` în `Init`).
- Ștergere logică (`SET DELETED ON`, `roagest.prg:28`) — Recno-urile rămân, paritatea impar/par
se păstrează.
- Capcană generală VFP: niciodată `ZAP`/recreare pe cursorul-sursă al unui grid — grid-ul își
pierde sursa și rămâne blank.
## Familia explicațiilor TVA pe factură multi-cotă (07.2026)
## Explicații TVA pe factură multi-cotă
- **Perechea bază/TVA se citește din nomenclator** (`jtva_coloane2.id_tva`), iar trecerea de la o
cotă la alta în aceeași familie se face pe **semnătura coloanei** (`coloana_jc` fără cifre:
`FO21B``FOB`, `FO21T``FOT`) — `gaseste_jtva_cota`. Potrivirea pe primele 2 caractere confunda
coloana de bază cu cea de TVA.
- **Alinierea T → S** (`aliniaza_tva_la_baza`, la finalul `sparge_document`): fiecare rând T
primește perechea de TVA a rândului S de aceeași cotă, dar numai dacă explicația S-ului chiar are
cota rândului (altfel nu există pereche validă — cazul nomenclatorului incomplet). Fără ea, o
explicație aleasă din altă serie pe rândul S (ex. `CE11CTB`) muta rândurile T în seria CE, în timp
ce S-ul se re-alinia la familia documentului (`FO`) la resincronizare — bază și TVA pe rubrici
diferite în jurnalul de TVA.
- **`expl_manual`** (coloană client-side pe `introdc`, lângă `mod_manual`): 1 când utilizatorul
alege explicit explicația pe un rând T (`aplica_explicatie_tva` / combo-ul din grilă); rândurile
marcate nu se aliniază. Nu s-a refolosit `mod_manual` — acela înseamnă „nu-mi recalcula suma"
și ar fi înghețat și sumele. Peste regenerarea rândurilor T eticheta se păstrează prin snapshot
pe cotă (`crsExplT`, luat înainte de ștergere, reaplicat după); la `sparge_tva_protejat` rămâne
doar pe cota rândului original, cotele apărute din spargere se aliniază normal.
- **Golul de nomenclator la 11%**: importul de bunuri nu avea perechea de 11% (`FO11B`/`FO11T` =
236/237, adăugate 30.07.2026). Fără pereche, `sparge_document` lasă în `cmesajsync` mesajul
„Documentul <fdoc> are marfă la <cotă>%, dar nu există explicație TVA de <cotă>% în seria
'<serie>'" și finalizarea rămâne blocată; utilizatorul poate ocoli lipsa alegând manual o
explicație de 11% din altă serie.
- **`tlIntern` în `achizitie_import`**: `Createobject('IMPORT_nota', tlIntern)` primește parametrul
procedurii, dar codul din clasă trebuie să citească `Thisform.lIntern` — o referință la `tlIntern`
dintr-o metodă a formularului prinde variabila PRIVATE a apelantului doar cât timp acesta e pe
stivă (în `inainte_de_do_termin` era deja ieșit).
- **Perechea bază/TVA din nomenclator** (`jtva_coloane2.id_tva`); trecerea între cote în aceeași
familie = pe **semnătura coloanei** (`coloana_jc` fără cifre: `FO21B``FOB`, `FO21T``FOT`,
`gaseste_jtva_cota`). Potrivirea pe primele 2 caractere confunda baza cu TVA.
- **Alinierea T → S** (`aliniaza_tva_la_baza`, final `sparge_document`): fiecare T primește
perechea de TVA a S-ului de aceeași cotă, doar dacă explicația S-ului chiar are cota rândului.
Fără ea, o explicație din altă serie pe S (ex. `CE11CTB`) muta T-urile în seria CE, în timp ce
S se re-alinia la familia documentului (`FO`) la resincronizare.
- **`expl_manual`** (coloană client-side, lângă `mod_manual`): 1 când utilizatorul alege explicit
explicația pe un rând T; rândurile marcate nu se aliniază. Nu s-a refolosit `mod_manual`
(înseamnă „nu recalcula suma", ar fi înghețat și sumele). Peste regenerarea T-urilor eticheta se
păstrează prin snapshot pe cotă (`crsExplT`, luat înainte de ștergere, reaplicat după); la
`sparge_tva_protejat` rămâne doar pe cota rândului original.
- **Gol de nomenclator la 11%**: importul de bunuri nu avea perechea 11% (`FO11B`/`FO11T` =
236/237, adăugate 30.07.2026). Fără pereche, `sparge_document` lasă în `cmesajsync` „Documentul
<fdoc> are marfă la <cotă>%, dar nu există explicație TVA de <cotă>% în seria '<serie>'" și
finalizarea rămâne blocată; utilizatorul poate ocoli alegând manual o explicație de 11% din altă
serie.
- **`tlIntern` în `achizitie_import`**: `Createobject('IMPORT_nota', tlIntern)` primește
parametrul, dar codul din clasă citește `Thisform.lIntern` — o referință la `tlIntern` dintr-o
metodă a formularului prinde variabila PRIVATE a apelantului doar cât timp acesta e pe stivă
(în `inainte_de_do_termin` era deja ieșit).
- **Fixture-uri de test**: cele 32 de teste din `COMUN\utile\Teste\achizitie_import` își creează
singure `introdc` prin `CREATE CURSOR` — orice coloană nouă folosită în SQL-ul din clasă trebuie
adăugată și acolo, altfel apare „SQL: Column '<X>' is not found".
`introdc` prin `CREATE CURSOR` — orice coloană nouă folosită în SQL-ul din clasă trebuie
adăugată și acolo, altfel „SQL: Column '<X>' is not found".

View File

@@ -6,10 +6,9 @@ desi continutul e identic.
Cauza: SVN scrie CRLF nativ si atinge mtime la fiecare update; `core.autocrlf=true`
face git sa (re)verifice/converteasca EOL-urile si sa le raporteze ca dirty.
Fix (2026-07-15): `.gitattributes` cu `* -text` la radacina fiecarui repo (ROAGEST,
COMUN, ROAAUTO, ROACONT, ROAIMOB, ROAACNPRO) — opreste normalizarea CRLF/LF a git,
SVN ramane autoritatea EOL. Pe repo nou cu acelasi tipar svn+git, copiaza acelasi
`.gitattributes`.
Fix: `.gitattributes` cu `* -text` la radacina fiecarui repo (ROAGEST, COMUN, ROAAUTO,
ROACONT, ROAIMOB, ROAACNPRO) — opreste normalizarea CRLF/LF a git, SVN ramane autoritatea
EOL. Pe repo nou cu acelasi tipar svn+git, copiaza acelasi `.gitattributes`.
Capcana: `-text` opreste doar conversia *viitoare* — blob-urile deja in git (LF)
tot difera de ce scrie SVN (CRLF), deci diferenta reala reapare o data. Fix unic:

View File

@@ -1 +1 @@
2026_08_02_01
2026_08_02_06