# Cota de TVA a discountului de DOCUMENT (VANZARI.DISCOUNT) — program + eFactura Cercetare read-only. Nu s-a modificat niciun fisier, nu s-a rulat `git_sync.ps1`, pe Oracle doar `SELECT`. STATUS: complet. Acest document e rezultatul imbinarii a doua rapoarte de cercetare pe aceeasi intrebare, facute de doi agenti separati. Raportul suplimentar, `discount_document_cota_tva_b.md`, ramane pe disc ca sursa a partii adaugate aici (sectiunile 3.1-3.3 si observatiile din 2.3 si 4.1). ## Raspunsul scurt Discountul de document **NU se sparge pe cote**. El devine o **singura pseudo-linie negativa** numita `"Discount % Factura"`, careia i se atribuie **cota maxima de TVA de pe factura** (`Calculate Max(proc_tvav) To lnProcTvav`). eFactura chiar genereaza `cac:AllowanceCharge` la nivel de document, cu `TaxCategory/ID` + `Percent` + `TaxScheme` corecte si `AllowanceChargeReason = "Discount"`, `ReasonCode = 95` — dar **cota e cea maxima, aleasa prin `Max()`, nu de utilizator si nici proportionala**, iar "explicatia" e literalul hardcodat `"Discount"`. Regula "cota maxima" e scrisa **de doua ori**, independent: in VFP (`Calculate Max(proc_tvav)`) si in PL/SQL (`PACK_FACTURARE.recalculeaza_totaluri_vanzari`, care din ea deriva `VANZARI.DISCOUNT_TVA`, `TOTAL_TVA` si `TOTAL_CU_TVA`). Pentru #13 asta e informatia operationala: **se schimba in doua locuri, nu in unul** (sectiunea 1.5). Pe factura obisnuita (cote mixte, fara scutire), XML-ul rezultat e intern coerent (TaxSubtotal-urile includ deja pseudo-linia de discount) si **trece validarea** — verificat cu validatorul local DUKIntegrator, inclusiv pe cazul mixt si pe unul cu baza impozabila negativa. Deci defectul pe care **l-am putut dovedi** nu se vede: e o eroare **tacuta de atribuire fiscala**. Pe o factura cu 1000 lei la 21% si 1000 lei la 11% cu discount de document 10%, se declara cu **10 lei mai putin TVA** decat ar trebui (sectiunea 4.4), mereu in acelasi sens — TVA colectat subdeclarat. Pe factura scutita XML-ul e si mai putin coerent decat atat — vezi paragraful urmator. **Sectiunea 3 s-a inchis intre timp, cu un rezultat impartit.** Pe o factura obisnuita (toate liniile `scutit=0`, `expltva` gol), pseudo-linia de discount se contopeste corect in grupul cotei maxime — verificat prin masuratoare, nu doar dedus (sectiunea 3.1). Dar pe o factura **scutita, cu taxare inversa sau intracomunitara**, gruparea chiar se rupe: pseudo-linia formeaza un `TaxSubtotal` **orfan**, cu baza negativa si categorie gresita (sectiunea 3.2). Validatorul local nu respinge nici aceasta forma (sectiunea 3.3) — deci ramane, ca si defectul de atribuire fiscala, o eroare **tacuta**, nu una care blocheaza factura. --- ## 1. Cum se aplica azi discountul de document in program **Cine il aplica: amandoua, fiecare pentru consumatorul lui.** Oracle stocheaza `VANZARI.DISCOUNT` (valoare absoluta, in moneda documentului) si `VANZARI.DISCOUNT_EVIDENTIAT`, si **isi calculeaza singur** TVA-ul discountului in `PACK_FACTURARE.recalculeaza_totaluri_vanzari` (sectiunea 1.5); prelucrarea pentru **listare si eFactura** se face separat, in cursoare VFP (sectiunile 1.1-1.4). Ambele folosesc aceeasi regula — cota maxima — dar o implementeaza independent. ### 1.1. Randul-sentinela `ZZZZ...` in `crsfactura` `COMUN\programe\ofacturare_comun.prg:1886-1897` (`Procedure prelucreaza_facturacrs`): ``` 1886 If tnDiscount<> 0 1888 Calculate Sum(valdiminuatftva),Sum(vvaldiminuatftva),Max(id_temp) To lnTotalBaza,lnTotalBazaVal,lnIdTemp 1890 Append Blank 1891 Replace denumire With Replicate('Z',20),cantitate With 1,; 1892 pretftva With lnTotalBaza,discountftva With tnDiscount,valdiscountftva With tnDiscount,; 1893 valdiscounttva With Round(tnDiscount * (tnProcTvav - 1),gnPc),; 1894 vpretftva With lnTotalBazaVal,vdiscountftva With tnDiscountVal,vvaldiscountftva With tnDiscountVal,; 1895 vvaldiscounttva With Round(tnDiscountVal * (tnProcTvav - 1),gnPVal),; 1896 proc_Tvav With tnProcTvav,id_temp With lnIdTemp+1 1897 Endif ``` Observatii portante: - **baza** discountului = `Sum(valdiminuatftva)` peste **toate** liniile, indiferent de cota; - **TVA-ul** discountului = `tnDiscount * (tnProcTvav - 1)` — o **singura** cota, `tnProcTvav`; - randul e un **singur rand de document**, nu o repartizare pe linii. ### 1.2. De unde vine `tnProcTvav` — cota maxima de pe factura Toate cele trei cai de apel calculeaza acelasi lucru: | apelant | linia | cod | |---|---|---| | listare factura emisa (din lista de facturi) | `COMUN\clase\ofacturare_comun.vc2:4494-4498` (`frm_facturi.do_listeaza_formular`, 4188-4539) | `Calculate Max(proc_tvav) To lnProcTvav` -> `prelucreaza_facturacrs([crsdetalii],[crsfactura],lnProcTvav,lnDiscount,lnDiscountVal)` | | listare proforma | `COMUN\clase\ofacturare_comun.vc2:7293-7298` (`frm_proforme.do_listare`, 7233-7315) | idem | | listare din `oproceduri_facturare` | `COMUN\programe\oproceduri_facturare.prg:1386-1391` | `Select crsDetaliiListare` / `Calculate Max(proc_tvav) To lnProcTvav` | | facturare din stoc | `COMUN\programe\ofacturare_stoc.prg:582, 728` | `Calculate Max(proc_tvav) To lnProcTvav` | **Deci cota de TVA a discountului de document = MAX(cotele de pe liniile facturii).** Nu e nici aleasa de utilizator, nici derivata din structura pe cote, nici proportionala. Nu exista niciun control in formular pentru ea si nicio coloana in `VANZARI` care sa o retina. ### 1.3. Randul `ZZZZ...` devine pseudo-linia `"Discount NN.NN % Factura"` `COMUN\programe\ofacturare_comun.prg:1273-1392` (in `prelucreaza_factura`, scan peste `crsfacttemp`): ``` 1279 If loArticol.denumire <> Replicate('Z',20) ... (linia normala de articol se copiaza in cursorul destinatie) 1361 Else 1362 loArticol.denumire = [FACTURA] 1363 Endif 1365 If lnPretListAviz = 2 && pret fara tva 1367 If loArticol.discountftva <> 0 1368 Append Blank 1369 lnProcentDiscount = loArticol.discountftva * 100 / loArticol.pretftva 1370 Replace denumire With [Discount ]+Alltrim(Str(lnProcentDiscount,10,2))+[ % ]+Alltrim(Proper(loArticol.denumire)),; 1374 pretftva With (-1) * loArticol.discountftva,valftva With (-1) * loArticol.valdiscountftva,...; 1375 ... valtva With (-1) * loArticol.valdiscounttva,; 1376 proc_tva With loArticol.proc_Tvav,id_jtva_coloana With loArticol.id_jtva_coloana,... 1378 Endif ``` Randul `ZZZZ...` nu ajunge niciodata in cursorul final ca atare — la `:1361-1363` doar i se schimba denumirea in `FACTURA`, iar la `:1367-1377` se creeaza pseudo-linia **`"Discount 10.00 % Factura"`** cu `pretftva` si `valftva` **negative** si `proc_tva = tnProcTvav`. **Coloanele atinse in cursorul final** (`crsFacturaFinala` / `crsfacturafinalaval`): `denumire`, `cantitate`, `pretftva` (negativ), `valftva` (negativ), `valtva` (negativ), `proc_tva`, `id_jtva_coloana`, `id_jtva_coloana_ex`. Deci **discountul de document mosteneste si coloana de jurnal TVA (`id_jtva_coloana`) a randului-sentinela** — care nu e setata la `:1891-1896`, deci ramane 0/blank pe randul `ZZZZ`. (Consecinta in eFactura: sectiunea 2.3.) ### 1.4. `discount_evidentiat` schimba cate pseudo-linii "Discount" apar - `discount_evidentiat = 0` (implicit): ramura `ofacturare_comun.prg:1177-1203`. Liniile de articol primesc `0 As discountftva` (`:1188`), deci **nu** genereaza pseudo-linii; doar randul `ZZZZ` (reinserat separat prin `Where denumire = Replicate('Z',20)`, `:1193-1203`) pastreaza `discountftva` -> **o singura** pseudo-linie de discount, cea de document. - `discount_evidentiat = 1`: ramura `:1157-1173`, un singur `Insert` fara `WHERE`, `discountftva` pastrat per articol (coloana 20 din `group by 2,3,...,20,...`) -> **fiecare articol cu discount unitar produce propria pseudo-linie** `"Discount X % "`, plus cea de document. Aici cotele chiar sunt cele ale articolelor respective. ### 1.5. Regula "cota maxima" e implementata A DOUA OARA, in Oracle Corectie la afirmatia de la inceputul sectiunii 1 ("Oracle stocheaza doar `VANZARI.DISCOUNT`"): **este incompleta**. `PACK_FACTURARE.recalculeaza_totaluri_vanzari` reface acelasi rationament independent, in PL/SQL — `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`, procedura de la `:16024`: ``` 16081 MAX(ROUND(decode(lnInValuta, 1, 16082 ROUND(a1.curs * NVL(lnDiscountFactura,0) / a1.multiplicator, lnPreciziePretV), 16085 NVL(lnDiscountFactura,0)) * 16088 (a1.proc_tvav - 1), lnPreciziePretV)) as DISC_TVA_RON, 16090 MAX(ROUND(NVL(lnDiscountFactura,0) * (a1.proc_tvav - 1), lnPreciziePretV)) as DISC_TVA_VAL, ``` **Precizare pe forma exacta**: nu e `discount * MAX(proc_tvav)`, ci `MAX(discount * (proc_tvav-1))` — maximul se ia peste **produsele rotunjite**. Cat timp `lnDiscountFactura >= 0` cele doua coincid (acelasi rand castiga), deci efectul e identic cu al VFP-ului. Ar diverge doar pe un discount **negativ** (o majorare), unde `MAX` ar alege cota cea mai **mica** — n-am verificat daca un discount negativ e posibil in UI. **Ce se scrie cu asta** (`:16049-16062` -> `:16214-16227`): nu doar `VANZARI.DISCOUNT_TVA`, ci si **totalurile salvate ale documentului**: ``` 16052 a.suma_tva_ron - a.disc_tva_ron as TOTAL_TVA, 16053 a.suma_fara_tva_ron - a.disc_fara_tva_ron + a.suma_tva_ron - a.disc_tva_ron as TOTAL_CU_TVA, ... 16214 update vanzari set discount = lnDiscountFactura, discount_tva = lnDiscountTVA, ... 16218 total_tva = lnTotalTVA, total_cu_tva = lnTotalCuTVA, ... where id_vanzare = V_ID_VANZARE; ``` **Consecinta pentru #13**: regula de repartizare a discountului pe cote trebuie schimbata **in doua locuri, nu unul** — `prelucreaza_facturacrs` (VFP, pentru listare/eFactura/nota contabila) **si** `recalculeaza_totaluri_vanzari` (Oracle, pentru `VANZARI.DISCOUNT_TVA` / `TOTAL_TVA` / `TOTAL_CU_TVA`, adica pentru ce se vede in liste, rapoarte de sinteza si sold). Daca se schimba doar unul, `VANZARI.TOTAL_TVA` si TVA-ul din XML **vor diverge**. Nu am verificat care dintre cele doua valori e considerata azi "cea buna" acolo unde ambele sunt disponibile. ### 1.6. Ramura "pret cu TVA" (`lnPretListAviz = 1`) — nu atinge facturile `ofacturare_comun.prg:1380-1391` (ramurile `Otherwise` / `tnDiscountEvidentiat=1 And lnPretListAviz=1`) seteaza pe pseudo-linia de discount **numai** `pretctva`/`valctva`/`valtva`, **nu** si `pretftva`/`valftva` — care raman 0. Am verificat daca asta poate ajunge in eFactura: **nu poate**. `lnPretListAviz` e initializat `= 2` (`COMUN\programe\ofacturare.prg:1112`) si e pus pe `1` intr-un singur loc, in ramura de **aviz de transfer** (`lcRaport = [AVIZ]`, `ofacturare.prg:1856-1861`, conditionat de `gnPretListAviz = 1`), iar avizele nu trec de filtrul `tip_doc_394 IN ('F','S','M','U','H')` din `xmlefactura.prg:276-279`. Deci nu e un defect eFactura. --- ## 2. Ce ajunge in XML-ul eFactura **Generatorul viu** e `COMUN\programe\xmlefactura.prg` (`getXmlEFactura`), apelat prin `goExport.export2xml_efactura` (`COMUN\programe\oexport.prg:1586-1594`) din `COMUN\programe\ofacturare.prg:2126`, cu cursorul `crsFacturaFinala` (sau `crsfacturafinalaval` in valuta) — exact cursorul de listare (`ofacturare.prg:2108-2114`). `COMUN\clase\anaf_efactura.vc2` este UI-ul/transportul ANAF (trimitere, validare, preview), nu generatorul de XML. ### 2.1. Da — se genereaza `cac:AllowanceCharge` la nivel de document Detectia e **euristica pe denumire + semn**, `xmlefactura.prg:230`: ``` 230 Iif('DISCOUNT' $ Upper(a.denumire) And a.pretftva < 0, 1, 0) As discount ; ``` Pseudo-linia `"Discount 10.00 % Factura"` cu `pretftva < 0` (sectiunea 1.3) satisface ambele conditii. Randurile marcate `discount = 1` sunt excluse din liniile normale (`Scan For discount = 0`, `:901`) si emise ca alocari de document, `xmlefactura.prg:756-795`: ``` 757 If mliniireducere > 0 758 SELECT SUM(-1*valftva) as valftva, proc_tva ; 759 FROM C_IES_FORM ; 760 WHERE discount = 1 ; 761 GROUP BY proc_tva ; 762 ORDER BY proc_tva ; 763 INTO CURSOR cDiscounturiTemp 765 Select cDiscounturiTemp 766 SCAN 770 oallowancecharge = oinvoice.appendchild(oxml.createelement("cac:AllowanceCharge")) 771 ... ChargeIndicator = "false" 773 ... cbc:AllowanceChargeReasonCode = "95" 775 ... cbc:AllowanceChargeReason = "Discount" 777 odocallowancecharge = ... ("cbc:Amount") && BT-92 778 odocallowancecharge.setattribute("currencyID", "RON") 779 odocallowancecharge.Text = Alltrim(Str(m.lnValftva, 15, 2)) 780 otaxcategoryallowance = ... ("cac:TaxCategory") 782 Select tip From C_TVA_FACTURA Where proc_tva = (m.lnProcTva - 1) * 100 Into Array agettipcota 786 otaxcategoryallowance.lastchild.Text = Alltrim(agettipcota(1)) 787 ... ("cbc:Percent") 788 otaxcategoryallowance.lastchild.Text = Alltrim(Str((m.lnProcTva - 1) * 100, 2, 0)) 789 otaxschemeallowance = ... ("cac:TaxScheme") / cbc:ID = "VAT" 792 ENDSCAN ``` Raspunsurile punctuale: - **`cac:TaxCategory/cbc:ID`** (`S`, `AE`, `Z`, `E`, `K`, `O`): **nu e hardcodat** — se ia din `C_TVA_FACTURA.tip`, adica din `This.GetTipTaxa(mtipfactura, intracomunitar, taxare_inversa, scutit, proc_tva, @lcExplicatie, @lcMotiv, expltva)` (`xmlefactura.prg:298`), pe grupul cu **aceeasi cota** ca pseudo-linia de discount. - **`cbc:Percent`**: `(proc_tva - 1) * 100` al pseudo-liniei — adica **cota maxima de pe factura** (sectiunea 1.2). *Aici e raspunsul la intrebarea lui Marius: cota exista in XML, dar sursa ei e un `Max()`, nu o alegere.* - **`cbc:AllowanceChargeReason`**: literalul `"Discount"` (`:776`), **hardcodat**; **`cbc:AllowanceChargeReasonCode`**: `"95"` (`:774`), hardcodat. Textul real din program (`"Discount 10.00 % Factura"`) **nu** ajunge in XML — ramane doar in cursorul de listare. Deci "explicatia" pe care o cauta Marius nu exista: e o constanta. ### 2.2. Cote mixte: se sparge in mai multe `AllowanceCharge`? **Mecanismul exista** (`GROUP BY proc_tva`, `:761` -> cate un `AllowanceCharge` per cota), dar **nu se activeaza pentru discountul de document**, pentru ca acesta e prin constructie o **singura** pseudo-linie cu o **singura** cota (`Max`). Gruparea foloseste efectiv doar cand `discount_evidentiat = 1`, unde exista mai multe pseudo-linii de discount **pe articol**, fiecare cu cota articolului ei. Deci, pe o factura cu 21% si 11% si un discount de document: **un singur** `AllowanceCharge`, cu `Percent = 21`. ### 2.3. Riscuri identificate in acest bloc (nedovedite pe rulare) - **`currencyID` hardcodat `"RON"`** la `:778`, in timp ce tot restul documentului foloseste `mmoneda` (`:820, 827, 873, 876, ...`, definit la `:266-267`). Pe o factura in valuta cu discount de document, `AllowanceCharge/cbc:Amount` iese cu `currencyID="RON"` iar `LegalMonetaryTotal/cbc:AllowanceTotalAmount` cu `currencyID="EUR"`. Acelasi tipar la acciza (`:803`). **Testat cu validatorul local** (sectiunea 4.3): DUKIntegrator **nu** respinge neconcordanta. Ramane o inconsecventa de cod, dar nu doar teoretica: sectiunea 4.1 arata un XML real de productie cu exact aceasta neconcordanta, confirmat pe SHA256 ca a plecat la ANAF si a fost **acceptat**. - **`Select ... Into Array agettipcota` fara garda pe `_Tally`** (`:782-786`): daca gruparea nu gaseste randul (egalitate pe numere in virgula mobila: campul `C_TVA_FACTURA.proc_tva` e stocat rotunjit, comparatia se face cu `(lnProcTva-1)*100` calculat la rulare), `agettipcota(1)` da eroare de variabila inexistenta. *Risc teoretic — nu l-am putut reproduce; il semnalez ca "de verificat", nu ca defect.* - **`Str((lnProcTva-1)*100, 2, 0)`** — latime 2. Pentru cotele romanesti (0, 5, 9, 11, 19, 21) e in regula; o cota de trei cifre ar da `**`. --- ## 3. Coerenta cu `TaxTotal` / `TaxSubtotal` **Da, baza impozabila din XML tine cont de discount** — si o face corect aritmetic. `C_TVA_FACTURA` se construieste **peste toate randurile** din `C_IES_FORM`, **inclusiv** pseudo-linia de discount (nu exista `WHERE discount = 0`), `xmlefactura.prg:242-248`: ``` 242 Select(proc_tva - 1) * 100 As proc_tva, intracomunitar, taxare_inversa, scutit, expltva, ; 243 Sum(valtva) As tva, ; 244 Sum(valftva) As valoare, ... ; 245 From C_IES_FORM ; 246 Group By proc_tva, intracomunitar, taxare_inversa, scutit, expltva ; 247 Into Cursor C_TVA_FACTURA ``` `valftva`/`valtva` ale pseudo-liniei sunt negative -> grupul cotei maxime iese **deja net de discount**. `cbc:TaxableAmount` = `C_TVA_FACTURA.valoare` (`:828`), `cbc:TaxAmount` = `C_TVA_FACTURA.tva` (`:831`). Totalurile inchid corect (`:863-898`): ``` 864 Sum valftva To mtotalnet For discount = 0 && numai liniile reale 867 mtotalnetliniifactura = mtotalnet && BT-106 LineExtensionAmount 869 mtotalnet = mtotalnet + mtotalcharges - mtotalallowances && BT-109 TaxExclusiveAmount 870 mtotalbrut = mtotalnet + mtotaltva && BT-112 TaxInclusiveAmount 882 ... AllowanceTotalAmount = mtotalallowances && BT-107 ``` cu `mtotalallowances = mdiscounturi = Sum(-1*valftva) For discount = 1` (`:282-287`). Verificare: `Σ TaxSubtotal/TaxableAmount` = suma peste toate randurile = `mtotalnetliniifactura − mdiscounturi` = `mtotalnet` = `TaxExclusiveAmount`. Deci **BR-CO-13** (`TaxExclusiveAmount = LineExtensionAmount − AllowanceTotalAmount + ChargeTotalAmount`) si **BR-CO-15** se respecta. **Concluzie**: pe **factura obisnuita**, suma liniilor minus discount **da** `TaxableAmount`-ul declarat; discrepanta nu e aritmetica, ci **de atribuire pe cote** (sectiunea 4). Pe **factura scutita / cu taxare inversa / intracomunitara**, concluzia nu tine — vezi 3.1-3.3. Rationamentul de mai sus presupune ca pseudo-linia de discount **cade in acelasi grup** cu liniile de la cota maxima. Asta e adevarat doar daca cele patru chei suplimentare din `GROUP BY` (`intracomunitar`, `taxare_inversa`, `scutit`, `expltva`, `xmlefactura.prg:246`) ies **egale** pe pseudo-linie si pe liniile reale. Subsectiunile care urmeaza verifica exact asta, prin masuratoare, nu prin deductie. ### 3.1. Verificat prin masuratoare: `IIF()` peste NULL nu se propaga ca `.NULL.` in VFP Pseudo-linia are `id_jtva_coloana = 0` (randul-sentinela e `Append Blank` la `ofacturare_comun.prg:1890` si campul nu e setat la `:1891-1896`). Daca LEFT JOIN-ul de la `xmlefactura.prg:226-232` nu gaseste rand in `cJTVAVanzariTemp` pentru `id = 0`, `b.coloana_jv` iese `.NULL.`, si intrebarea e ce intoarce `Iif(Left(.Null.,2) = 'CE', 1, 0)` — daca s-ar propaga ca `.NULL.`, cheia de grupare a pseudo-liniei ar diferi de a liniilor reale pe **orice** factura. Am rulat o sonda headless (`vfp9.exe -A -T`, `probe_null.prg`) care reproduce exact acest `LEFT JOIN` si `GROUP BY`, cu o pseudo-linie de discount pe `id_jtva_coloana = 0`: ``` 1) IIF(.NULL.="CE",1,0) -> tip=N isnull=.F. 2) IIF(LEFT(.NULL.,2)="CE",1,0) -> tip=N isnull=.F. 3) IIF(INLIST(.NULL.,...),1,0) -> tip=N isnull=.F. linie=ARTICOL A | coloana_jv nul=.F. | intracom=0 | scutit=0 linie=ARTICOL B | coloana_jv nul=.F. | intracom=0 | scutit=0 linie=Discount 10.00 % Factura | coloana_jv nul=.T. | intracom=0 | scutit=0 4) grupuri in C_TVA_FACTURA = 1 grup: cota=21 baza=1350 tva=283.50 (1500 - 150, corect) ``` **`IIF()` intoarce ramura falsa, nu `.NULL.`**, chiar daca conditia e nula. Deci pe o factura interna obisnuita pseudo-linia primeste `intracomunitar=0, taxare_inversa=0, scutit=0` — exact ca liniile reale — si **se contopeste in grupul cotei maxime**. Sonda ramane pe disc in `%TEMP%\claude\...\scratchpad\probe_null.prg`, nu depinde de baza de date si se poate reface oricand. ### 3.2. Dar pe factura scutita / taxare inversa / intracomunitara, gruparea chiar se rupe Contopirea de la 3.1 tine doar cat timp **si liniile reale** au `scutit=0` si `expltva` gol. Pe o factura scutita nu e asa: | camp din cheia `Group By` (`xmlefactura.prg:246`) | liniile reale (scutite) | pseudo-linia de discount de document | |---|---|---| | `id_jtva_coloana` | id real (ex. 11) | **0** — `prelucreaza_facturacrs` nu-l seteaza niciodata pe randul `ZZZZ` (`ofacturare_comun.prg:1891-1896`) | | `coloana_jv` (din `LEFT JOIN`) | `'WRSCDD'` | `.NULL.` — `cJTVAVanzariTemp` e incarcat cu `where afisat > 0 and id_jtva_coloana > 0` (`updateserver.prg:578`), deci **nu exista rand cu id 0** | | `scutit` | **1** | **0** | | `expltva` | `'Scutit cu drept de deducere'` | **gol** | Ultimul rand merita explicat, pentru ca e contraintuitiv: `completeaza_explicatie_tva` (`ofacturare_comun.prg:2077-2137`) chiar **include** pseudo-linia in lista de id-uri cautate — scanul de la `:2094` e `For proc_tva = 1 And Nvl(id_jtva_coloana,-1) <> -1`, iar pseudo-linia are `proc_tva = 1` (cota 0) si `id_jtva_coloana = 0`, deci trece filtrul. Dar interogarea de la `:2108` e `where id_jtva_coloana in (...)` pe `jtva_coloane`, unde id-ul 0 nu exista, asa ca `Replace expltva ... For NVL(id_jtva_coloana,0) = m.lnIdJtva` (`:2129`) nu o atinge niciodata. Ramane goala. Doua campuri diferite din cinci => **doua grupuri**. XML-ul iese cu: ```xml ... Discount 539.82 Z0... 0.00 -539.82 0.00 Z0... 4410.00 0.00 E0 Scutit cu drept de deducere... ``` Categoria `Z` a grupului orfan vine din `GetTipTaxa` ramura cu ramura (`xmlefactura.prg:1116-1140`): `intracomunitar=0` sare peste `'K'`, `taxare_inversa=0` sare peste `'AE'`, `scutit=0` sare peste `'E'`, si cade pe `Case m.lcTipFactura = 'F' And m.lnProcTva = 0` -> **`'Z'`** (`:1128-1129`). In plus, cautarea categoriei pentru `AllowanceCharge` (`xmlefactura.prg:782-786`) devine ambigua: `Select tip From C_TVA_FACTURA Where proc_tva = 0 Into Array agettipcota` gaseste acum **doua** randuri (`E` si `Z`), iar codul ia neconditionat `agettipcota(1)` — primul in ordinea cursorului, nu cel corect prin vreun criteriu. Ordinea nu e garantata de VFP si nu a fost fixata experimental; categoria alocarii poate iesi `E` sau `Z` dupa caz — oricare din ele e gresita ca modelare, doar in mod diferit. **Nu s-a reprodus scenariul end-to-end prin program** (ar fi cerut o factura scutita cu discount de document, iar in baza de dev nu exista — sectiunea 4.2). Ramane stabilit din citirea codului plus semantica `IIF`/NULL masurata la 3.1, nu dintr-o factura rulata efectiv prin program. ### 3.3. Validare offline: XML-ul cu grup orfan nu e respins, dar controlul negativ functioneaza XML-urile de mai sus au fost construite pornind de la o factura reala acceptata de ANAF ca schelet si trecute prin validatorul local `DUKIntegrator.jar` (acelasi apel ca la 4.3): | scenariu | ce contine | rezultat | |---|---|---| | `scutit_bug` | scutit + discount de document, **cu grupul orfan** (ce produce codul azi) | **ok** | | `scutit_corect` | scutit + discount, un singur `TaxSubtotal` net (varianta corecta) | **ok** | | `control_stricat` | `TaxExclusiveAmount` stricat intentionat, ca martor ca validatorul chiar valideaza | **eroare `BR-CO-13` + `BR-CO-15`** | Controlul negativ conteaza: fara el, un „ok" pe `scutit_bug` n-ar dovedi nimic — ar putea insemna ca validatorul nu verifica deloc coerenta totalurilor. Cu el, e clar ca validatorul **chiar verifica**, si totusi trece grupul orfan. **De ce trece**: regulile EN16931 pe categorii (`BR-S-08`, `BR-E-08`, `BR-Z-08`) cer ca baza declarata pe o categorie sa fie egala cu *suma liniilor din acea categorie minus alocarile din aceeasi categorie*. Grupul orfan respecta asta trivial (`0 - 539.82 = -539.82`), iar grupul `E` la fel (`4410.00 - 0`). Aritmetica inchide; **modelarea fiscala e cea gresita**, si asta niciun schematron nu prinde. Aceeasi rezerva ca in 4.3: validatorul local e din ianuarie 2022 (`ro16931-ubl-1.0.8`); validatorul online curent al ANAF nu a fost apelat (interdictie explicita). > **Verdict sectiunea 3**: contopirea corecta descrisa mai sus e confirmata prin masuratoare pentru > factura obisnuita (3.1) si infirmata pentru factura scutita / taxare inversa / intracomunitara > (3.2), unde discountul de document formeaza un `TaxSubtotal` orfan cu baza negativa si categorie > ambigua (`E` sau `Z`). Pe niciuna din cele doua forme validatorul local nu respinge XML-ul (3.3, > si 4.3 pentru cazul cu cote mixte) — deci ramane, ca si defectul din sectiunea 4, o eroare > **tacuta**, nu una care blocheaza factura. --- ## 4. Defect real sau gol de proiectare **Verdict: NU s-a putut dovedi un defect de VALIDARE — nici pe factura obisnuita, nici pe cea scutita cu grupul orfan (sectiunea 3.2-3.3), validatorul local nu respinge XML-ul. S-a dovedit in schimb un defect de ATRIBUIRE FISCALA: pe facturi cu cote mixte, tot TVA-ul discountului de document se scade din cota maxima, si pe facturi scutite/taxare inversa/intracomunitare, o modelare fiscala gresita (grup orfan) care trece neobservata.** Adica exact ce banuia Marius, dar consecinta stabilita nu e "factura respinsa", ci "TVA colectat gresit sau baza modelata gresit, tacut". > **Nuanta ramasa, dupa inchiderea ipotezei din sectiunea 3**: ipoteza grupului orfan **s-a > confirmat** pentru facturile scutite/taxare inversa/intracomunitare (3.2), dar validatorul local > **nu** o respinge (3.3) — deci nu devine, cum s-ar fi putut anticipa, un defect de validare > propriu-zis, ci ramane in aceeasi categorie cu restul sectiunii 4: o eroare de modelare care nu > blocheaza factura. Testele din 4.3 (cote mixte) si cele din 3.3 (factura scutita) acopera acum > ambele forme. ### 4.1. Dovada ca mecanismul chiar produce `AllowanceCharge` de document in productie Am cautat in cele ~250 de XML-uri eFactura salvate pe disc (`D:\ROA\Efactura`, `D:\ROA\ROAEFACTURA`, `D:\ROA\ROAFACTURARE\Utile\efactura`) blocurile `cac:AllowanceCharge` care contin `cac:TaxCategory` (marca alocarii **de document**; cele de linie nu au `TaxCategory`, au `MultiplierFactorNumeric`). Exemple reale: | fisier | Amount | TaxCategory | Percent | |---|---|---|---| | `D:\ROA\Efactura\2024_01\VENDING_MASTER_SRL\efactura_20240125_1526_BEST_POWER_DANCE_S_R_L_.xml` | 13.84 / 25.02 (doua) | S / S | 9 / 19 | | `D:\ROA\Efactura\2024_02\VENDING_MASTER_SRL\efactura_20240216_2885_IT_BUL_PLAST_LTD.xml` | 539.82 | E | 0 | | `D:\ROA\Efactura\2024_03\VENDING_MASTER_SRL\efactura_20240301_3736_BRIANA_ALIMENT_SRL.xml` | 411.01 | S | 9 | | `D:\ROA\Efactura\2024_07\VENDING_MASTER_SRL\efactura_20240426_7446_CIA_TRADE_POSSIBLE_SRL.xml` | 176.15 | S | 9 | Forma emisa (exemplu real, `...2885...`): ```xml false 95 Discount 539.82 E0 VAT ``` **Precizare de onestitate**: niciunul dintre aceste patru nu pot sa-l atribui sigur discountului de **document**. Dimpotriva — la `...7446...` factura are linii pe 9% (2016.51) si pe 19% (1477.11), iar unica alocare cade pe **9%**; daca ar fi fost discount de document, `Max(proc_tvav)` ar fi dat **19%**. Deci acolo sunt discounturi **pe linie** cu `discount_evidentiat = 1` (sectiunea 1.4). La fel `...1526...`, unde cele doua alocari sunt exact 2.00% din baza fiecarei cote. **Nu am gasit pe disc un XML in care sa pot identifica pozitiv un discount de document.** Ce dovedesc aceste fisiere e ca **traseul cod -> `AllowanceCharge` cu `TaxCategory` chiar functioneaza in productie** si ca gruparea pe cote e reala cand exista mai multe pseudo-linii de discount. **Al treilea indiciu, pe acelasi fisier `...2885...`, in sens invers.** Factura e integral **scutita cu drept de deducere**: toate cele trei linii sunt `E` / `Percent 0` cu `TaxExemptionReason = "Scutit cu drept de deducere"`, `DocumentCurrencyCode = EUR`, si are `AllowanceCharge` la nivel de document de 539.82 cu `TaxCategory ID = E`. Are **un singur `TaxSubtotal`**: `TaxableAmount = 3870.18`, adica exact `4410.00 − 539.82` — **net de discount, fara grup orfan**. Asta e semnificativ dupa sectiunea 3.2: `expltva` face parte din cheia de grupare, iar grupul unic de aici poarta `TaxExemptionReason` completat. Daca pseudo-linia de discount ar fi avut `expltva` gol si `id_jtva_coloana = 0` (cazul discountului de **document**, descris la 3.2), gruparea nu s-ar fi putut contopi — ar fi iesit doua grupuri, ca in `scutit_bug` (3.3). Contopirea observata aici dovedeste deci ca pseudo-linia purta un `id_jtva_coloana` real, adica era un discount **pe linie** (`discount_evidentiat = 1`), nu de document — un al treilea indiciu, independent de cele doua de mai sus (alocare pe cota minima la `...7446...`; doua alocari la `...1526...`), care coroboreaza aceeasi concluzie: cele patru XML-uri de productie gasite sunt discounturi pe linie, nu de document. Fisierul arata insa **pozitiv forma corecta** pentru o factura scutita cu discount de document: cand pseudo-linia poarta `id_jtva_coloana` corect, grupul iese unul singur si net — exact forma recomandata la sectiunea 6, punctul 1. Deci recomandarea are un precedent real in productie, nu doar o constructie sintetica de test. **Rezerva onesta**: fisierul e din februarie 2024, iar inferenta presupune ca traseul de cod e neschimbat de atunci; ramane adevarat ca **nu exista niciun XML de productie identificat pozitiv ca discount de DOCUMENT**. **Identitatea fisierului, verificata pe SHA256.** `D:\ROA\Efactura\2024_02\VENDING_MASTER_SRL\efactura_20240216_2885_IT_BUL_PLAST_LTD.xml` (5922 octeti) are acelasi SHA256 (`3303AFE34BC9E3E84DA9B3527C435DD9B8CB0BC7881D7D2F660A250237E23C64`) cu `4172939206.xml` din `...\TRIMISE\4172939206_3250292036.zip` — deci e exact ce a plecat la ANAF, si a fost **acceptat**. Continutul din `...\ERORI\4172675286_3249814520.zip` e un mesaj de eroare de 446 octeti pentru o incarcare **anterioara**, cu alt index de incarcare, si listeaza exact doua reguli: `BR-CO-15` si `BR-CL-04` (cod de moneda invalid). Deci respingerea aceea **nu** e a fisierului cu `currencyID="RON"` discutat la sectiunea 2.3 — acela a trecut. ### 4.2. Datele din baza de dev — putine, dar arata ca situatia e posibila `MARIUSM_AUTO@ROA_CENTRAL`, doar `SELECT`: - facturi nesterse cu `VANZARI.DISCOUNT <> 0`: **3** (id_vanzare 165 / 575 / 576; `discount_evidentiat` = 1 / 1 / 0). Toate trei au **o singura cota** pe linii (1.19, 1.24, 1.24). - facturi nesterse cu **cote mixte** pe linii: **34**. Deci in dev nu exista intersectia "discount de document + cote mixte". **Asta nu dovedeste nimic** — volumele de dev sunt mici, iar ambele ingrediente exista separat. In productie combinatia e banala (orice comerciant cu alimente 9%/11% + nealimentare 21% care da un discount global). ### 4.3. Ce am testat efectiv cu validatorul ANAF, offline Am folosit **validatorul local** `D:\ROA\COMUNROA\dist_efactura\DUKIntegrator.jar` (`-v FACT1`, reguli `ro16931-ubl-1.0.8`), acelasi pe care il apeleaza `xmlefactura.prg:1166-1194`. **Nu s-a trimis nimic catre ANAF; nu s-a apelat niciun serviciu web.** XML-urile de test sunt in `%TEMP%\claude\...\scratchpad\` (base/scenA/scenB/scenC_*), construite plecand de la un XML real valid. | test | ce contine | rezultat | |---|---|---| | `base` | XML-ul real `...7446...`, nemodificat (martor) | **ok** | | `scenA` | cote mixte 21% + 11%, discount 200 lei atribuit **integral** cotei 21% (exact ce genereaza programul) | **ok** | | `scenB` | 100 lei @21% + 5000 lei scutit, discount 510 lei la 21% -> `TaxableAmount = -410.00`, `TaxAmount = -86.10` | **ok** | | `scenC_corect` | acelasi ca scenA, in EUR, cu `AllowanceCharge/Amount currencyID="EUR"` | **ok** | | `scenC_bug` | idem, dar cu `currencyID="RON"` pe alocare (ce face codul la `:778`) | **ok** | **Concluzii, inclusiv cele care imi infirma ipotezele:** 1. Atribuirea intregului discount cotei maxime **trece validarea** — deci nu e o eroare pe care ANAF sa o prinda. E o eroare **tacuta**. 2. Ipoteza mea ca o `TaxableAmount` **negativa** ar fi respinsa e **infirmata** de validatorul local. 3. Ipoteza ca neconcordanta de moneda (`currencyID="RON"` pe factura in EUR) ar fi respinsa e tot **infirmata** de validatorul local. 4. **Rezerva**: validatorul instalat e din **ianuarie 2022** (`DUKIntegrator.jar`, 19.01.2022, reguli 1.0.8). Regulile ANAF s-au inasprit de atunci. Punctele 2 si 3 raman "neinfirmate de validatorul disponibil local", nu "garantat acceptate azi de ANAF". ### 4.4. Scenariul reproductibil al defectului REAL (fiscal) **Factura**: client intern, in lei, `discount_evidentiat = 0`. - Linia 1: marfa cota standard, 1 buc x 1000.00 lei, **21%** - Linia 2: marfa cota redusa, 1 buc x 1000.00 lei, **11%** - Discount de document: **10%** -> `VANZARI.DISCOUNT = 200.00` **Ce face programul**: - `Max(proc_tvav)` = 1.21 -> pseudo-linia de discount primeste **21%** (`oproceduri_facturare.prg:1387` / `ofacturare_comun.vc2:4495`) - `valdiscounttva = Round(200 * 0.21, 2) = 42.00` (`ofacturare_comun.prg:1893`) **Ce iese in XML** (verificat ca valid — `scenA`): ``` AllowanceCharge: Amount 200.00, TaxCategory S, Percent 21 TaxSubtotal S/21: TaxableAmount 800.00 TaxAmount 168.00 TaxSubtotal S/11: TaxableAmount 1000.00 TaxAmount 110.00 TaxAmount total 278.00 ; LineExtension 2000.00 ; TaxExclusive 1800.00 ; TaxInclusive 2078.00 ``` **Ce ar fi trebuit** (discount repartizat proportional cu baza: 100 lei pe fiecare cota): ``` AllowanceCharge #1: 100.00, S, 21 AllowanceCharge #2: 100.00, S, 11 TaxSubtotal S/21: 900.00 / 189.00 TaxSubtotal S/11: 900.00 / 99.00 TaxAmount total 288.00 ; TaxInclusive 2088.00 ``` **Diferenta: 10.00 lei TVA colectat in minus**, adica 5% din TVA-ul facturii — si creste cu ecartul dintre cote si cu marimea discountului. **Sensul e mereu acelasi**: cota maxima absoarbe tot discountul, deci TVA-ul declarat e **prea mic**. Riscul e al emitentului (TVA colectat subdeclarat), nu al ANAF-ului care respinge documentul. Aceeasi valoare gresita ajunge si in nota contabila si in jurnalul de TVA, pentru ca `valdiscounttva` e acelasi camp. **Caz-limita, tot valid dupa validator dar clar absurd** (`scenB`): factura cu 100 lei la 21% si 5000 lei scutit, discount de document 10% (510 lei). Tot discountul intra pe cota 21%, unde baza e 100 lei -> `TaxSubtotal S/21` iese cu `TaxableAmount = -410.00` si `TaxAmount = -86.10`. Factura declara **TVA negativ** pe o livrare normala. Nu e nevoie de cote diferite de zero pe ambele parti: ajunge o factura in care liniile de la cota maxima sunt o mica parte din total. ### 4.5. Gol de proiectare, distinct de defect **Explicatia ("reason") nu exista ca notiune in program.** In XML `AllowanceChargeReason` e literalul `"Discount"` si `ReasonCode` e `"95"`, ambele hardcodate (`xmlefactura.prg:774-776`). Textul construit in VFP — `"Discount 10.00 % Factura"` (`ofacturare_comun.prg:1370`) — **nu ajunge in XML**. Nu exista nicio coloana pe `VANZARI` pentru motivul discountului si niciun control in formular. Deci raspunsul la a doua jumatate a intrebarii lui Marius: **nu, discountul de document nu are azi explicatie — are o constanta.** --- ## 5. Recomandare pentru formularul unificat (#13) **Sa NU ceara utilizatorului cota. Sa sparga discountul automat, proportional cu baza fiecarei cote, si sa expuna doar un camp optional de motiv.** Argumentul e ca discountul de document nu *are* o cota proprie de ales: prin definitie e un procent aplicat bazei intregii facturi (`lnTotalBaza = Sum(valdiminuatftva)` peste toate liniile, `ofacturare_comun.prg:1888`), deci natura lui de TVA e determinata de liniile pe care le reduce, nu de o optiune. A pune operatorul sa aleaga o cota inseamna a-i cere sa ia o decizie fiscala pe care datele o dau deja, si a deschide o a doua cale de a gresi — azi `Max()` greseste consecvent, un camp liber ar greseste imprevizibil. Repartizarea proportionala e si singura care satisface modelul EN16931, unde `TaxableAmount`-ul fiecarei categorii se calculeaza ca *net de linii al categoriei minus alocarile de document ale aceleiasi categorii*. **Costul de implementare e mic, dar atinge doua locuri, nu unul** (sectiunea 1.5): `prelucreaza_facturacrs` (`ofacturare_comun.prg:1886-1897`) trebuie sa insereze cate un rand-sentinela **per cota** in loc de unul singur, cu `tnDiscount` repartizat pe baza fiecarei cote (ultima cota preia diferenta de rotunjire, ca suma sa fie exact `VANZARI.DISCOUNT`), **si** `recalculeaza_totaluri_vanzari` (`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16081-16092`) trebuie sa inlocuiasca `MAX(...)` cu suma repartizarii, altfel `VANZARI.TOTAL_TVA` ramane pe regula veche si diverge de XML; **eFactura nu are nevoie de nicio modificare structurala** — `xmlefactura.prg:758-792` grupeaza deja `GROUP BY proc_tva` si emite cate un `AllowanceCharge` per cota, iar `C_TVA_FACTURA` include deja pseudo-liniile in `TaxSubtotal`. Doua consecinte de decis explicit cu Marius: **factura tiparita** va arata N randuri "Discount X % Factura" in loc de unul (pe cote mixte), si **nota contabila** primeste TVA-ul discountului spart pe cote. Pentru "explicatie", recomand un singur camp text optional pe document, folosit ca `AllowanceChargeReason` in locul constantei `"Discount"` (`ReasonCode` ramane `95`) — util si pe hartie, si e singura bucata care chiar cere UI nou. **Precizare, dupa sectiunea 3.2**: "eFactura nu are nevoie de modificare" e adevarat doar daca fiecare pseudo-linie noua, per cota, primeste si `id_jtva_coloana` **al grupului pe care il reduce**, nu doar `proc_tva` al lui. Cota singura nu ajunge — cheia de grupare din `xmlefactura.prg:246` are cinci campuri, iar `expltva` se completeaza tot prin `id_jtva_coloana` (sectiunea 3.2). O implementare care seteaza doar `proc_tva` pe randul-sentinela ar lasa grupul orfan exact acolo unde e azi, pe facturile scutite / cu taxare inversa / intracomunitare. Fisierul `...2885...` de la sectiunea 4.1 e dovada pozitiva ca, atunci cand `id_jtva_coloana` e setat corect, forma iese unul singur si net — deci reparatia are deja un precedent real in productie, nu doar o constructie de test. --- ## Verificat direct vs. dedus **Verificat direct (citit in cod, cu `fisier:linie`)** - randul-sentinela `ZZZZ` si campurile lui — `ofacturare_comun.prg:1886-1897` - transformarea in pseudo-linia `"Discount % Factura"` — `ofacturare_comun.prg:1361-1392` - `Max(proc_tvav)` pe toate cele patru cai de apel — `oproceduri_facturare.prg:1387`, `ofacturare_comun.vc2:4495` si `:7294`, `ofacturare_stoc.prg:582` - a doua implementare a aceleiasi reguli, in PL/SQL, si campurile pe care le scrie — `ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16024` (procedura), `:16081-16092` (`MAX(...)`), `:16049-16062` (`TOTAL_TVA`/`TOTAL_CU_TVA` derivate din el), `:16214-16227` (`update vanzari`) - euristica de detectie in eFactura — `xmlefactura.prg:230` - generarea `AllowanceCharge` de document, cu `GROUP BY proc_tva` — `xmlefactura.prg:756-795` - sursa lui `TaxCategory/ID` (`GetTipTaxa`, `xmlefactura.prg:1103-1143`) si a lui `Percent` - includerea pseudo-liniei in `C_TVA_FACTURA` -> `TaxSubtotal` — `xmlefactura.prg:242-248, 822-851` - inchiderea totalurilor `LegalMonetaryTotal` — `xmlefactura.prg:863-898` - ca generatorul viu e `xmlefactura.prg`, nu `anaf_efactura` — `oexport.prg:1586-1594`, `ofacturare.prg:2107-2126` - ca ramura "pret cu TVA" (unde pseudo-linia iese cu `valftva = 0`) nu poate ajunge in eFactura — `ofacturare.prg:1112, 1856-1861` + filtrul `tip_doc_394` din `xmlefactura.prg:276-279` - semantica `LEFT JOIN` + `IIF`/`INLIST` peste `.NULL.` in cheia de grupare (sectiunea 3.1/3.2) — `xmlefactura.prg:226-248` - de ce grupul orfan nu poate fi completat prin `completeaza_explicatie_tva` — filtrul de scan vs. filtrul de update (`ofacturare_comun.prg:2094` vs. `:2108, 2129`, sectiunea 3.2) - sursa categoriei `Z` a grupului orfan, ramura cu ramura in `GetTipTaxa` — `xmlefactura.prg:1116-1140` (sectiunea 3.2) - incarcarea `cJTVAVanzariTemp` doar cu `id_jtva_coloana > 0`, motivul pentru care randul 0 nu se gaseste — `updateserver.prg:578` (sectiunea 3.2) **Verificat prin rulare** - 4 XML-uri reale de productie cu `AllowanceCharge` de document (sectiunea 4.1) - 3 facturi cu discount in baza de dev, 34 cu cote mixte (`SELECT`, sectiunea 4.2) - 5 validari DUKIntegrator offline pe cote mixte (sectiunea 4.3) — **au infirmat doua dintre ipotezele initiale** - semantica `IIF()` peste `.NULL.` masurata cu o sonda headless (`probe_null.prg`, sectiunea 3.1) — intoarce ramura falsa, nu `.NULL.` - 3 validari DUKIntegrator offline pe scenariul grupului orfan (`scutit_bug`, `scutit_corect`, plus `control_stricat` ca martor negativ, sectiunea 3.3) — grupul orfan **nu** e respins - identitatea SHA256 a XML-ului EUR de productie fata de fisierul chiar trimis la ANAF, si citirea celor doua zip-uri (`TRIMISE`/`ERORI`) care arata ca respingerea gasita e a unei incarcari anterioare, pentru alte reguli (sectiunea 4.1) **Dedus, NEverificat prin rulare** - calculul numeric din scenariul 4.4 (aritmetica pe formulele citite, nu o factura rulata efectiv prin program) - riscul `agettipcota(1)` fara garda pe `_Tally` (`xmlefactura.prg:782-786`) — n-am reusit sa-l provoc si nu-l afirm ca defect - ce se intampla in nota contabila / jurnalul de TVA cu `valdiscounttva` — am dedus din faptul ca e acelasi camp, n-am urmarit consumatorii - scenariul "factura scutita + discount de document" **end-to-end prin program** (sectiunea 3.2): gruparea separata e stabilita din cod + semantica `IIF`/NULL masurata, nu dintr-o factura reala rulata prin program — in baza de dev nu exista intersectia (sectiunea 4.2) - ordinea randurilor in `C_TVA_FACTURA` dupa `GROUP BY` (deci daca `agettipcota(1)` alege `E` sau `Z` in cazul grupului orfan) — nu e garantata de VFP si nu a fost fixata experimental **Neacoperit — si stiut ca neacoperit** - daca `VANZARI.TOTAL_TVA` (Oracle, sectiunea 1.5) si TVA-ul din XML sunt confruntate undeva si care primeaza — am constatat doar ca ambele exista si folosesc aceeasi regula - daca un discount de document **negativ** e posibil din UI (ar inversa `MAX`-ul din Oracle, 1.5) - calea in **valuta** (`crsfacturafinalaval` / `prelucreaza_factura_valuta`, `ofacturare_comun.prg:1540+`) — am presupus simetrie cu cea in lei pe baza campurilor `v*` paralele de la `:1894-1895`, n-am parcurs-o linie cu linie - daca `Max(proc_tvav)` e cota corecta si pentru **proforme** in vreun sens special - comportamentul validatorului ANAF **curent** (cel local e din 2022, atat pentru cote mixte cat si pentru grupul orfan) --- ## Intrebari ramase pentru Marius 1. **Repartizarea proportionala se aplica retroactiv la relistare?** O factura veche relistata sau retrimisa in eFactura ar genera alt XML decat cel trimis initial. Se accepta, sau noul comportament se leaga de o data / de un flag? 2. **Pe factura tiparita**: e in regula sa apara N randuri "Discount X % Factura" (unul pe cota), sau vrei un singur rand vizibil si spargerea doar in XML / nota contabila? 3. **Rotunjirea**: pe cine cade diferenta de rotunjire cand discountul nu se imparte exact (ex. 100 lei pe trei cote)? Propunerea mea: pe cota cu baza cea mai mare. 4. **Discountul care depaseste baza unei cote** (cazul din 4.4, factura majoritar scutita): dupa repartizarea proportionala problema dispare de la sine — confirmi ca nu mai e nevoie de nicio garda separata? 5. **Campul de motiv**: il vrei per document (un singur text), sau e suficient sa ramana constanta `"Discount"` si sa nu adaugam UI? 6. **`discount_evidentiat`**: mai e folosit in productie? Schimba semnificativ ce se tipareste (sectiunea 1.4) si e a doua sursa de pseudo-linii "Discount" in XML. 7. **Cele doua implementari ale regulii** (VFP + Oracle, sectiunea 1.5): se schimba amandoua in aceeasi livrare, sau Oracle ramane pe regula veche o vreme? Daca raman desincronizate, `VANZARI.TOTAL_TVA` si TVA-ul din eFactura vor diferi pe facturile cu cote mixte si discount. 8. **Discount de document negativ** (majorare): e posibil din UI? Daca da, `MAX`-ul din Oracle alege cota cea mai **mica**, iar `Max(proc_tvav)` din VFP tot pe cea mai mare — adica cele doua implementari ar diverge deja azi, inainte de orice modificare.