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) --- # --- Notite locale neversionate (credentiale, specifice masinii) ---
docs/local/ docs/local/
docs/progres.md
docs/diff_runda*.patch
# --- Subversion (working copy paralela) --- # --- Subversion (working copy paralela) ---
.svn/ .svn/

View File

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

View File

@@ -3,8 +3,11 @@
ROAGEST - 2.11.13 ROAGEST - 2.11.13
:nou: :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. 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 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. 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 01/08/2026

View File

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

View File

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