sync SVN r18062

This commit is contained in:
2026-08-28 13:21:37 +03:00
parent ec49ad52d1
commit f4378bde96
3 changed files with 140 additions and 0 deletions

View File

@@ -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,

View File

@@ -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

134
docs/view-uri-efactura.md Normal file
View File

@@ -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\<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`**.