8.3 KiB
View-urile eFactura: ANAF_VEFACTURA_*
Cele sapte view-uri prin care ROA citeste facturile electronice descarcate/incarcate la ANAF, plus regula de potrivire cu registrul de TVA. Suna simplu si nu e: potrivirea are doua ramuri, cateva invariante de performanta si un istoric de fals-pozitive platite scump. Cine le atinge citeste intai aici.
Tabelele reale si view-urile peste ele
Tabelele sunt ANAF_EFACTURA (antetul, un rand per factura) si ANAF_EFACTURA_DETALII (liniile).
Coloana FACTURA_EMISA desparte cele doua lumi: 0 = achizitie (primita), 1 = vanzare
(trimisa). Restul sunt view-uri:
| View | Peste ce | La ce foloseste |
|---|---|---|
ANAF_VEFACTURA_PRIMIT |
ANAF_EFACTURA + JC2007 + NOM_PARTENERI |
achizitii, cu potrivirea in jurnalul de cumparari |
ANAF_VEFACTURA_TRIMIS |
ANAF_EFACTURA + JV2007 + NOM_PARTENERI |
vanzari, cu potrivirea in jurnalul de vanzari |
ANAF_VEFACTURA_EMIS |
+ VANZARI, VNOM_VALUTE |
facturile emise din ROA, legate de documentul intern |
ANAF_VEFACTURA_DETALII |
ANAF_EFACTURA_DETALII + NOM_ARTICOLE, NOM_GESTIUNI |
liniile, cu articolul si gestiunea ROA potrivite |
..._PRIMIT_DETALIU, ..._TRIMIS_DETALIU, ..._EMIS_DETALIU |
detaliile filtrate pe view-ul de antet respectiv | griduri de detaliu |
Unde se consuma: borderoul eFactura, COMUN\programe\import_efactura.prg,
PROCEDURE vizImportEFactura - alege anaf_vefactura_primit sau anaf_vefactura_trimis dupa
parametrul PRIMITE/TRIMISE (linia 27) si coloreaza randurile dupa diferenta fata de jurnal.
Detaliile se iau din anaf_vefactura_detalii (linia 60). Vizualizarea XML e in
COMUN\programe\anaf_efactura.prg, PROCEDURE viz_efactura_xml / viz_spv.
Pe ecran, jtotctva e coloana cJtotcTVA din COMUN\clase\anaf_efactura.vc2, prezenta pe toate
cele trei griduri ale formularului: pgfeFactura.Page1.grdFacturiEmise (anaf_efactura.vc2:1240),
Page2.grdFacturiPrimite (:2713) si Page3.grdFacturiTrimise (:4029).
Potrivirea cu registrul de TVA: jtotctva si jtva_ti
jtotctva = totalul cu TVA gasit in jurnal pentru factura respectiva. jtotctva IS NULL
inseamna "documentul nu e in registrul de TVA" - nu exista o coloana separata cu numarul de
potriviri, nulul e semnalul. jtva_ti (doar pe PRIMIT) e TVA-ul de taxare inversa, ca borderoul
sa nu coloreze fals facturile cu 4426=4427; pe TRIMIS e constanta 0.
Potrivirea are doua ramuri legate prin COALESCE, in ordinea asta:
- dupa numar - aceeasi zi, acelasi partener, iar
NRACTdin jurnal e unul din grupurile de cifre ale luiXNUMAR_ACT(sau concatenarea tuturor cifrelor). Ramura normala, acopera aproape tot. - rezerva pe valoare - aceeasi zi, acelasi partener, aceeasi suma cu TVA. Ruleaza numai pentru randurile unde prima a intors NULL.
Ce NU se atinge - fiecare regula e platita
COALESCE, nuNVLsi nuOR.COALESCEisi evalueaza argumentele lene, deci a doua ramura ruleaza doar unde prima n-a gasit nimic. Unite prinORin aceeasi subinterogare: peste 10 minute pe acelasi set de date, si potrivire nediferentiata a oricarui document cu aceeasi suma la acelasi partener in aceeasi zi (masurat pana la 49 de documente pentru o singura factura).- Forma predicatului pe numar. Grupurile de cifre se extrag din
XNUMAR_ACT(coloana din exterior) si se compara cuj.nractprinIN, caNRACTsa intre inaccess()peIDX_JC2007_003/IDX_JV2007_003. Scris invers, caREGEXP_LIKEpestej.nract, nu mai e sargabil: 97 de secunde in loc de 1,4 pe acelasi lot. avg, nusum, pe rezerva pe valoare. Doua facturi cu aceeasi valoare, acelasi partener, aceeasi zi potriveau fiecare ambele randuri din jurnal, iarsum()dadea valoare dubla.sum(NVL(j.totctva,0)), nusum(j.totctva), casum()sa fie NULL doar cand nu s-a potrivit niciun rand - altfeljtotctvasijtva_tipot alege ramuri diferite.HAVING-ul de anti-ghicire pe rezerva pe valoare. Se potriveste doar daca numarul de eFacturi din aceeasi zi, cu acelasi cod fiscal si aceeasi valoare, nu depaseste numarul de randuri de jurnal cu acea valoare. Mai multi pretendenti decat randuri = nu se ghiceste.having count(*) = 1e interzis: exista cazul real a doua facturi cu aceeasi valoare, acelasi partener, aceeasi zi, ambele in jurnal.ID_FACTnu e utilizabil la achizitii - se completeaza doar cand factura e inregistrata din wizardul de import (13 randuri din 970 pe schema de test).SERIE_ACTnu e cheie - exista inJC2007/JV2007, dar e populat ~3%.- Un document apare in
JC2007cu mai multe randuri (an/lunadiferite, reportarea neexigibilului), de aceea view-urile filtreazaj.an/j.lunadupaxdata_actsi ramura pe numar folosestesum(). - Fara obiecte noi si fara indecsi noi. S-au respins deja: view ajutator cu numerele
candidate,
not existsde anti-revendicare, ramura peID_FACT. - Scris compatibil Oracle 11g.
Codul fiscal: cand se cere egalitate si cand nu
Codul fiscal se normalizeaza pe ambele parti (REGEXP_REPLACE(upper(...), '[^[:digit:]]','')),
nu doar cel din NOM_PARTENERI.
La persoanele fizice care nu isi declara CNP-ul, XML-ul duce la ANAF CompanyID-ul cumparatorului
completat cu 13 de zero (0000000000000) - eticheta nu poate lipsi - in timp ce partenerul din
NOM_PARTENERI are COD_FISCAL NULL. Egalitatea stricta nu se poate implini niciodata, deci
toate facturile catre persoane fizice ieseau cu jtotctva NULL. La un client de vending: 20780
din 47369 de facturi emise.
De aceea, numai pe ramura pe numar din ANAF_VEFACTURA_TRIMIS, pe langa egalitate se accepta
si cazul in care ambele parti sunt "fara cod fiscal" (normalizat: NULL, gol sau numai zerouri).
Garda pe ambele parti e esentiala: o factura cu cod fiscal real nu poate prinde randul unui
partener fara cod fiscal, si invers.
Relaxarea nu costa indecsi: conditia de cod fiscal era si inainte un filtru dupa jonctiune, nu
un predicat de acces - are REGEXP_REPLACE peste ambele coloane, deci nu putea intra niciodata in
access(). EXPLAIN PLAN pe productie da acelasi plan hash (1870929383) si acelasi cost inainte
si dupa: NRACT ramane in access() pe indexul din JV2007, AN/LUNA raman filtru pe tabela,
iar OR-ul nou apare doar in filter() peste randurile deja aduse. Ce alege randurile e tot
numarul plus data.
Rezerva pe valoare ramane stricta, si ANAF_VEFACTURA_PRIMIT la fel:
- la un client cu vanzare catre persoane fizice, valorile identice in aceeasi zi sunt frecvente, iar la acelasi client 17034 din 24006 parteneri nu au cod fiscal - relaxata acolo, rezerva ar potrivi documente nediferentiat;
- la achizitii nu exista niciun
COD_FISCAL_EMITENTnul sau cu zerouri, furnizorii sunt persoane juridice.
Unde stau si cum se livreaza
View-urile se recreeaza integral din scripturile ff_*_COMUN_EFACTURA.sql din
D:\ROA\DATABASE\SCRIPTURI_CLAR\<an>\<luna>\. Fiecare script isi poarta motivatia in antet -
acolo sunt masuratorile si cazurile reale care au dus la forma actuala; se citeste inainte de orice
modificare si nu se rescrie fara motiv.
Ultimele: ff_2026_07_29_01_COMUN_EFACTURA.sql (potrivirea dupa numar, sargabila),
ff_2026_08_28_01_COMUN_EFACTURA.sql (HAVING-ul de anti-ghicire + cazul persoanelor fizice).
Rollback = se ruleaza pur si simplu scriptul anterior.
Sursa de referinta pentru DDL e schema MARIUSM_AUTO de pe ROA_CENTRAL, nu productia - vezi
scripturi-migrare-db.md. Publicarea la clienti: COMUN\utile\publicare_scripturi.ps1
(publicare-scripturi-db.md); fisierele trebuie CRLF si ASCII pur.
Changelog: nu. O modificare numai de baza de date, fara versiune noua de executabil, nu intra
in changelog_roacont.txt - changelog-ul insoteste livrarea unui .exe.
Cum se verifica o modificare inainte de livrare
Comparatie rand-cu-rand intre view-ul curent si expresia corectata, pe o schema de productie cu
volum real, numarand patru lucruri: reparate, pierdute, valoare schimbata, ramase
NULL. "Pierdute" si "valoare schimbata" trebuie sa fie zero - orice altceva inseamna ca
modificarea atinge si cazuri la care nu te asteptai. Sablonul de interogare e in
D:\ROA\ROACONT\docs\analiza_efactura_cnp_zerouri.md.
Conectarea la productie prin tunel: conexiuni-tunel-ssh-odbc.md. Pe productie doar SELECT.