14 KiB
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 = 1SIpretftvai > pretftva): uncac:AllowanceChargela nivel de linie cuAmount = valftvai-valftva,BaseAmount = valftvai,MultiplierFactorNumeric = proc_disc—xmlefactura.prg:952-971. - Optional (flag separat
gnEFACTURA_XML_DISC_PLISTA_ART = 1): uncac:AllowanceChargela nivel decac:Pricecu 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 totCOMUN\programesiCOMUN— nicio potrivire pe un generator de fisier D406/SAF-T XML.Glob '**/*saft*'pe tot proiectul si peCOMUN— 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_taxtablesisaft_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— cautareaDISCOUNTin 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
vdiscountftvae editabila direct in grid (ofacturare.vc2:12340-12345, faraReadOnly) dar fara niciun handlerValid/InteractiveChangecare sa recalculezevvaldiminuatftva/totalurile — confirmat cautat explicit indocs\cercetare\discount_verificare2.mdpunctul 3, ultimul paragraf ("editarea directa in grid NU declanseaza recalcularea automata avvaldiminuatftva/totaluri, doar modifica valoarea bruta incrsfactura"). - De ce conteaza pentru rapoarte/eFactura:
valdiminuatftva/valdiminuatctva(nudiscount_unitarbrut) sunt campurile citite deprelucreaza_factura/creeaza_crsfacttemppentruvalftvatiparit 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 cufrm_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_LINIEsignEFACTURA_XML_DISC_PLISTA_ART(unde sunt setate ca optiune de firma) — nu am cautat sursa lor, doar am confirmat ca cuTYPE(...) <> 'N'(nedefinite) comportamentul e "fara AllowanceCharge pe linie". - Nu am verificat pe date reale (Oracle/XML generat) un caz cu
discount_evidentiat=1siDISCOUNT_UNITARpopulat 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 cacrsfacturafinala/crsfacttemp(cursorul in lei), pe baza simetriei campurilorvpretftva/vvalftva/vdiscountftvagasite deja documentate indiscount_verificare2.mdsidiscount_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.