217 lines
14 KiB
Markdown
217 lines
14 KiB
Markdown
# Discount pe linie (DISCOUNT_UNITAR) in afara formularului de facturare — rapoarte .frx, eFactura, SAF-T
|
|
|
|
Cercetare read-only pentru S4c (plan_13). Nu s-a modificat niciun fisier, nu s-a rulat git_sync.
|
|
|
|
## Verdict (5-10 randuri)
|
|
|
|
Niciun raport tiparit de factura (`factura.fr2`, `facturatip*.fr2`, `factura_val*.fr2`,
|
|
`invoice*.fr2`, `proforma*.fr2`) nu afiseaza discountul pe linie ca coloana separata — nici ca
|
|
valoare, nici ca procent. Rapoartele tiparesc `pretftva` (pret unitar) si `valftva` (valoare linie)
|
|
care sunt **deja nete de discount** (calculate ca `pretftva-discountftva` / `Sum(valdiminuatftva)`
|
|
in cursorul intermediar `crsfacttemp`, construit de `prelucreaza_factura`/`creeaza_crsfacttemp` din
|
|
`ofacturare_comun.prg`). eFactura (`xmlefactura.prg`) foloseste **exact acelasi cursor** —
|
|
comentariul din cod chiar spune asta explicit — deci `LineExtensionAmount`/`PriceAmount` trimise la
|
|
ANAF sunt aceleasi valori nete, cu optiunea (dezactivata implicit, din flag-uri globale) de a
|
|
adauga si un `cac:AllowanceCharge` informativ pe linie. SAF-T (D406): **nu exista niciun generator
|
|
D406/SAF-T in ROAFACTURARE** — exista doar tabele de nomenclator cu prefix `saft_` (coduri TVA/plata)
|
|
folosite pe partea de achizitii, fara legatura cu `DISCOUNT_UNITAR`.
|
|
|
|
**Raspuns la intrebarea care conteaza**: daca discountul pe linie devine editabil direct in grid,
|
|
**nu se strica nimic in codul rapoartelor/eFacturii** — ele citesc oricum campurile finale
|
|
(`valdiminuatftva`/`discountftva`/`discount_unitar`) din cursor, indiferent cum au fost populate
|
|
(dialog separat vs. editare in grid). **Riscul real e in alta parte**: exista deja azi o cale prin
|
|
care discountul e editabil direct in grid (`vdiscountftva`, pe factura in valuta) care **nu
|
|
declanseaza recalcularea** lui `valdiminuatftva`/`valdiminuatctva` — vezi `docs\cercetare\discount_verificare2.md`
|
|
punctul 3, ultimul paragraf. Daca S4c extinde editarea in grid la toate coloanele de discount fara
|
|
sa cablaje si recalculul, rapoartele si eFactura vor tipari/trimite **valori vechi** (stale), pentru
|
|
ca ambele citesc `valdiminuatftva`, nu `discount_unitar` direct.
|
|
|
|
## 1. Rapoartele .frx/.fr2 tiparite
|
|
|
|
**Cautare**: `Grep 'DISCOUNT'` si apoi `Grep 'disc'` (case-insensitive) in toate `.fr2` din
|
|
`COMUN\Rapoarte` cu glob `*factur*.fr2`, `*proforma*.fr2`, `*invoice*.fr2` — **zero potriviri** in
|
|
toate cele (factura.fr2, facturatip.fr2, facturatip_a5.fr2, facturatip_cuchit.fr2, factura_a5.fr2,
|
|
factura_chit.fr2, factura_val.fr2, factura_val_a5.fr2, invoice.fr2, invoice_a5.fr2, proforma.fr2,
|
|
proforma_orig.fr2, proforma_val.fr2, proforma_val_orig.fr2). Singurele 2 fisiere `.fr2` din toata
|
|
`COMUN\Rapoarte` care contin "DISCOUNT" sunt `rap_nir_materiale.fr2` si `rap_nir_marfuri.fr2` —
|
|
rapoarte de NIR (receptie), nu facturi emise.
|
|
|
|
**Ce se tipareste per linie** (confirmat in `factura.fr2`):
|
|
```
|
|
1002: <expr><![CDATA[formateaza(cantitate,30,gnPCant)]]>
|
|
1014: <expr><![CDATA[formateaza(pretftva,14,gnPPretV)]]>
|
|
1026: <expr><![CDATA[formateaza(valftva,14,gnPc)]]>
|
|
1062: <expr><![CDATA[PADL(ALLTRIM(STR((proc_tva-1)*100)),2,[ ])+'%']]> -- procent TVA, nu discount
|
|
```
|
|
Deci: cantitate, pret unitar, valoare linie, procent TVA. Nici discount valoric, nici procent
|
|
discount.
|
|
|
|
**De unde vin `pretftva`/`valftva` — si de ce sunt deja nete**: cursorul de tiparire
|
|
(`crsfacttemp`) e construit de `Procedure prelucreaza_factura` (`COMUN\programe\ofacturare_comun.prg:1055-1059`),
|
|
apelata din `COMUN\programe\ofacturare.prg:1887`:
|
|
```
|
|
prelucreaza_factura([crsfactura], [crsfacturaset], [crsfacturafinala], poDate.discount_evidentiat, poDate.in_valuta, lnPretListAviz, poDate.nListareDetaliata)
|
|
```
|
|
In interior, `Do Case` pe `tnDiscountEvidentiat`/`lnPretListAviz` (`ofacturare_comun.prg:1156-1248`).
|
|
Cazul comun, `tnDiscountEvidentiat = 0` (checkbox-ul "Se pune in evidenta discount-ul..." NEBIFAT —
|
|
comportamentul implicit):
|
|
```
|
|
1182: Sum(cantitate) As cantitate,pretftva-discountftva As pretftva,;
|
|
...
|
|
1186: Sum(valdiminuatftva) As valftva,Sum(valdiminuattva) As valtva,;
|
|
```
|
|
adica pretul tiparit = pret brut minus discountul pe unitate, iar valoarea tiparita = suma
|
|
`valdiminuatftva` (deja calculata la adaugarea articolului ca `pretftva - discount_unitar`, cf.
|
|
`ofacturare.vc2:13126`, deja documentat in `discount_pe_articol.md` sectiunea 3). Simetric pentru
|
|
varianta cu TVA la `:1226-1230`.
|
|
|
|
**Cazul `tnDiscountEvidentiat = 1`** (checkbox bifat — discountul "se pune in evidenta"):
|
|
```
|
|
1165: pretftva,Nvl(codbare,... -- pretftva RAMANE brut, nu se scade discountftva
|
|
1166-1167: Sum(valftva) As valftvai,... Sum(valftva) As valftva,Sum(valtva) As valtva,
|
|
1168: discountftva,Sum(valdiscountftva) As valdiscountftva,Sum(valdiscounttva) As valdiscounttva,
|
|
```
|
|
Aici `pretftva`/`valftva` tiparite raman **brute** (neta de discount), iar `discountftva`/
|
|
`valdiscountftva`/`valdiscounttva` sunt calculate in cursor **dar nu sunt tiparite de niciun .frx**
|
|
(confirmat, zero hit pe "disc" in .fr2). Practic, cand discountul e "pus in evidenta", pretul si
|
|
valoarea linie tiparite pe factura NU reflecta discountul per linie — discountul apare doar ca linie
|
|
separata de document (randul-sentinela `denumire = Replicate('Z',20)`, populat din
|
|
`Thisform.nbazafdiscount`/`nbazafdiscountval` la `ofacturare.vc2:14534,14591,18532,18602` si
|
|
`ofacturare_comun.prg:1891`) — asta e insa discountul **de document** (`VANZARI.DISCOUNT`), nu
|
|
`DISCOUNT_UNITAR` pe linie. Nu am gasit nicio dovada ca acest mod (`discount_evidentiat=1`) ar fi
|
|
folosit uzual — e o optiune existenta, documentata deja in `discount_pe_articol.md` punctul 3 ca
|
|
schimband "doar mecanismul aritmetic", dar aici se vede consecinta suplimentara: **si ce se
|
|
tipareste**.
|
|
|
|
**Fara impartiri la pret zero pe randul de discount**: unde raportul calculeaza procent
|
|
(`proc_disc`), sursa e protejata explicit:
|
|
```
|
|
1184-1185 (ofacturare_comun.prg): Iif(cu_tva=0,Iif(pretftva<>0,Round(discountftva/pretftva*100,2),0),;
|
|
Iif(pretctva<>0,Round(discountctva/pretctva*100,2),0))
|
|
```
|
|
deci nu exista risc de impartire la zero — dar, ca observat mai sus, `proc_disc` nu e tiparit
|
|
nicaieri in .frx-urile de factura verificate (e calculat doar pentru consum intern/eFactura).
|
|
|
|
## 2. eFactura (ANAF/UBL) — `xmlefactura.prg`
|
|
|
|
**Concluzie**: eFactura foloseste **acelasi cursor de linii ca cel de la tiparire**, explicit
|
|
documentat in cod:
|
|
```
|
|
oexport.prg:1590: * tcCursorLiniiFactura = numele cursorului cu liniile facturii, asa cum arata la listare
|
|
```
|
|
Lantul: `ofacturare.prg:2126` -> `goExport.export2xml_efactura(poDate, m.lcCursoreFactura, ...)` cu
|
|
`lcCursoreFactura` = `lcCursorFacturaTemp` (= `'crsFacturaFinala'`, `ofacturare.prg:1892`, sau
|
|
`'crsfacturafinalaval'` pentru valuta) -> `xmlefactura.prg:231`:
|
|
```
|
|
Select a.*, ... From (m.tcCursorLiniiFactura) a Left Join cJTVAVanzariTemp b ... Into Cursor C_IES_FORM Readwrite
|
|
```
|
|
Deci `C_IES_FORM` (sursa liniilor XML) e construit direct din cursorul de tiparire — aceleasi
|
|
`pretftva`/`pretftvai`/`valftva`/`valftvai`/`proc_disc` descrise la punctul 1, cu aceeasi dependenta
|
|
de `poDate.discount_evidentiat`.
|
|
|
|
**Ce se trimite pe linie**:
|
|
- `cbc:LineExtensionAmount` (BT-131) = `C_IES_FORM.valftva` — `xmlefactura.prg:935-937`.
|
|
- `cbc:PriceAmount` = `C_IES_FORM.pretftva` — `xmlefactura.prg:1043-1046`.
|
|
- Optional (doar daca flag global `gnEFACTURA_XML_DISC_PLISTA_LINIE = 1` SI `pretftvai > pretftva`):
|
|
un `cac:AllowanceCharge` la nivel de linie cu `Amount = valftvai-valftva`,
|
|
`BaseAmount = valftvai`, `MultiplierFactorNumeric = proc_disc` — `xmlefactura.prg:952-971`.
|
|
- Optional (flag separat `gnEFACTURA_XML_DISC_PLISTA_ART = 1`): un `cac:AllowanceCharge` la nivel de
|
|
`cac:Price` cu discountul unitar (`ABS(pretftvai-pretftva)`) — `xmlefactura.prg:1054-1067`.
|
|
|
|
Ambele flag-uri sunt verificate cu `TYPE(...) = 'N' AND ... = 1` — daca variabila globala nu exista
|
|
sau e 0 (implicit), **nu se trimite niciun `AllowanceCharge` pe linie**; discountul e vizibil pentru
|
|
ANAF doar implicit, prin faptul ca `PriceAmount * InvoicedQuantity = LineExtensionAmount` (adica
|
|
pretul e deja net). Nu am gasit unde sunt setate global aceste doua variabile (`gnEFACTURA_XML_DISC_PLISTA_LINIE`/`_ART`) —
|
|
posibil optiuni de firma necautate in acest fisier; nu afecteaza concluzia principala.
|
|
|
|
**Discount de document, separat**: exista o eticheta euristica in `C_IES_FORM`
|
|
(`Iif('DISCOUNT' $ Upper(a.denumire) And a.pretftva < 0, 1, 0) As discount`, `xmlefactura.prg:230`)
|
|
care detecteaza randuri-pseudo-articol de discount/taxa (denumire contine "DISCOUNT", pret negativ)
|
|
si le exclude din liniile normale (`Scan For discount = 0`, `:901`), agregandu-le separat intr-un
|
|
`cac:AllowanceCharge` la nivel de document (`:756-793`, motiv "Discount", cod 95). Acesta e
|
|
discountul de document, nu `DISCOUNT_UNITAR` pe linie — mecanism diferit de randul-sentinela
|
|
`Replicate('Z',20)` folosit la tiparire (punctul 1).
|
|
|
|
**Nicio validare care ar respinge discount > pret**: n-am gasit nicio verificare explicita in
|
|
`xmlefactura.prg` care sa blocheze o linie cu `discount_unitar` mai mare ca pretul (ar rezulta
|
|
`pretftva` negativ pe linie individuala; codul are doar o corectie generala pentru
|
|
`pretftva < 0` la nivel de linie completa, `xmlefactura.prg:236-239`, care inverseaza semnul
|
|
cantitate/pret — nu specifica pentru discount).
|
|
|
|
## 3. SAF-T (D406)
|
|
|
|
**Concluzie: nu exista implementare SAF-T/D406 in ROAFACTURARE.** Cautat explicit:
|
|
- `Grep 'SAF-T|SAFT|D406|declaratie406|GenereazaSAFT|GenereazaD406'` in tot `COMUN\programe` si
|
|
`COMUN` — nicio potrivire pe un generator de fisier D406/SAF-T XML.
|
|
- `Glob '**/*saft*'` pe tot proiectul si pe `COMUN` — zero fisiere cu "saft" in nume.
|
|
- Singurele aparitii reale (nu fals-pozitive de tip "safe") sunt:
|
|
- `oinit_optiuni.prg:523-524`: `gl406 = (TYPE('gnD406') = 'N' and m.gnD406 = 1)` — un flag "firma
|
|
are activata SAFT 406", comentat "Firma are activata SAFT 406".
|
|
- `oproceduri_comune.prg:889-896,6083,6151`, `ointroduceri.prg:1597`: `saft_taxtable` si
|
|
`saft_mecanisme_plati` — tabele de nomenclator (coduri de TVA/mecanism de plata compatibile
|
|
SAF-T) folosite pe **partea de achizitii** (limitare deducere TVA la introducerea facturilor de
|
|
achizitie), nu pe vanzari/facturare.
|
|
- `oproceduri_comune.prg:6066-6067,6137-6138,6195`: comentarii care mentioneaza "Taxa SAFT tip"
|
|
ca denumire pentru codurile de TVA, tot pe achizitii.
|
|
- Niciuna din aceste aparitii nu are legatura cu `DISCOUNT`/`DISCOUNT_UNITAR` — cautarea `DISCOUNT`
|
|
in fisierele care contin "saft" (`oproceduri_comune.prg`, `ointroduceri.prg`, `pmenu.prg`,
|
|
`oinit_optiuni.prg`) nu a gasit nicio intersectie intre cele doua seturi de rezultate.
|
|
|
|
**Interpretare**: `gl406` pare sa activeze doar validari/coduri suplimentare pentru conformitate
|
|
SAF-T pe partea de achizitii (poate pentru ca alt produs din suita, ROACONT, genereaza efectiv
|
|
D406 din datele contabile) — ROAFACTURARE nu produce singur un fisier D406.
|
|
|
|
## 4. Alte consumatori care ar presupune discount uniform pe document
|
|
|
|
Nu am gasit vreun raport/export care sa presupuna un discount unic pe tot documentul in sensul de
|
|
"aceeasi valoare/procent pe toate liniile" — mecanismul de discount de document
|
|
(`VANZARI.DISCOUNT`, randul `Replicate('Z',20)`) e tratat ca **valoare agregata separata**, adaugata
|
|
ca linie proprie (in tiparire) sau ca `AllowanceCharge` de document (in eFactura), nu redistribuita
|
|
implicit pe liniile existente — cu o exceptie: `xmlefactura.prg` are logica de **distribuire**
|
|
explicita a discountului/taxelor de document pe articole cand bifa `chkDistribuieDiscount`/
|
|
`llDistribuieDiscountTaxe` e activa (`xmlefactura.prg:12189-12320`, `:12534-12790`) — asta insa
|
|
opereaza pe discountul de document, nu presupune ca discountul de linie (`DISCOUNT_UNITAR`) e
|
|
uniform; dimpotriva, distribuie proportional cu valoarea fiecarei linii, deci suporta discount
|
|
diferit per linie din start.
|
|
|
|
## Ce ar strica S4c, concret
|
|
|
|
**Nu se strica codul rapoartelor sau al eFacturii** — ambele citesc valori finale din cursor
|
|
(`valdiminuatftva`, `discountftva`, `pretftva` deja net), indiferent de sursa UI a discountului.
|
|
|
|
**Se poate strica invariantul pe care se bazeaza**, daca editarea in grid nu recalculeaza:
|
|
- **Dovada ca gaura exista deja azi**: pe factura in valuta, coloana `vdiscountftva` e editabila
|
|
direct in grid (`ofacturare.vc2:12340-12345`, fara `ReadOnly`) dar **fara niciun handler
|
|
`Valid`/`InteractiveChange`** care sa recalculeze `vvaldiminuatftva`/totalurile — confirmat cautat
|
|
explicit in `docs\cercetare\discount_verificare2.md` punctul 3, ultimul paragraf ("editarea directa
|
|
in grid NU declanseaza recalcularea automata a `vvaldiminuatftva`/totaluri, doar modifica valoarea
|
|
bruta in `crsfactura`").
|
|
- **De ce conteaza pentru rapoarte/eFactura**: `valdiminuatftva`/`valdiminuatctva` (nu
|
|
`discount_unitar` brut) sunt campurile citite de `prelucreaza_factura`/`creeaza_crsfacttemp`
|
|
pentru `valftva` tiparit si trimis la ANAF (punctele 1 si 2 de mai sus). Daca operatorul modifica
|
|
discountul direct in grid si acel camp nu se recalculeaza, factura tiparita si XML-ul ANAF vor
|
|
arata **valoarea veche** (dinainte de editare) — o discrepanta reala intre ce vede operatorul in
|
|
grid si ce se tipareste/trimite.
|
|
- **Concluzie pentru plan**: daca S4c extinde editarea de discount la toate coloanele din grid
|
|
(inclusiv `discountctva`, azi read-only pe lei), trebuie cablat un recalcul echivalent cu
|
|
`frm_articol_factura.do_calculeaza_discount` (`ofacturare.vc2:1874-1976`) pe evenimentul de editare
|
|
din grid — altfel riscul de mai sus (deja prezent azi doar pe valuta) se extinde la toate
|
|
facturile in lei.
|
|
|
|
## Ramas de verificat
|
|
|
|
- Valorile implicite ale flag-urilor globale `gnEFACTURA_XML_DISC_PLISTA_LINIE` si
|
|
`gnEFACTURA_XML_DISC_PLISTA_ART` (unde sunt setate ca optiune de firma) — nu am cautat sursa lor,
|
|
doar am confirmat ca cu `TYPE(...) <> 'N'` (nedefinite) comportamentul e "fara AllowanceCharge pe
|
|
linie".
|
|
- Nu am verificat pe date reale (Oracle/XML generat) un caz cu `discount_evidentiat=1` si
|
|
`DISCOUNT_UNITAR` populat simultan, ca sa confirm empiric (nu doar din citirea codului) ca factura
|
|
tiparita arata pretul brut.
|
|
- Nu am urmarit `crsfacturafinalaval` (varianta valuta a cursorului final) linie cu linie — am
|
|
presupus ca urmeaza acelasi patron ca `crsfacturafinala`/`crsfacttemp` (cursorul in lei), pe baza
|
|
simetriei campurilor `vpretftva`/`vvalftva`/`vdiscountftva` gasite deja documentate in
|
|
`discount_verificare2.md` si `discount_pe_articol.md`; n-am reverificat separat sursa SQL pentru
|
|
varianta valuta.
|
|
- Nu am identificat un al doilea produs (ROACONT?) care sa genereze efectiv D406 din datele scrise
|
|
de ROAFACTURARE — presupunerea din sectiunea 3 e speculativa, nu confirmata cu cod.
|