Files
roagest/docs/flux-achizitie-import.md
Marius Mutu 40fdfe41f6 Achizitie import unificata: documentatie si changelog (2.11.9)
- 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
2026-07-20 00:50:18 +03:00

12 KiB
Raw Blame History

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_adaugaviz_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 812, 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.