- changelog 2.11.9 (achizitie import unificata, total/TVA automat, TVA pe conturile creditoare); todo actualizat - docs: flux-achizitie-import actualizat; testare-ui-vfp, testare-vfp-mcp si flux-editare-vfp-text mutate in COMUN\docs (general valabile pentru VFP); README fara mentiuni temporare (handoff) - CLAUDE.md / docs/CLAUDE.md: fluxul de editare text vcx/scx si modul de lucru Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019DGibQKa5uK4P2TNSFFQNh
160 lines
12 KiB
Markdown
160 lines
12 KiB
Markdown
# 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).
|
||
- **`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;
|
||
- 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`.
|
||
|
||
Căutarea generică: `cauta_alfa()` (`COMUN\programe\cauta_alfa.prg`) → forma `cauta_alfa_form_plus`.
|
||
|
||
## Structura reală a șablonului `vnote_contabile` (verificat 11.07.2026)
|
||
|
||
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**:
|
||
|
||
| Pereche (ordine) | SCD/SCC bază | SCD/SCC TVA | Ce e |
|
||
|---|---|---|---|
|
||
| 1 (1-2) | 3028/401 | 4426/4427 | marfă CE 21% + TVA |
|
||
| 2 (3-4) | 3028/401 | 4426/4427 | slot repetat (gol) |
|
||
| 3 (5-6) | 3028/401 | 4426/4427 | slot repetat (gol) |
|
||
| 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.
|
||
|
||
**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).
|
||
|
||
## DECIZIE 11.07.2026 — pivot la „Direcția A" (rescriere flux introducere)
|
||
|
||
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):
|
||
|
||
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.
|
||
|
||
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ă.
|
||
|
||
## Model curent `import_nota` (după rundele 8–12, 07.2026, necomis)
|
||
|
||
- **`doc_key` e unic per document**: prefix `nr_doc` (contor intern) + câmpurile de 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).
|
||
- **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).
|
||
- **Ș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
|
||
`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
|
||
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`.
|
||
|
||
## Ștergere note — model istoric pe paritate (înlocuit de rundele de mai sus)
|
||
|
||
- 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.
|