diff --git a/docs/README.md b/docs/README.md index 396dda9..5024000 100644 --- a/docs/README.md +++ b/docs/README.md @@ -42,6 +42,7 @@ atingi zona X, citeste fisierul Y"). Restul se deschid doar la declansator. | `flux-modificare-stergere-nota-jurnal.md` | modificare/stergere nota; ce face `PACK_CONTAFIN` | | `tipuri_documente_facturare.md` | `VANZARI.TIP` si seturile de contare `ID_SET` | | `sold-neexigibil-reportat-jc2007-jv2007.md` | interogari pe sold TVA neexigibil | +| `view-uri-efactura.md` | view-urile `ANAF_VEFACTURA_*` si potrivirea eFacturilor cu registrul de TVA | | `email-thunderbird.md` | citirea mailurilor de pe conturile romfast | `onboarding\` — proceduri rulate o singura data per proiect (inrolare in fluxul git-text, diff --git a/docs/conexiuni-tunel-ssh-odbc.md b/docs/conexiuni-tunel-ssh-odbc.md index 09641be..ea3b9c9 100644 --- a/docs/conexiuni-tunel-ssh-odbc.md +++ b/docs/conexiuni-tunel-ssh-odbc.md @@ -54,6 +54,11 @@ In `stnlc_out.txt` linia care conteaza e `Added client-to-server forwarding rule catre alt client, al doilea nu mai poate lega portul si vei interoga **alta baza** fara sa-ti dai seama. Verifica intotdeauna cu ce te-ai conectat (vezi pasul 4). +**Capcana inrudita**: interfata grafica `BvSsh.exe` poate tine portul 1521 legat pe `0.0.0.0` cu o +sesiune moarta - `sqlplus` raspunde atunci `ORA-12541: TNS:no listener`, desi "tunelul pare sus". +`stnlc` isi poate lega totusi propria regula pe `127.0.0.1:1521` peste ea si merge. Nu te lua dupa +`netstat`: proba reala e interogarea din pasul 4. + ## 2. Aliasul TNS `D:\ROA\instantclient_19_18\tnsnames.ora` (si `instantclient_11_2_0_2` pentru driverul ODBC pe diff --git a/docs/view-uri-efactura.md b/docs/view-uri-efactura.md new file mode 100644 index 0000000..5f76a26 --- /dev/null +++ b/docs/view-uri-efactura.md @@ -0,0 +1,134 @@ +# 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: + +1. **dupa numar** - aceeasi zi, acelasi partener, iar `NRACT` din jurnal e unul din grupurile de + cifre ale lui `XNUMAR_ACT` (sau concatenarea tuturor cifrelor). Ramura normala, acopera + aproape tot. +2. **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`, nu `NVL` si nu `OR`.** `COALESCE` isi evalueaza argumentele lene, deci a doua + ramura ruleaza doar unde prima n-a gasit nimic. Unite prin `OR` in 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 cu `j.nract` prin `IN`, ca `NRACT` sa intre in `access()` pe + `IDX_JC2007_003` / `IDX_JV2007_003`. Scris invers, ca `REGEXP_LIKE` peste `j.nract`, nu mai e + sargabil: 97 de secunde in loc de 1,4 pe acelasi lot. +- **`avg`, nu `sum`, pe rezerva pe valoare.** Doua facturi cu aceeasi valoare, acelasi partener, + aceeasi zi potriveau fiecare ambele randuri din jurnal, iar `sum()` dadea valoare dubla. +- **`sum(NVL(j.totctva,0))`, nu `sum(j.totctva)`**, ca `sum()` sa fie NULL doar cand nu s-a + potrivit niciun rand - altfel `jtotctva` si `jtva_ti` pot 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(*) = 1` e interzis**: exista cazul real a doua facturi cu aceeasi valoare, + acelasi partener, aceeasi zi, ambele in jurnal. +- **`ID_FACT` nu e utilizabil la achizitii** - se completeaza doar cand factura e inregistrata din + wizardul de import (13 randuri din 970 pe schema de test). +- **`SERIE_ACT` nu e cheie** - exista in `JC2007`/`JV2007`, dar e populat ~3%. +- Un document apare in `JC2007` cu mai multe randuri (`an`/`luna` diferite, reportarea + neexigibilului), de aceea view-urile filtreaza `j.an`/`j.luna` dupa `xdata_act` si ramura pe + numar foloseste `sum()`. +- **Fara obiecte noi si fara indecsi noi.** S-au respins deja: view ajutator cu numerele + candidate, `not exists` de anti-revendicare, ramura pe `ID_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_EMITENT` nul 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\\\`. 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`**.