changelog 2.11.12: achizitie import - discount financiar, TVA DVI cu valuta proprie, cote multiple
Reguli de lucru in CLAUDE.md: stil de raspuns scurt, changelog compact, curatenie (diff/handoff/temporare) inainte de commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U9uDgDfUQXbh2Neib36CN8
This commit is contained in:
18
CLAUDE.md
18
CLAUDE.md
@@ -112,6 +112,10 @@ ROAGEST - 2.11.5
|
||||
|
||||
Tags in use: `:nou:` (new feature), `:modificare:` (change), `:eroare:` (bug fix), and occasionally `:adaugare:` (addition) — match this exact tag vocabulary (a lone historical `:modfiicare:` typo exists; don't repeat it). Bump the `MAJOR.MINOR.PATCH` version (currently `2.11.5`) when you add an entry. The app checks for updates on startup (`COMUN/programe/oupdate.prg`, `wwcodeupdate.prg`) against `versiune_db.txt`'s schema stamp; the runtime reads its own version from the built `.exe`'s file version resource.
|
||||
|
||||
**Intrările sunt simple și compacte — doar strictul necesar pentru utilizatori.** O singură intrare
|
||||
consolidată per livrare (versiunea o dă Marius), fără pași intermediari, fără runde, fără mecanisme
|
||||
interne și fără erori apărute și corectate în interiorul aceleiași lucrări nelivrate.
|
||||
|
||||
## Mod de lucru: delegare către subagenți + review înainte de commit
|
||||
|
||||
Preferințele lui Marius pentru sesiunile pe acest proiect:
|
||||
@@ -119,6 +123,20 @@ Preferințele lui Marius pentru sesiunile pe acest proiect:
|
||||
- **Orchestrare pe misiuni lungi**: niciodată un singur subagent care acumulează context pe multe sarcini înlănțuite — sesiunea principală orchestrează subagenți proaspeți per sarcină (prag: max ~200–250k tokens per subagent, apoi handoff + agent nou), cu handoff compact pe disc; regula comună tuturor proiectelor ROA: `COMUN\docs\orchestrare-subagenti.md`.
|
||||
- **Delegare**: modificările de cod de volum/rutină (aplicarea unei propuneri din `docs/propuneri_*.md`, editări pe cache-ul text + write-back, actualizări de documentație, rulări de teste) se deleagă către **subagenți Sonnet care lucrează în background** (team agents — Agent tool cu `model: sonnet`, lane-uri paralele unde e posibil), iar sesiunea principală doar orchestrează și monitorizează: împarte planul pe lane-uri, transmite constatările între agenți, verifică rezultatele (diff, teste, fidelity) și intervine direct doar la deblocări (procese agățate), decizii și verificări.
|
||||
- **Fără commit fără review**: nu da commit din proprie inițiativă pe modificări de cod — Marius vrea întâi să **vadă diff-ul**. Pentru binarele VFP (`.vcx`/`.scx`), diff-ul lizibil se face pe forma text: regenerează textul din binarul vechi (HEAD din git) cu `vcx2txt.ps1 -Source` și compară-l cu textul editat din cache (`git diff --no-index`). Commit doar după ce Marius confirmă pe diff.
|
||||
- **Curățenie înainte de commit**: la finalul unei lucrări se șterg patch-urile de review (`docs/diff_runda*.patch`), handoff-urile, planurile de rundă, logurile brute de regresie/repro și backup-urile `*.pre_runda*.bak` (proiect, `COMUN`, cache text) — abia apoi commit.
|
||||
|
||||
## Stil de raspuns: scurt si concret
|
||||
|
||||
Marius vrea raspunsuri **clare, concise, fara vorbarie**. Regula, nu preferinta.
|
||||
|
||||
- **Starea si ce urmeaza, nu povestea.** Ce e gata, ce e stricat, ce trebuie decis, ce urmeaza —
|
||||
in liste scurte, cu fisier si linie. Fara reconstituirea drumului pana la rezultat.
|
||||
- **Fara naratiune de proces**: ce a raportat fiecare agent, cine ce a corectat, cum au fost
|
||||
coordonate benzile. Intra in `docs/`, nu in raspuns.
|
||||
- **Fara laude si fara reluari.** Nu repeta ce s-a spus deja in conversatie.
|
||||
- Detaliile tehnice lungi (dovezi, iesiri de test, metodologie) se scriu in fisier si se
|
||||
**trimite la el**, nu se copiaza in raspuns.
|
||||
- Cand e ceva de decis: enunta decizia si optiunile in cateva randuri, cu recomandarea ta.
|
||||
|
||||
## Reguli de lucru si testare
|
||||
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
<!--
|
||||
01/08/2026
|
||||
ROAGEST - 2.11.12
|
||||
|
||||
:nou:
|
||||
Marfa > Achizitie import. Facturile pot avea discount financiar: se completeaza suma fara TVA, TVA-ul se calculeaza pe valoarea diminuata, iar marfa si preturile articolelor raman pe valoarea integrala. Discountul se inregistreaza pe contul 767.
|
||||
Marfa > Achizitie import. TVA-ul de pe declaratia vamala (DVI) poate avea valuta si curs proprii, diferite de ale facturii.
|
||||
Marfa > Achizitie import. Facturile cu articole pe cote de TVA diferite se impart automat pe cote.
|
||||
-->
|
||||
<!--
|
||||
25/07/2026
|
||||
ROAGEST - 2.11.11
|
||||
|
||||
|
||||
@@ -144,6 +144,76 @@ dare în funcțiune deliberată.
|
||||
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`.
|
||||
|
||||
## TVA DVI cu valută proprie + discount financiar (07-08.2026)
|
||||
|
||||
- **Două coloane noi client-side pe `introdc`** (fără migrare Oracle): `rand_dvi` (identitate —
|
||||
1 pe rândul T scris de ramura DVI a `do_adauga_factura`) și `valuta_proprie` (autonomie — 1
|
||||
când acel rând T are valută/curs diferite de ale documentului, setat la creare sau din grilă).
|
||||
Nu s-a refolosit `mod_manual` — e supraîncărcat semantic (`sparge_document` face match și pe
|
||||
el pentru alte scopuri, ar fi dat duplicate/omisiuni de rânduri T).
|
||||
- **Rând „protejat"** = `Nvl(valuta_proprie,0)=1` (helper unic `rand_protejat()`, folosit
|
||||
peste tot ca `Thisform.rand_protejat()`). E ocolit de `copiaza_valoare` (câmpurile valutare nu
|
||||
se propagă pe el, câmpurile de identitate nu se propagă pe orice rând `rand_dvi=1`),
|
||||
`do_executa`, `recalc_tva_document`, `uneste_document`, `sparge_document` (vezi mai jos)
|
||||
și handlerele de grilă `cCurs`/`cInValuta`/`cValuta` (editare LOCALĂ, fără
|
||||
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
|
||||
urmează factura la propagări, identic cu azi.
|
||||
- **Spargerea T-ului protejat** (`sparge_tva_protejat`, apelată din `sparge_document`): când
|
||||
TOATE rândurile T ale documentului sunt protejate, TVA-ul facturii e integral cel de pe DVI —
|
||||
nu se mai fabrică rânduri T din rândul de bază. Varianta inițială (`loRandT = loBaza`) dădea
|
||||
**TVA dublă**: rândul protejat rămânea, plus un T nou cu conturile bazei (371 în loc de 4426),
|
||||
în valuta facturii. Acum totalul protejat se sparge pe cotele articolelor (pondere
|
||||
`bază_cotă × cotă`, rest de rotunjire pe |suma| maximă), păstrând prin `Gather` identitatea
|
||||
vamală, valuta proprie și `rand_dvi`/`valuta_proprie` — deci rândurile rezultate rămân
|
||||
protejate. O singură cotă = niciun rând atins (ieșire devreme). Analogul lui B → S, dar pe T.
|
||||
- **Discount financiar pe factură**: un singur rând `tip_rand='G'` (401=767, suma = discountul
|
||||
fără TVA), același `doc_key`/`nr_doc` cu factura, `participa_valuta=.F.`. Marfa (3028) și
|
||||
prețurile articolelor rămân pe valoarea integrală — discountul schimbă doar baza de calcul a
|
||||
TVA-ului: `T = (b-d)*p/100`, sold 401 = `b + (b-d)*p/100 - d`. Ordinea la creare e B → G → T.
|
||||
Excluse structural din bazele TVA/diferență/spargere prin filtrele deja existente pe
|
||||
`Inlist(tip_rand,'B','S')`/`'T'` — un singur loc nu filtra pe `tip_rand` (suma în valută din
|
||||
footer, `do_executa`) și a primit `And tip_rand<>'G'`.
|
||||
Punct unic de adevăr: `disc_document(doc_key, tlValuta)`. Se scade DIRECT în `do_executa` și
|
||||
`recalc_tva_document` (același `doc_key`, exact), dar se REPARTIZEAZĂ prin factor în
|
||||
`sparge_document`, unde bazele vin din `crsGrupCota` (articole), nu din `suma_doc`. Factorul e
|
||||
clampat la 0: validarea din dialog compară discountul cu suma facturii, care poate fi mai mare
|
||||
decât baza articolelor când rămâne rest pe rândul de diferențe → altfel ar ieși TVA negativă.
|
||||
`suma_doc`/`suma_doc_val` rămân BRUTE (`sparge_document` repartizează toată baza pe rândurile
|
||||
S, iar `verifica_sincronizare` compară `Suma(S)` cu `suma_doc`).
|
||||
`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
|
||||
factura e în valută) și 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`,
|
||||
`nDviTvaVal=0`. Condiția de ramură din `recalc_tva` trebuie să includă bifa, nu doar
|
||||
`dvi_valuta_efectiva()` — aceasta din urmă întoarce valuta facturii și nu știe de bifă, deci
|
||||
fără ea se scrie `dvi_tva_val` nenul împreună cu `dvi_in_valuta=.F.`. Cazul nou „factură în
|
||||
valută, DVI doar în lei" dă `dvi_valuta_proprie=1`.
|
||||
- **Concordanța cotelor pe factură multi-cotă**: rândurile S se generează pe `cont+analitic+cota_tva`
|
||||
(doar la documentul principal) și primesc cota articolelor lor — `creeaza_rand_s` are parametrul
|
||||
`tnCota`, care scrie `ptva` + `id_jtva_coloana`/`explicatie_tva` prin `gaseste_jtva_cota` (familia =
|
||||
coloana bazei). Rândul G se sparge la fel, proporțional cu bazele pe cotă (`sparge_discount`, apelat
|
||||
din `sparge_document` imediat după `calc_baze_cota_creditor`), păstrând totalul discountului;
|
||||
e idempotentă (recalculează din suma rândurilor G existente). Fără astea, baza (S) și discountul (G)
|
||||
rămâneau pe cota facturii în timp ce T-urile erau deja sparte pe cotele articolelor — în jurnalul de
|
||||
TVA baza ieșea pe altă cotă decât TVA-ul. Articolele fără cotă proprie preiau cota documentului
|
||||
înainte de grupare (altfel apare un grup tranzitoriu „cota 0").
|
||||
- **`nOldVal` e NUMERIC**: coloanele caracter din grila notelor (`cScc`/`cAscc`) folosesc `cOldVal`.
|
||||
O singură proprietate partajată între coloane numerice și caracter dădea „Operator/operand type
|
||||
mismatch" în `cSuma.Text1.Valid` când Valid se re-declanșa fără GotFocus (refresh de grilă din
|
||||
`sincronizeaza`). `cSuma`/`cSumaVal.Valid` au primit și garda `lInSync`, ca `cScc`/`cAscc`.
|
||||
- **Două reprezentări ale „RON"** — capcană reală, ușor de reintrodus: rândul din picker
|
||||
(`caut_valuta`/`vnom_valute`) e un rând REAL cu `id_valuta` nenul (`moneda_nationala=1`);
|
||||
sentinela „fără valută" din `introdc`/`ACT` e `id_valuta=0`, `nume_val=''`. Comparațiile
|
||||
trebuie făcute pe valuta EFECTIVĂ (`Empty(nume) Or Upper(nume)=='RON'`), nu pe id brut — o
|
||||
factură fără valută + RON ales explicit pe DVI sunt ambele „fără valută", dar o comparație
|
||||
de id-uri brute le-ar vedea ca diferite (`dvi_valuta_proprie` ar da fals 1).
|
||||
|
||||
## Ș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
|
||||
@@ -157,3 +227,34 @@ dare în funcțiune deliberată.
|
||||
- **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)
|
||||
|
||||
- **Perechea bază/TVA se citește din nomenclator** (`jtva_coloane2.id_tva`), iar trecerea de la o
|
||||
cotă la alta în aceeași familie se face pe **semnătura coloanei** (`coloana_jc` fără cifre:
|
||||
`FO21B`→`FOB`, `FO21T`→`FOT`) — `gaseste_jtva_cota`. Potrivirea pe primele 2 caractere confunda
|
||||
coloana de bază cu cea de TVA.
|
||||
- **Alinierea T → S** (`aliniaza_tva_la_baza`, la finalul `sparge_document`): fiecare rând T
|
||||
primește perechea de TVA a rândului S de aceeași cotă, dar numai dacă explicația S-ului chiar are
|
||||
cota rândului (altfel nu există pereche validă — cazul nomenclatorului incomplet). Fără ea, o
|
||||
explicație aleasă din altă serie pe rândul S (ex. `CE11CTB`) muta rândurile T în seria CE, în timp
|
||||
ce S-ul se re-alinia la familia documentului (`FO`) la resincronizare — bază și TVA pe rubrici
|
||||
diferite în jurnalul de TVA.
|
||||
- **`expl_manual`** (coloană client-side pe `introdc`, lângă `mod_manual`): 1 când utilizatorul
|
||||
alege explicit explicația pe un rând T (`aplica_explicatie_tva` / combo-ul din grilă); rândurile
|
||||
marcate nu se aliniază. Nu s-a refolosit `mod_manual` — acela înseamnă „nu-mi recalcula suma"
|
||||
și ar fi înghețat și sumele. Peste regenerarea rândurilor T eticheta se păstrează prin snapshot
|
||||
pe cotă (`crsExplT`, luat înainte de ștergere, reaplicat după); la `sparge_tva_protejat` rămâne
|
||||
doar pe cota rândului original, cotele apărute din spargere se aliniază normal.
|
||||
- **Golul de nomenclator la 11%**: importul de bunuri nu avea perechea de 11% (`FO11B`/`FO11T` =
|
||||
236/237, adăugate 30.07.2026). Fără pereche, `sparge_document` lasă în `cmesajsync` mesajul
|
||||
„Documentul <fdoc> are marfă la <cotă>%, dar nu există explicație TVA de <cotă>% în seria
|
||||
'<serie>'" și finalizarea rămâne blocată; utilizatorul poate ocoli lipsa alegând manual o
|
||||
explicație de 11% din altă serie.
|
||||
- **`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ă
|
||||
singure `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".
|
||||
|
||||
10
todo.txt
10
todo.txt
@@ -43,3 +43,13 @@ import unificat - preview tiparit al notei inainte de salvare (E7, amanat)
|
||||
import unificat - persistenta pozitiei splitterului per user (amanat)
|
||||
import unificat - dupa 1-2 luni de productie: stergere clase moarte import_nir si import_nota_original din ointroduceri.vcx (F6)
|
||||
import unificat v2 - id_fact per articol + extinderea modelului B/S/T/D la NIR-ul intern clasic
|
||||
conturi discount factura import (667/4426) configurabile - daca mai cere o firma (acum: 401 preluat de pe randul B, 667/4426 fixe; plan aprobat 27.07.2026)
|
||||
stergere 'doar linia curenta' pe randul B al unei facturi de import lasa randuri G (discount) / T orfane care se scriu in ACT - de curatat (comportament preexistent la T)
|
||||
|
||||
achizitie import - de verificat (gasite la runda DVI/discount, in afara scopului):
|
||||
- lSuprimaDirty e declarat si verificat in txtCurs.Valid dar NICIODATA setat pe .T. - suprimare moarta;
|
||||
txtCurs.Valid si txtSumaLei.Valid marcheaza dirty la orice pierdere de focus, nu doar la modificare
|
||||
(acelasi defect reparat la campurile DVI cu tiparul nOldVal/GotFocus).
|
||||
- conturi discount configurabile (acum fixe in cod: 401=667 / 4426=401).
|
||||
- stergere 'doar linia curenta' pe randul B lasa randuri G orfane (identic cu comportamentul randului T azi).
|
||||
nomenclator explicatii TVA - CE11CTB/CTT/FTB/FTT si XX11TIB/TIT au AFISAT=0 si ORDINE null, spre deosebire de perechile lor de 21%: de decis daca trebuie sa apara in jurnalul de TVA
|
||||
|
||||
Reference in New Issue
Block a user