diff --git a/.gitignore b/.gitignore index 9ab6d85..4af1c41 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,6 @@ bash.exe.stackdump # Setari locale Claude Code (specifice masinii, nu proiectului) .claude/ + +# Notite locale neversionate (credentiale, specifice masinii) +docs/local/ diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md new file mode 100644 index 0000000..230fd14 --- /dev/null +++ b/docs/CLAUDE.md @@ -0,0 +1,24 @@ +# Mod de lucru Claude ↔ Marius pe ROAGEST + +## Propuneri de modificare pentru cod VFP binar (.vcx/.scx) + +Clasele/formele sunt binare și se editează doar în VFP IDE, deci fluxul e: + +1. Claude investighează (pe cache-ul text `_textcache_roagest`) și scrie un fișier de propunere + `docs/propuneri_.md` cu **cod complet, gata de copiat** în IDE, cu referințe + `fișier:linie` din cache și pași de testare. +2. Marius aplică modificările în VFP IDE și rulează `vcx2txt.ps1` (comanda din CLAUDE.md rădăcină) + pentru refresh-ul cache-ului text. +3. Claude verifică pe cache-ul reîmprospătat ce s-a aplicat (diff față de propunere, cazuri ratate). +4. După implementare + changelog, fișierul de propunere se șterge sau se arhivează; insight-urile + durabile descoperite pe parcurs se mută în notițe `docs/flux-*.md` / `docs/pachet-*.md`. + +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. diff --git a/docs/README.md b/docs/README.md index 914d66e..86ede46 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,7 +2,14 @@ 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. -Niciun subiect documentat inca — prima notita se adauga cand rezolvam prima sarcina concreta in acest proiect. +## Index + +- [CLAUDE.md](CLAUDE.md) — modul de lucru Claude ↔ Marius (propuneri de cod pentru VFP IDE, acces Oracle direct). +- [flux-achizitie-import.md](flux-achizitie-import.md) — lantul achizitie import: gestiuni.vcx → achizitie_import → import_nota → import_nir → PACK_CONTAFIN; capcane (ptva bruta vs proc_tva, import_nota_original mort, 4427/401). +- [propuneri_achizitie_import.md](propuneri_achizitie_import.md) — *temporar*: modificarile propuse (cu cod) pentru sesizarea achizitie import; se sterge dupa implementare. +- `local/` — notite neversionate (credentiale Oracle etc., in .gitignore). + +Vezi si `COMUN\docs\oracle_export.md` (export surse PL/SQL, PACK_CONTAFIN.pck). ## Cand actualizezi diff --git a/docs/flux-achizitie-import.md b/docs/flux-achizitie-import.md new file mode 100644 index 0000000..dc71e30 --- /dev/null +++ b/docs/flux-achizitie-import.md @@ -0,0 +1,46 @@ +# 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 , 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`). +- **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`. diff --git a/docs/propuneri_achizitie_import.md b/docs/propuneri_achizitie_import.md new file mode 100644 index 0000000..6453df1 --- /dev/null +++ b/docs/propuneri_achizitie_import.md @@ -0,0 +1,303 @@ +# Propuneri de modificare — Sesizare ACHIZIȚIE IMPORT + +> Fișier de lucru (se șterge/arhivează după implementare). Modificările se aplică **în VFP IDE** +> (clasele sunt în binare `.vcx`); după aplicare se rulează `vcx2txt.ps1` pentru refresh cache. +> +> Context flux (detalii durabile în `docs/flux-achizitie-import.md`): +> `gestiuni.vc2:2045-2171` → `DO achizitie_import WITH 208/209/220/221, llIntern IN ointroduceri.prg` +> → `ointroduceri.prg:1435-1617` construiește `poAct` (din `ACT`/`actactan`), cursorul liniilor de notă +> `introdc`, cursorul `jtva_coloane2`, apoi `CREATEOBJECT('IMPORT_nota')` (`:1599`). +> `import_nota.inainte_de_do_termin` lansează `import_nir` (grila de articole → `rul_temp`), iar salvarea +> finală trece prin `oscrie_in_fisiere` → `PACK_CONTAFIN.SCRIE_IN_ACT/SCRIE_IN_RUL/SCRIE_IN_STOC`. +> **`import_nota_original` (ointroduceri.vc2:8269) NU e instanțiat nicăieri — e copie de rezervă, nu se modifică.** +> Liniile de mai jos se referă la cache-ul text `D:\ROA\UTIL\foxbin2prg\_textcache_roagest\comun\clase\ointroduceri.vc2` +> (stadiul de la 08.07.2026, cu implementarea ta începută la punctul 1 deja inclusă). + +--- + +## 1. Explicație TVA prin formular de căutare (în loc de dropdown) + +**Stadiu:** ai făcut deja în `import_nota`: `Column4 (cExplicatieTva).CurrentControl = "Text1"`, +ai adăugat `Text1` cu `DblClick`/`InteractiveChange` → `do_modifica_explicatie_tva` (`:7628-7697`), +copiat după `frm_modific2024.do_modifica_explicatie_tva` (`omodificari.vc2:12829`). +`Combo1` + `Combo1.Valid` rămân în clasă, dezactivate (decizie: păstrate ca fallback). + +**Probleme găsite în versiunea ta actuală** (comparat cu originalul `Combo1.Valid`, `:7962-8027`, +a cărui logică trebuie păstrată identic): + +| # | Problema | Detaliu | +|---|----------|---------| +| A | **`lnPtva = (locauta.cota_tva + 100) / 100` e greșit** | Formula vine din registru jurnal, unde câmpul e `proc_tva` (1.21). În `introdc.ptva`, originalul `Combo1.Valid` salvează **cota brută** (`lnPtva = jtva_coloane2.cota_Tva`, ex. 21). Cu formula ta: (a) `ptva` primește 1.21 în loc de 21 → calculele de TVA din `cSuma.Text1.Valid` ies greșite; (b) testul `If lnPtva = 0` pentru cota 0% nu mai e adevărat niciodată (0% → 1), deci ramura de golire a liniei de TVA nu se mai execută. | +| B | **`lnId_tva = locauta.id_tva` — proprietatea nu există** | `caut_explicatie_tva` (`ocautare.prg:1951`) selectează doar `id_jtva_coloana, denumire, cota_tva` din `vjtva_coloane`. Obiectul întors NU are `.id_tva` → eroare la runtime. `id_tva` trebuie citit din `jtva_coloane2` după `LOCATE` (cursorul e deja deschis în acest flux, `ointroduceri.prg:1586-1594`, și conține coloana `ID_TVA`). LOCATE-ul există deja la tine (`:7647-7648`) dar nu-i folosești rezultatul și nu verifici `FOUND()`. | +| C | **`lnTipEx = iif(introdc.scd='4428',2,1)` evaluat pe linia greșită** | Pe linia de bază (impară) `scd` e contul de marfă (3xx/2xx), niciodată 4428 → mereu `tlTipEx=1`. 4426/4428 e pe **linia pereche de TVA** (para). Trebuie să te uiți la linia următoare când ești pe linia de bază. Alternativă mai simplă: `introdc.tva_incasare` (moștenit din `poAct`, vezi `ointroduceri.prg:1558`) — `IIF(introdc.tva_incasare=1, 2, 1)`. | +| D | Guard pe anulare | `Store "" To loCauta` în `caut_explicatie_tva` + acces direct `.id_jtva_coloana` poate da eroare dacă utilizatorul închide căutarea. Adaugă `Vartype(loCauta) <> 'O'` în test. | + +**Cod propus (înlocuiește integral `import_nota.do_modifica_explicatie_tva`):** + +```foxpro +PROCEDURE do_modifica_explicatie_tva + *!* cautare explicatie TVA prin formular (model: frm_modific2024 din omodificari.vcx), + *!* pastrand integral logica originala din Grid1.cExplicatieTva.Combo1.Valid + *!* (linia de baza + linia pereche de TVA + comutarea 4427/401) + LOCAL lnId, lnPtva, lnId_tva, lnId_jtva_coloanaTVA, lnCota_tva, lcExplicatie_TVA + LOCAL lcExplicatieTVA, lnRec, lnTipEx, loCauta + + Select introdc + lnRec = Recno() + + * tipul exigibil(1)/neexigibil(2) se decide dupa contul liniei de TVA (linia para); + * pe linia de baza (impara) scd e contul de marfa, deci ma uit la linia urmatoare + If Mod(lnRec,2) <> 0 And lnRec < Reccount('introdc') + Skip + lnTipEx = Iif(Alltrim(scd) == '4428', 2, 1) + Go lnRec + Else + lnTipEx = Iif(Alltrim(scd) == '4428', 2, 1) + Endif + + loCauta = caut_explicatie_tva(Nvl(introdc.id_jtva_coloana,-1),,,m.lnTipEx) + + If Vartype(loCauta) <> 'O' Or Empty(Nvl(loCauta.id_jtva_coloana,0)) + Return + Endif + + * ATENTIE: in introdc.ptva se salveaza COTA BRUTA (ex. 21), ca in Combo1.Valid. + * NU (cota+100)/100 ca in registru jurnal - acolo campul e proc_tva, alta semantica. + lnId = loCauta.id_jtva_coloana + lnPtva = loCauta.cota_tva + lcExplicatieTVA = loCauta.denumire + + * id_tva (perechea pentru linia de TVA) NU vine din caut_explicatie_tva + * (selectul intoarce doar id_jtva_coloana, denumire, cota_tva) - il iau din jtva_coloane2 + Select jtva_coloane2 + Locate For id_jtva_coloana = lnId + If !Found() + Return + Endif + lnId_tva = jtva_coloane2.id_tva + + Select introdc + Replace id_jtva_coloana With lnId, ptva With lnPtva, explicatie_tva With lcExplicatieTVA + If Mod(lnRec,2)<>0 && linie impara BAZA + Thisform.UpdateExplicatieSAFT() + If lnPtva = 0 + Select introdc + Replace cu_tva With 0 + Skip + Replace id_jtva_coloana With 0, ptva With 0, explicatie_tva With '', cu_tva With 0 + Else && linia para TVA + Select jtva_coloane2 + Locate For id_jtva_coloana = lnId_tva + If Found() + lnId_jtva_coloanaTVA = jtva_coloane2.id_jtva_coloana + lnCota_tva = jtva_coloane2.cota_Tva + lcExplicatie_TVA = jtva_coloane2.denumire + + * PENTRU TAXARE INVERSA SI COMUNITATEA EUROPEANA: 4426 = 4427 PE LINIA DE TVA, ALTFEL 4426 = 401 + Select introdc + Replace cu_tva With 1 + Skip + Replace id_jtva_coloana With lnId_jtva_coloanaTVA, ptva With lnCota_tva, ; + explicatie_tva With lcExplicatie_TVA, cu_tva With 1 + If Seek(lnId_jtva_coloanaTVA, "cJtvaCol4427", "id_jtva") + Replace scc With '4427' In introdc + Else + Replace scc With '401' In introdc + Endif + Thisform.UpdateExplicatieSAFT() + Endif + Endif + Endif + + Thisform.grid1.cSuma.teXT1.Valid +ENDPROC +``` + +**Recomandări suplimentare:** + +- În `Grid1.cExplicatieTva.Text1.InteractiveChange`, după apel, adaugă + `This.Value = introdc.explicatie_tva` — altfel caracterul tastat (care a declanșat evenimentul) + rămâne în buffer-ul textbox-ului și poate suprascrie explicația la părăsirea celulei: + ```foxpro + PROCEDURE Grid1.cExplicatieTva.Text1.InteractiveChange + Thisform.do_modifica_explicatie_tva() + This.Value = introdc.explicatie_tva + ENDPROC + ``` +- **De testat mapping-ul `tlTipEx`**: comentariile din `caut_explicatie_tva` (`ocautare.prg:1936-1942`) + spun 1=JC exigibil / 2=JC neexigibil, dar filtrele din `DO CASE` (`:1962-1979`) arată invers la prima + citire (`case 1` filtrează `id_jtva_neex is not null`). Testează cu un document normal și unul cu TVA + la încasare (4428) și, dacă lista afișată e cea greșită, inversează 1↔2 în `lnTipEx`. +- Testează explicit: cotă 21%, cotă 0% (scutit), taxare inversă/CE (trebuie `scc='4427'` pe linia de TVA), + TVA la încasare (4428), anulare din formularul de căutare, apel de pe linia de TVA (para) direct. + +--- + +## 2. Valute și cursuri diferite pentru transport / alte taxe + +**Modelul de documente al fluxului** (clarificat de Marius): un NIR de import cuprinde +- **factura principală de achiziție** (marfă și/sau imobilizări/alte articole) — valuta și cursul ei + sunt cele din antet: `poAct.id_valuta` / `poAct.Curs`; ea rămâne referința în care se convertește tot; +- opțional **factura de transport** — poate fi în altă valută, cu alt curs; +- opțional **factura de taxe vamale** (comisionar/vamă) — de regulă în lei, dar poate fi și în valută; +- **Declarația vamală de import (DVI)** — cu TVA-urile aferente fiecărei facturi (plătite în lei în vamă). + +Toate ajung ca linii în același cursor `introdc`, iar apartenența unei linii la un document e DEJA +modelată per rând prin `nract` / `serie_act` / `id_fact` (`ointroduceri.prg:1554-1561`). Tot per rând +există deja și coloanele `id_valuta` și `curs` (moștenite din `poAct` la construire) — dar codul +folosește peste tot `poAct.Curs`/`Thisform.oact.Curs` în loc de valorile rândului. Deci nu trebuie +schimbată structura: (a) faci editabile valuta+cursul, logic per **document** (aceleași valori pe +toate liniile cu același `nract`); (b) folosești cursul rândului în calcule. La copierea în +`actactan` (→ `ACT_TEMP` → `ACT`), cursul per rând se salvează deja natural. + +**Modificări propuse (toate în `import_nota`):** + +**(a) UI — în VFP IDE:** adaugă în `Grid1` două coloane noi lângă `cSumaVal`: +- `cValuta` — `ControlSource = "introdc.id_valuta"`, cu un Text1 read-only care afișează codul valutei + și `DblClick` care deschide căutarea pe `NOM_VALUTE` (există `caut_valuta`/echivalent în `ocautare.prg`; + dacă nu, un mic `SELECT id_valuta, nume_val FROM nom_valute` + `cauta_alfa`). La selectare, propagă + pe **toate liniile aceluiași document** (același `nract`), inclusiv pe linia pereche de TVA: + ```foxpro + LOCAL lnNract + lnNract = introdc.nract + Update introdc Set id_valuta = loCauta.id_valuta Where nract = m.lnNract + * cursul se cere/ia imediat dupa schimbarea valutei + ``` +- `cCurs` — `ControlSource = "introdc.curs"`, editabil numeric (4 zecimale), doar pe linii cu + `in_valuta = 1`; la `Valid`, propagă la fel pe liniile cu același `nract`. Opțional: dacă există + funcție de curs BNR pe dată (caută `getcurs`/`curs_valutar` în COMUN), propune automat cursul la + data documentului respectiv (`introdc.dataact`), nu la data facturii principale. + +Liniile facturii principale rămân needitabile pe aceste coloane (păstrează `poAct.id_valuta`/`poAct.Curs`) — +doar liniile celorlalte documente (transport, taxe vamale) au voie curs propriu. Liniile de TVA din DVI +sunt în lei (`in_valuta = 0`) și rămân pe mecanismul existent (`suma`, fără curs propriu). + +**(b) Conversia — formula generală.** Contribuția unei linii la baza în valuta facturii principale: + +``` +linia in valuta (in_valuta=1): baza_val += ROUND(suma_val * introdc.curs / poAct.Curs, gnPval) +linia in lei (in_valuta=0): baza_val += ROUND(suma / poAct.Curs, gnPval) && neschimbat +``` + +Formula cu `introdc.curs` e corectă și pentru liniile în valuta principală (curs identic ⇒ raport 1), +deci poate înlocui uniform sumările existente. + +Locuri de modificat: + +1. **`inainte_de_do_termin`** (`ointroduceri.vc2:7699+`), sumările de baze (`:7792-7806`): + ```foxpro + * inainte: Sum suma_val For ... in_valuta = 1 And participa_valuta To lnBazaVal + * dupa: Sum Round(suma_val * curs / poAct.Curs, gnPval) For ... in_valuta = 1 And participa_valuta To lnBazaVal + ``` + (idem pentru `lnTvaVal`; ramurile `in_valuta = 0` cu `Round(suma/poAct.Curs, gnPval)` rămân neschimbate). +2. **Verificarea lei↔valută la editare** (`ointroduceri.vc2:8214-8221`, `cSumaVal`/`cSuma` Valid): + ```foxpro + * inainte: lnSumaDinVal = Round(suma_val * Thisform.oact.Curs, gnPC) + * dupa: lnSumaDinVal = Round(suma_val * introdc.curs, gnPC) + ``` +3. **`do_executa`** (`:7560-7598`, calculul procentelor stocate în `explicatia4`/`explicatia5`) — + verifică fiecare loc unde apare `poAct.Curs`/`oact.Curs` și înlocuiește cu cursul rândului unde + se convertește o sumă **a rândului**; `poAct.Curs` rămâne doar unde se convertește **totalul** + în valuta principală. +4. **Copierea în `actactan`** (`:7737-7782`): rândurile în lei primesc deja `Curs=0, id_valuta=0` + (`:7754`) — neschimbat; rândurile în valută își duc acum automat cursul propriu (corect). +5. **Afișaj**: `lb_curs` (`:7882-7883`) rămâne cursul facturii principale; opțional adaugă în caption + „(liniile pot avea curs propriu)". + +**Ce NU se schimbă:** repartizarea pe articole în `import_nir` (`:6276-6316`) — lucrează cu +`procent_lei`/`procent_val` derivate din bazele de mai sus și cu `ncurs = poAct.Curs` pentru prețul +în lei al articolelor; odată ce bazele sunt corecte, restul rămâne valid. + +**Testare:** factură USD + transport EUR + taxă în lei; verifică: NIR-ul valoric (lei și valută), +linia „DIFERENTE" (`:6329-6364`) să rămână nesemnificativă, nota contabilă echilibrată +(`verificare_note_contabile`), jurnalul de cumpărări. + +--- + +## 3. Conturi 2xx (nu doar 3xx) la căutarea articolelor + +Filtrul e în **`import_nir`** (nu `import_nota`), în două locuri: + +**(a) `do_adauga`** (butonul „Caută articol", `ointroduceri.vc2:5949`): +```foxpro +* inainte: +SELECT DISTINCT scd FROM actactan WHERE LEFT(ALLTRIM(scd),1) = '3' AND suma <> 0 INTO CURSOR tconturi +* dupa: +SELECT DISTINCT scd FROM actactan WHERE INLIST(LEFT(ALLTRIM(scd),1),'2','3') AND suma <> 0 INTO CURSOR tconturi +``` +Lista rezultată intră în `lcFiltru_init = [inactiv = 0 and cont in (...)]` (`:5958`) transmis la +`viz_catalog_articole()` — nimic altceva de schimbat acolo. + +**(b) `do_modiparam`** (preluarea din XLS, `ointroduceri.vc2:6177`): aceeași înlocuire. +Atenție la contul implicit `'371'` pentru articole noi (`:6215`, `:6230`) — rămâne valid ca default +al `Inputbox`-ului, utilizatorul poate tasta alt cont; nu necesită modificare, dar verifică fluxul. + +**Opțional (de discutat cu contabilul):** în loc de tot `2xx`, restrânge la clasele relevante +(ex. exclude 28x amortizări, 29x ajustări): `... WHERE (LEFT(ALLTRIM(scd),1) = '3' OR +INLIST(LEFT(ALLTRIM(scd),2),'20','21','22','23','26','27')) AND suma <> 0`. + +--- + +## 4. Articolele negestionabile 2xx să nu se salveze în RULAJE + +**Constatări:** +- Câmpul din nomenclator: `nom_articole.in_stoc` (1 = „Gestionabil"), prezent în cursorul întors de + `viz_catalog_articole` (`oproceduri_articole.prg:91-107`) — deci disponibil fără query suplimentar. +- Azi NU există nicio filtrare: tot ce e bifat în catalog intră în cursorul NIR → `rul_temp` → + `PACK_CONTAFIN.SCRIE_IN_RUL` care face `INSERT INTO RUL (SELECT ... FROM RUL_TEMP)` + (PACK_CONTAFIN.pck:1896-2015). **Filtrarea client-side e suficientă** — pachetul scrie doar ce + primește în `RUL_TEMP`. + +**Modificare propusă — `import_nir.do_adauga`, în `SCAN FOR bifa = 1` (`ointroduceri.vc2:5989`):** + +```foxpro +LOCAL lcSarite +lcSarite = '' + +SELECT (lcCrsArt) +SCAN FOR bifa = 1 + + SCATTER NAME loArt + + * articolele negestionabile cu cont 2xx nu intra pe NIR/rulaje - + * valoarea lor ramane doar pe linia de nota contabila (contul 2xx e deja debitat) + IF NVL(loArt.in_stoc,1) = 0 AND LEFT(ALLTRIM(loArt.cont),1) = '2' + lcSarite = lcSarite + IIF(EMPTY(lcSarite),'',', ') + ALLTRIM(loArt.denumire) + LOOP + ENDIF + + * ... restul SCAN-ului neschimbat ... +ENDSCAN + +IF !EMPTY(lcSarite) + amessagebox("Urmatoarele articole sunt negestionabile (cont 2xx) si NU au fost adaugate pe NIR" + ; + " (valoarea ramane doar pe nota contabila): " + lcSarite, 0+64, "Atentie") +ENDIF +``` + +**Și în `do_modiparam` (XLS):** la căutarea articolului după codmat (`:6193`), adaugă `in_stoc` în +select (`select id_articol, denumire, in_stoc from nom_articole ...`) și aplică același skip + mesaj +înainte de `Append Blank` în `rul_temp` (`:6246-6249`). + +**Atenții:** +- Dacă vrei regula pentru **orice** articol negestionabil (nu doar 2xx), scoate condiția pe cont — + sesizarea cere explicit doar 2xx, așa că am păstrat-o. +- Liniile de notă 2xx aferente acestor articole nu trebuie să participe la repartizarea valorii pe + articolele rămase: la introducerea notei, debifează `participa_valuta` (coloana `cParticipaValuta`) + pe acele linii, altfel valoarea lor umflă `procent_lei`/`procent_val` și deci prețul de intrare al + mărfurilor 3xx. De verificat operațional; se poate automatiza ulterior (warning în `do_executa` + când o linie 2xx are `participa_valuta = 1`). +- Plasă de siguranță opțională în `import_nir.inainte_de_do_termin`, înainte de `oscrie_in_fisiere` + (`:6424`): verifică `rul_temp` contra `nom_articole.in_stoc = 0` (un `SELECT` prin `goExecutor` pe + lista de `id_articol`) și șterge rândurile găsite sau avertizează. Utilă doar dacă apar și alte căi de umplere a grilei. + +--- + +## Ordine recomandată de aplicare și testare + +1. **Punctul 3** (2 linii) + **Punctul 4** (localizat) — testabile imediat pe un NIR de probă. +2. **Punctul 1** — corectează cele 4 probleme (A–D) din implementarea ta; testele de la secțiunea 1. +3. **Punctul 2** — cel mai amplu; întâi calculele (b), apoi UI (a); testele valutare de la secțiunea 2. + +După fiecare rundă de editare în IDE: `Build` + rulare + `vcx2txt.ps1` pentru refresh cache, ca să pot +verifica codul aplicat. La final: intrare în `changelog_roagest.txt` (bump versiune, tag `:modificare:`/`:nou:`).