- 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
12 KiB
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 dinactactan, structura dinpmenu.prg:281-307, tabelulACT) — o singură perecheid_valuta+curspe act; - liniile de notă = cursorul
introdc(din viewvnote_contabilefiltrat peid_set), fiecare rând moșteneșteid_valuta/curs/dataact/tva_incasaredinpoAct; 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_originaldin același .vcx NU e instanțiat nicăieri — e copie de rezervă.
- antetul facturii =
- 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 înintrodc, apartenența la document fiind per rând:nract/serie_act/id_fact(rândurile au șiid_valuta/cursproprii, dar istoric codul folosește doarpoAct.Curs). import_nota(nota contabilă a facturii): grila peintrodc; transport/alte taxe se introduc ca linii de notă suplimentare cu flagurilein_valuta(suma e în valută) șiparticipa_valuta(linia intră în valoarea de intrare a mărfii).do_executacalculează procentele de repartizare (stocate înexplicatia4/explicatia5);inainte_de_do_terminsumează bazele (lei/valută, liniile în lei se împart lapoAct.Curs) și lanseazăimport_nircuprocent_lei/procent_val/ncurs.import_nir(grila de articole):do_adauga→viz_catalog_articole()(oproceduri_articole.prg:62, câmpulin_stoc= „Gestionabil") filtrat pe conturilescddin 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 prinpack_preturi.adauga_articol, cont implicit 371).- Salvare:
oscrie_in_fisiere→ tabelele temporareACT_TEMP/RUL_TEMP→ pachetul OraclePACK_CONTAFIN(SCRIE_IN_ACT,SCRIE_IN_RUL,SCRIE_IN_STOC, …).SCRIE_IN_RULinserează înRULexact conținutulRUL_TEMP(nu derivă din ACT) — orice filtrare de rulaje se face în clientul VFP. Sursa pachetului:COMUN\docs\PACK_CONTAFIN.pck(veziCOMUN\docs\oracle_export.md). - Articole negestionabile (
nom_articole.in_stoc = 0): modelul canonic e în clasanir(NIR-ul obișnuit, acelașiointroduceri.vcx), mecanism din 2009 — articolul intră normal în grilă și participă la calcule, iar îninainte_de_do_termin, chiar înainte de scriere, se faceDelete From rul_temp Where in_stoc = 0(valoarea rămâne doar pe nota contabilă, nu ajunge înRUL/STOC). Din v2.11.6import_nire aliniat la același model, cu un cursor temporar (crsNegest) care readaugă rândurile șterse în grilă dacăoscrie_in_fisiereeșuează. Cursorulrul_tempare coloanain_stocpentru că e creat din view-ulvrul(where 1=2); lado_adaugacoloana se umple prinGATHER NAME loArtdin cursorul catalogului, lado_modiparam(XLS) explicit din selectul penom_articole. - Explicație TVA: dropdown istoric
Grid1.cExplicatieTva.Combo1(RowSourcejtva_coloane2); modelul alternativ cu formular de căutare =frm_modific2024.do_modifica_explicatie_tva(omodificari.vcx) →caut_explicatie_tva()(ocautare.prg:1934, viewvjtva_coloane, întoarce DOARid_jtva_coloana, denumire, cota_tva). Capcane: înintrodc.ptvase ține cota brută (21), pe când în registru jurnalproc_tva= (cota+100)/100; comutarea 4427/401 pe linia de TVA se face prin SEEK în cursorulcJtvaCol4427.
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):
achizitie_import:introdcpornește gol (0 rânduri de document); se păstrează perechea- șablon (bază+TVA, cu conturile reale dinvnote_contabileale setului) ca sursă de clonare. Nu se mai încarcă cele 10 sloturi.- 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). - 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_keye unic per document: prefixnr_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, propagarecopiaza_valoareîntre documente străine).- Spargerea principalei (
sparge_document/creeaza_rand_s): gruparerul_temppecont+acont; analiticul articolului merge direct înascdal rândului S (fallbackassign_analiticdoar când nu e furnizat). - Procentele per rând (
explicatia4/explicatia5= coloanele "Procent lei/valuta"): scrise desincronizeaza()după spargere (nu dedo_executa, care nu mai scrie procente), numitor = baza documentului principal (This.nbazaprincipala_lei/_val, calculate înrecalculeaza). Principala = 100.00; celelalte = pondere lei și valută (convertit laoact.Cursdacă 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 cunr_doc/doc_keynoi (S/D se regenerează la sincronizare). Capcană rezolvată acolo:Calculatemută pointerul la EOF → poziția sursă se salvează/restaurează înainte deScatter. - Rândul TOTAL de sub grila notelor:
TxtFtvaLei/TxtFtvaVal(fără TVA) lângăText2/Text3(cu TVA), setate înactualizeaza_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=1se setează și pe rândul T (Valid-urilecSuma/cSumaVal);do_executanu rescrie T manual,sparge_documentnu-l șterge și nu creează duplicat pe aceeași cotă (ptva). Nimic nu reseteazămod_manualpe rând existent. nOldValunic (r15): o singură proprietate pentru valoarea la intrarea în celulă (GotFocus) — Valid/LostFocus ies devreme la valoare nemodificată (cSuma,cSumaVal,cCotaTva,cPretFactura).do_calculeaza_diferenterestaurează pozițiarul_tempde la intrarea în procedură (tnRecNonu mai poziționează);do_refacerepoziționează explicit.- Totaluri articole (r17):
_grdfooter1(clasa_grdfooterdin_grd_base.vcx) atașat laGridArtla finalulInit; sume pecValoareValutaFactura/cValoareValutaCalculat/cValoareLeiCalculatdinrul_temp, recalculate înactualizeaza_banda+do_calculeaza_diferente. VechileClb_leiftva/leitva/valftva/valtva(dublau totalurile notelor) au fost eliminate de peimport_nota. Totalurile de sub grila notelor rămân dinintrodc; 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_documentregrupează 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_documentaplică aceeași pondere (fără S-uri: împărțire egală 1/N);uneste_documentreunește T-urile sparte când documentul revine la B. Armarea resincronizării dincScc/cAscc.Validse face pe gardanOldVal(nu pe comparația cu câmpul — grila poate scrie câmpul înaintea Valid-ului, ex. Enter) + gardălInSynccontra 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(clasabut_sterge) șterge nota curentă = perechea bază+TVA, de pe oricare din cele două linii (lnBaza = Recno() - Iif(Mod(Recno(),2)=0,1,0), apoiDelete Next 2). Dispatch-ul butonului trece prininainte_de_do_sterge, condiționat delactiv4— setat.T.înInit. - Ștergerea e logică, nu fizică:
SET DELETED ON(roagest.prg:28) ascunde perechea din grid și din toateScan/Sum-urile fluxului, iar Recno-urile rămase nu se schimbă → paritatea impar/par se păstrează (perechile se șterg mereu împreună, deci șiSkip-urile peste liniile șterse cad corect).Append Blankulterior 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.