Transa 1 ANAF TVA: changelog 2.11.67, plan corectat pe date, handoff-uri de verificare
Plan corectat in patru puncte confirmate pe Oracle: - lista de coloane de taxare inversa are 13 termeni, nu 10 (TI19T/TI09T nu exista pe jc2007; expresia din oproceduri_decont.prg:8670 e scrisa peste view-ul VJC2025, cu aliasuri calculate) - tva_incasare nu exista pe jc2007/jv2007; interogarea transei 3 merge pe VJC2025/VJV2025 - kill-switch-ul nu se face in Optiuni_FIRMA/PROGRAM.dbf, ci pe modelul RC_ANAF_VERIF_SELECTIE (INI + optiuni Oracle + intrare de meniu) - oExecute deschide dialog de reconectare cu QUIT pe conexiune cazuta; apelul din transa 3 trebuie sa dezactiveze explicit reconectarea SVN r17910/r17911. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DhJwsrFFe1ZNAAtS8Twuti
This commit is contained in:
87
docs/handoff_transa1.md
Normal file
87
docs/handoff_transa1.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# Handoff Transa 1 (L1 + L2) — ocautare.prg + validare.prg
|
||||
|
||||
Data: 27.07.2026. Patch: `docs/diff_runda1_transa1.patch`. Backup-uri: `*.pre_runda1.bak`
|
||||
in `COMUN/programe/`. Fara comit (git/svn), fara `git add`.
|
||||
|
||||
## L1 — perioada TVA
|
||||
|
||||
- `validare.prg` header (dupa ultima intrare 27.07.2026): intrare noua cumulativa.
|
||||
- `validare.prg:1663 ANAF_VerdictDinCursor`: 4 proprietati noi pe `loResult`
|
||||
(`dInceputScpTVA`, `dSfarsitScpTVA`, `dAnulareScpTVA`, `cMesajScpTVA`), citite din
|
||||
cursor INAINTE de `Use In` — linii neschimbate fata de plan (1657→1663 dupa insertia
|
||||
headerului, offset normal).
|
||||
- `validare.prg` `ParseJsonANAFv8` (~2074-2086): log explicit (nu in CATCH) pentru fiecare
|
||||
din cele 3 campuri de data, cand sirul sursa e nevid dar `CTOD` a intors gol.
|
||||
- `ocautare.prg` header: intrare noua cumulativa (L1; L2 nu are comentariu, e corectie).
|
||||
- `ocautare.prg:145-153 ANAF_StarePartener`: propaga cele 4 proprietati in `loOut`, citire
|
||||
garda cu `Pemstatus(loRezANAF, '<prop>', 5)`; daca lipsesc (validare.prg vechi la alte
|
||||
produse ROA), `loOut` primeste oricum proprietatea cu valoare goala — asa TextAnaf/Detalii
|
||||
n-au nevoie de Pemstatus la randul lor.
|
||||
- `TextStare` (nou parametru `tcPerioada`) + `SufixPerioadaTVA` (functie noua) + `TextAnaf`
|
||||
(foloseste cele doua) — implementeaza tabelul de conditii si formele exacte din plan
|
||||
(precedenta pe `dAnulareScpTVA`, apoi range daca ambele date, apoi `din data`; sufixul
|
||||
`' la data documentului'` dispare cand perioada apare).
|
||||
- `TextPerioadaTVA` (functie noua) + `Detalii`: bloc cu perioada completa (etichete distincte)
|
||||
+ mesajul ANAF integral, inserat dupa `AntetDialog(...)` in AMBELE ramuri unde `oStare`
|
||||
nu e null (cazul concordant si cel discordant/lista de candidati) — deci apare si in cazul
|
||||
concordant, cum cere planul.
|
||||
|
||||
## L2 — CNP la 13 cifre
|
||||
|
||||
- `EvalueazaRand:600(vechi)`: `This.cClasaEsec = ''` → `'COD_INVALID'` (fara comentariu).
|
||||
- `ANAF_StarePartener`: parametru nou `tnTipPersoana` (adaugat la finalul listei, ca sa nu
|
||||
mut pozitiile parametrilor `@`); conditia de la `:82` devine
|
||||
`Len(m.lcCui) = 13 And !(Vartype(m.tnTipPersoana) = 'N' And m.tnTipPersoana = 1)`, seteaza
|
||||
`tcClasaEsec = 'CNP'` inainte de `Return .Null.`. Singurul apel din tot codul e in
|
||||
`EvalueazaRand` (verificat cu grep in D:\ROA\ROACONT) — actualizat sa paseze
|
||||
`m.lnTipPersoana` (deja calculat la linia anterioara, nimic nou de calculat).
|
||||
**Corectie runda 2** (semnalata de team-lead la review): forma initiala
|
||||
`m.tnTipPersoana <> 1` compara direct cu 1, ceea ce arunca eroare VFP 107
|
||||
("Operator/operand type mismatch") daca `ANAF_StarePartener` e chemata cu vechea
|
||||
semnatura de 6 parametri (`tnTipPersoana` nepasat = `.F.` logic, `.F. <> 1` = mismatch
|
||||
tip) — risc real, pentru ca fisierul e cod partajat COMUN si alte produse ROA il pot
|
||||
chema fara noul parametru. Forma cu `Vartype(...) = 'N' And ... = 1` e sigura indiferent
|
||||
daca parametrul e pasat sau nu si pastreaza compatibilitatea inapoi (apelant vechi -> se
|
||||
comporta ca azi, sare ANAF pe 13 cifre).
|
||||
- `EvalueazaRand`: ramura noua `Case Isnull(m.loStare) And m.lcClasaEsec == 'CNP'` inaintea
|
||||
lui `Case Isnull(m.loStare)`, banda neutra `'Persoana fizica - CNP corect'`.
|
||||
- `Detalii`, Iif imbricat: doua ramuri noi, `CNP` si `COD_INVALID`, exact textul din plan.
|
||||
- Ramurile marcate INACCESIBILE in plan (CNP invalid sub clasa noua, CUI valid/invalid sub
|
||||
FARA_RASPUNS) NU au fost implementate, cum cere planul.
|
||||
|
||||
## Verificari facute
|
||||
|
||||
- cp1252: toate editarile au fost facute INTAI, verificare byte-level DUPA. `ocautare.prg`
|
||||
a avut 3 linii corupte (`0xBA` → `EF BF BD`) dupa editari (caracterul `ș` din
|
||||
"mașina"/"și"/"tranșa", niciuna dintre ele atinsa intentionat) — reparate cu
|
||||
`s/\xEF\xBF\xBD/\xBA/g` (sigur, pentru ca toate cele 3 corupte erau confirmat `0xBA` in
|
||||
backup si in `svn cat`, verificat byte-cu-byte cu `xxd`+`md5sum`, nu doar vizual — atentie,
|
||||
terminalul afiseaza `0xBA` si `EF BF BD` identic vizual, verificarea trebuie facuta pe
|
||||
octeti, nu pe ce se vede). Dupa reparare: 0 aparitii `EF BF BD` in ambele fisiere, numar de
|
||||
linii cu octeti >=0x80 identic intre fisierul curent si `svn cat` (3 in ocautare.prg, 0 in
|
||||
validare.prg), continut confirmat identic prin md5sum pe liniile respective.
|
||||
- Comentarii: doar in antet, cate o intrare cumulativa per fisier (L1); L2 fara comentariu.
|
||||
- Patch (`docs/diff_runda1_transa1.patch`) recitit — contine doar modificarile de mai sus,
|
||||
fara cele 3 linii cu diacritice (au disparut din diff dupa reparare, semn ca sunt
|
||||
byte-identice cu baseline-ul).
|
||||
|
||||
## Ce n-am putut verifica
|
||||
|
||||
- Nu am rulat headless VFP (`vfp9.exe -A -T`) pe aceste functii — modificarile ating clase
|
||||
UI (`anaf_verif_cautare`, mesaje `Amessagebox`) greu de testat fara IDE/formular; recomand
|
||||
testare manuala in VFP conform planului de test insotitor.
|
||||
- N-am gasit alti apelanti ai `ANAF_StarePartener` in afara de `ocautare.prg` insusi (grep pe
|
||||
tot `D:\ROA\ROACONT`), deci parametrul nou `tnTipPersoana` nu are alti calleri de actualizat
|
||||
— dar n-am verificat si in `D:\ROA\COMUNROA` sau alte produse ROA in afara acestui working
|
||||
copy.
|
||||
|
||||
## Capcane intalnite
|
||||
|
||||
- Editarea cu Edit tool a corupt caractere cp1252 in TOT fisierul `ocautare.prg` la fiecare
|
||||
scriere, exact cum avertizeaza `conventie_encoding_cp1252.md` — dar comparatia vizuala in
|
||||
terminal ("liniile arata la fel") a fost INSELATOARE: `0xBA` si `EF BF BD` (3 octeti) se
|
||||
afiseaza identic ca `<60>` in terminal. Un prim test cu `perl -ne 'print "$." if /[\x80-\xFF]/'`
|
||||
a raportat "acelasi numar de linii, acelasi continut vizual" si a fost gresit interpretat ca
|
||||
"nicio corupere" — abia comparatia cu `xxd`+`md5sum` a scos la iveala diferenta reala.
|
||||
Concluzie pentru viitor: verificarea corecta e strict pe secventa de octeti `EF BF BD`
|
||||
(`perl -ne 'print "$." if /\xEF\xBF\xBD/'`), nu pe prezenta oricarui octet >=0x80.
|
||||
189
docs/handoff_transa2_conditii.md
Normal file
189
docs/handoff_transa2_conditii.md
Normal file
@@ -0,0 +1,189 @@
|
||||
# TRANSA 2 (L4) — inchidere conditii de intrare — verificare Oracle
|
||||
|
||||
Data: 27.07.2026. Conexiune: `MARIUSM_AUTO@ROA_CENTRAL` (schema dev), read-only, doar SELECT.
|
||||
Fisiere sursa salvate: `docs/local/view_anaf_vefactura_primit.sql`, `docs/local/view_anaf_vefactura_trimis.sql`.
|
||||
|
||||
## VERDICT GENERAL
|
||||
|
||||
- **A — INCHISA.** Definitiile curente extrase din `USER_VIEWS.TEXT`.
|
||||
- **B — INCHISA PARTIAL.** Mecanismul e confirmat pe date, dar NU dintr-o factura venita real din import eFactura (nu exista in schema dev). Demonstrat pe cel mai apropiat caz din `jc2007`.
|
||||
- **C — INCHISA, cu recomandare concreta.** Forma subselectului unic e mai jos.
|
||||
- **D — INCHISA.** Sonda recomandata: `user_tab_columns`.
|
||||
|
||||
**CONTRAZICE PLANUL (cel mai important gasit):** lista canonica de 10 coloane din plan
|
||||
(`TI21T, TI11T, TI19T, TI09T, TI24T, TI20T, XX21TIT, XX11TIT, XX19TIT, XX9TIT`) **nu compileaza
|
||||
direct pe `JC2007`**. `TI19T` si `TI09T` NU exista ca si coloane pe tabela — vezi B mai jos.
|
||||
|
||||
---
|
||||
|
||||
## A. Definitiile curente ale view-urilor
|
||||
|
||||
Extrase din `USER_VIEWS.TEXT` (nu din arhiva CLAR), salvate integral in:
|
||||
- `docs/local/view_anaf_vefactura_primit.sql`
|
||||
- `docs/local/view_anaf_vefactura_trimis.sql`
|
||||
|
||||
Confirmari:
|
||||
- `anaf_vefactura_primit.jtotctva` = subselect corelat pe `jc2007 j` + `left join nom_parteneri p`,
|
||||
cheie de potrivire an/luna/dataact + `REGEXP_SUBSTR(a.xnumar_act, '\d+[^[:digit:]]*$') LIKE '%'||TO_CHAR(j.nract)||'%'`
|
||||
+ `REGEXP_REPLACE(p.cod_fiscal,'[^[:digit:]]','') = a.cod_fiscal_emitent`. Exact cum descrie planul.
|
||||
- `anaf_vefactura_trimis.jtotctva` = acelasi tipar dar pe **`jv2007`** (nu `jc2007`), cheie pe
|
||||
`cod_fiscal_beneficiar`, filtru `a.factura_emisa = 1`. Confirma ca planul are dreptate sa puna
|
||||
`jtva_ti = 0` constant la trimis: la vanzari nu exista familia `TI*`/`XX*TIT` (verificat — acele
|
||||
coloane sunt specifice achizitiilor, nu apar in `jv2007`, nu a fost nevoie sa fie recalculate).
|
||||
|
||||
**Views DETALIU** — exista amandoua, construite peste view-urile de baza prin `id_efactura`/`id`:
|
||||
- `ANAF_VEFACTURA_PRIMIT_DETALIU` (VALID) — `SELECT f.* (coloane specifice), d.* FROM anaf_vefactura_primit f JOIN anaf_efactura_detalii d ON f.id = d.id_efactura`.
|
||||
- `ANAF_VEFACTURA_TRIMIS_DETALIU` (VALID) — identic, pe `anaf_vefactura_trimis`.
|
||||
- Bonus gasit: exista si `ANAF_VEFACTURA_EMIS_DETALIU`, dar e **INVALID** azi (preexistent, nelegat
|
||||
de L4 — de semnalat, nu de reparat aici).
|
||||
|
||||
Important pentru scriptul de migrare: niciuna din cele doua DETALIU nu selecteaza `jtotctva` sau
|
||||
orice coloana noua din view-ul de baza (`f.*` explicit enumerat, fara `jtotctva`/`jtva_ti`) — deci
|
||||
adaugarea `jtva_ti` in view-urile de baza **nu le afecteaza structural**, doar le invalideaza
|
||||
temporar (dependinta VFP) pana la recompilare automata pe urmatoarea referire. Se pastreaza
|
||||
verificarea de obiecte invalide ceruta de plan la finalul scriptului.
|
||||
|
||||
---
|
||||
|
||||
## B. Trasare cap-coada — CONTRAZICE PLANUL pe lista de coloane
|
||||
|
||||
### Ce s-a confirmat
|
||||
|
||||
- `ProcentTva2IdJtva` (gasita real in `COMUN\programe\oproceduri_comune.prg:5836`, NU in
|
||||
`anaf_efactura.vc2` cum spune planul — functia e apelata acolo la `:12093`/`:12636`, dar
|
||||
**definita** in `oproceduri_comune.prg`) confirma exact id-urile din plan pentru taxare inversa
|
||||
pe JC: 21%->216, 11%->218, 19%->141, 9%->145 (`:5864-5871`).
|
||||
- `oproceduri_decont.prg:8670` (citat corect de plan) e o expresie SQL, dar **din view-ul
|
||||
`VJC2025`**, nu direct pe `jc2007`. Am extras `USER_VIEWS.TEXT` pentru `VJC2025`: acolo
|
||||
`ti19t` si `ti09t` sunt ALIASURI calculate — `SUM(a.ti19bct + a.ti19bvt + a.ti19bft) as ti19t`,
|
||||
`SUM(a.ti09bvt + a.ti09bft) as ti09t` — NU coloane fizice.
|
||||
|
||||
### Verificare directa pe `JC2007` (`USER_TAB_COLUMNS`)
|
||||
|
||||
Din cele 10 coloane canonice din plan, gasite pe tabela **8/10**:
|
||||
|
||||
| Coloana plan | Exista pe JC2007? |
|
||||
|---|---|
|
||||
| TI21T, TI11T, TI24T, TI20T | DA (coloane simple) |
|
||||
| XX21TIT, XX11TIT, XX19TIT, XX9TIT | DA (coloane simple) |
|
||||
| **TI19T** | **NU** — pe tabela exista in schimb `TI19BCT`, `TI19BVT`, `TI19BFT` (3 subcoloane) |
|
||||
| **TI09T** | **NU** — pe tabela exista in schimb `TI09BVT`, `TI09BFT` (2 subcoloane, fara varianta `BC`) |
|
||||
|
||||
Un `create or replace view` care scrie `nvl(j.TI19T,0)+nvl(j.TI09T,0)` direct pe `jc2007 j` **nu
|
||||
compileaza** — `ORA-00904`. Lista corecta de termeni pentru `jc2007` (13 termeni, nu 10):
|
||||
|
||||
```
|
||||
NVL(j.TI21T,0)+NVL(j.TI11T,0)+NVL(j.TI24T,0)+NVL(j.TI20T,0)
|
||||
+ NVL(j.TI19BCT,0)+NVL(j.TI19BVT,0)+NVL(j.TI19BFT,0)
|
||||
+ NVL(j.TI09BVT,0)+NVL(j.TI09BFT,0)
|
||||
+ NVL(j.XX21TIT,0)+NVL(j.XX11TIT,0)+NVL(j.XX19TIT,0)+NVL(j.XX9TIT,0)
|
||||
```
|
||||
|
||||
### Factura reala cu taxare inversa — NU exista una venita din import eFactura in schema dev
|
||||
|
||||
- `anaf_efactura` (schema `MARIUSM_AUTO`): 487 randuri primite, doar **8** au `id_fact` completat
|
||||
(legatura catre `jc2007`/`act`). Niciunul dintre acele 8 `id_fact` se suprapune cu vreun rand din
|
||||
`jc2007` care are coloane `TI*`/`XX*TIT` nenule (31 randuri in toata schema, toate din test/demo,
|
||||
ani 2007-2022, fara `id_fact` legat de `anaf_efactura`). Interogarea de join explicit
|
||||
(`jc2007 j JOIN anaf_efactura a ON a.id_fact = j.id_fact WHERE a.factura_emisa=0 AND <TI nenul>`)
|
||||
a intors **0 randuri**.
|
||||
- Cele 6 randuri din `anaf_vefactura_primit` cu `id_fact` legat au `total_cu_tva = jtotctva`
|
||||
(diferenta 0) — niciuna dintre ele nu e taxare inversa, deci nu demonstreaza mecanismul.
|
||||
|
||||
**Cel mai apropiat caz gasit** (nu vine din eFactura, e din `jc2007` direct — demonstreaza doar
|
||||
aritmetica pe care view-ul o va aplica):
|
||||
|
||||
```
|
||||
an=2022 luna=4 dataact=30-APR-22 nract=222 id_part=614 id_fact=8007136
|
||||
ti19bft=19 totctva=119
|
||||
```
|
||||
|
||||
Daca acest rand ar fi venit dintr-un import eFactura cu linie `AE` (TVA XML = 0), XML-ul ar fi
|
||||
avut `total_cu_tva = 100` (119 - 19 taxare inversa), in timp ce `jtotctva` (= `SUM(totctva)`) tot
|
||||
ar da `119`. Cu view-ul curent: `diferenta = total_cu_tva - jtotctva = 100 - 119 = -19` (fals
|
||||
pozitiv, exact cat e TVA de taxare inversa). Cu `jtva_ti` adaugat: `diferenta = total_cu_tva -
|
||||
(jtotctva - jtva_ti) = 100 - (119 - 19) = 0`. Mecanismul se confirma numeric, dar **pe un caz
|
||||
sintetic, nu pe o factura reala din import eFactura** — schema dev nu are asa ceva. De consemnat
|
||||
in nota de release: verificare finala pe date reale ramane de facut la prima factura de taxare
|
||||
inversa importata dupa aplicarea scriptului (sau pe schema de productie/testare cu date reale,
|
||||
daca exista acces).
|
||||
|
||||
---
|
||||
|
||||
## C. Verdict performanta — forma subselectului unic
|
||||
|
||||
Confirmat: `jtotctva` e deja un subselect scalar corelat cu `REGEXP_SUBSTR`/`REGEXP_REPLACE` in
|
||||
`WHERE`, neindexabil. Recomandare: `CROSS APPLY` (Oracle 12c+, disponibil pe 19c) in loc de doi
|
||||
subselecti scalari separati — un singur scan per rand din urma, ambele sume calculate odata:
|
||||
|
||||
```sql
|
||||
SELECT ...,
|
||||
jt.jtotctva,
|
||||
jt.jtva_ti
|
||||
FROM anaf_efactura a
|
||||
CROSS APPLY (
|
||||
SELECT SUM(j.totctva) AS jtotctva,
|
||||
SUM(NVL(j.TI21T,0)+NVL(j.TI11T,0)+NVL(j.TI24T,0)+NVL(j.TI20T,0)
|
||||
+NVL(j.TI19BCT,0)+NVL(j.TI19BVT,0)+NVL(j.TI19BFT,0)
|
||||
+NVL(j.TI09BVT,0)+NVL(j.TI09BFT,0)
|
||||
+NVL(j.XX21TIT,0)+NVL(j.XX11TIT,0)+NVL(j.XX19TIT,0)+NVL(j.XX9TIT,0)) AS jtva_ti
|
||||
FROM jc2007 j
|
||||
LEFT JOIN nom_parteneri p ON j.id_part = p.id_part
|
||||
WHERE j.an = EXTRACT(YEAR FROM a.xdata_act)
|
||||
AND j.luna = EXTRACT(MONTH FROM a.xdata_act)
|
||||
AND j.dataact = a.xdata_act
|
||||
AND REGEXP_SUBSTR(a.xnumar_act, '\d+[^[:digit:]]*$') LIKE '%' || TO_CHAR(j.nract) || '%'
|
||||
AND REGEXP_REPLACE(p.cod_fiscal, '[^[:digit:]]', '') = a.cod_fiscal_emitent
|
||||
) jt
|
||||
WHERE a.factura_emisa = 0
|
||||
```
|
||||
|
||||
Motiv pentru `CROSS APPLY` (nu doi subselecti separati): pastreaza exact semantica actuala — fiind
|
||||
un `SUM(...)` fara `GROUP BY`, subquery-ul `APPLY` intoarce mereu exact un rand (NULL pe ambele
|
||||
sume cand nu exista potrivire), identic cu comportamentul scalar-subquery de azi. Nu necesita
|
||||
restructurarea restului view-ului (multe coloane scalare + `detalii` tip `M`/CLOB, imposibil de
|
||||
pus curat intr-un `GROUP BY` la nivel de view fara alte modificari). Nu e scriptul de migrare final
|
||||
— doar forma recomandata, de validat de cine scrie scriptul.
|
||||
|
||||
Pe `anaf_vefactura_trimis`: `jtva_ti` ramane `0` constant (fara subselect), deci nu exista cost
|
||||
suplimentar acolo — planul are dreptate aici, nimic de schimbat.
|
||||
|
||||
---
|
||||
|
||||
## D. Sonda de coloana
|
||||
|
||||
Confirmat azi (inainte de migrare):
|
||||
```sql
|
||||
SELECT jtva_ti FROM anaf_vefactura_primit WHERE 1=2;
|
||||
-- ORA-00904: "JTVA_TI": invalid identifier
|
||||
```
|
||||
|
||||
**Recomandare: `USER_TAB_COLUMNS`**, nu `TRY` pe `SELECT`:
|
||||
|
||||
```sql
|
||||
SELECT COUNT(*) FROM user_tab_columns
|
||||
WHERE table_name = 'ANAF_VEFACTURA_PRIMIT' AND column_name = 'JTVA_TI';
|
||||
```
|
||||
|
||||
Motive:
|
||||
- Confirmat ca views apar normal in `USER_TAB_COLUMNS` (40 coloane gasite pentru
|
||||
`ANAF_VEFACTURA_PRIMIT`), deci interogarea functioneaza identic pe view ca pe tabela.
|
||||
- E o interogare de dictionar, fara sa declanseze parsarea/executia interogarii principale — in VFP
|
||||
nu necesita un bloc `TRY/CATCH` in jurul unui `SELECT` care ar putea arunca o eroare ANAF pe
|
||||
conexiunea Oracle reala (goExecutor), doar un `SELECT ... FROM user_tab_columns`, mai usor de
|
||||
facut robust si de logat separat daca lipseste catalogul.
|
||||
- Cost neglijabil (interogare pe dictionar, nu pe date), rulata o singura data la deschiderea
|
||||
ferestrei, nu per rand.
|
||||
|
||||
---
|
||||
|
||||
## Alte observatii utile pentru cine scrie scriptul de migrare
|
||||
|
||||
- `TI09` nu are deloc varianta `BC` (doar `BV`/`BF`) — asimetric fata de `TI19` care are toate 3
|
||||
(`BC`/`BV`/`BF`). Nu e o eroare, tabela chiar arata asa; scriptul trebuie sa scrie exact
|
||||
`TI09BVT + TI09BFT` (2 termeni), nu 3.
|
||||
- `XX9TIT`/`XX9TIB` (fara zero la 9) sunt corecte, exista pe tabela — confirmat, la fel cum zice
|
||||
planul.
|
||||
- `ANAF_VEFACTURA_EMIS_DETALIU` e INVALID in schema dev azi, independent de L4 — de mentionat catre
|
||||
echipa daca cineva verifica obiecte invalide global, ca sa nu fie confundat cu o stricare produsa
|
||||
de scriptul L4.
|
||||
185
docs/handoff_transa3_conditii.md
Normal file
185
docs/handoff_transa3_conditii.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# Handoff — TRANSA 3, verificare conditii de intrare (agent read-only)
|
||||
|
||||
Verificare pe cod + Oracle (schema `MARIUSM_AUTO`, alias `ROA_CENTRAL`), 27.07.2026.
|
||||
Referinta: `docs\plan-anaf-tva-efactura-4-lucrari.md`, sectiunea "TRANSA 3 — L3" (330-497)
|
||||
si "Ce ramane neverificat" (571-581). Niciun DDL/DML rulat, doar `SELECT`. Niciun commit.
|
||||
|
||||
---
|
||||
|
||||
## A. Cotele 21%/11% in `pack_contab` — **INCHIS**
|
||||
|
||||
Sursa exportata: `docs\local\PACK_CONTAB.pck` (`ALL_SOURCE`, `MARIUSM_AUTO`, PACKAGE + PACKAGE BODY,
|
||||
451 linii).
|
||||
|
||||
- `defalca_tva_incasare` (`.pck:60-79`) nu contine el insusi nicio lista de cote — deleaga integral
|
||||
la `creeaza_note_tva_incasare` (`.pck:69`).
|
||||
- `creeaza_note_tva_incasare` (`.pck:121-415`) foloseste `DECODE(A.ID_JTVA_COLOANA, ...)` cu id-urile
|
||||
211/215 pentru JC (`RO21NB/RO21NT`, `RO11NB/RO11NT`, `.pck:255-257, 288-289`) si 38/42 pentru JV
|
||||
(`.pck:270-272, 303-304`), alaturi de 171/179/189/173 (24/20/19/9) si default 5%. Antetul pachetului
|
||||
are comentariul `08.08.2025 / creeaza_note_tva_incasare TVA 21%, 11%` (`.pck:56-58`), care confirma
|
||||
data introducerii.
|
||||
- `cauta_facturaTVAEx` (`.pck:417-448`) filtreaza explicit `RO21NT <> 0 OR RO11NT <> 0 OR RO19NT <> 0
|
||||
OR RO9NT <> 0 OR RO5NT <> 0` (`.pck:433, 446`).
|
||||
|
||||
**Observatie in afara scopului A** (nu blocheaza conditia de intrare, dar de retinut): filtrul din
|
||||
`cauta_facturaTVAEx` omite `RO24NT`/`RO20NT` — o factura cu TVA neexigibil DOAR pe cota 24% sau 20%
|
||||
nu apare in lista cautata manual. E preexistent, nu introdus de suportul 21/11, si e alt buton
|
||||
(`cauta_facturaTVAEx` alimenteaza calea "Otherwise" din `do_adauga_tva_exigibil`, nu calea L3).
|
||||
|
||||
**VERDICT: cotele 21%/11% sunt tratate integral in ambele proceduri. Conditia de intrare e inchisa.**
|
||||
|
||||
---
|
||||
|
||||
## B. Formula de sold neexigibil — **INCHIS PARTIAL, CONTRAZICE PLANUL pe sursa datelor**
|
||||
|
||||
Confirmat pe `ALL_TAB_COLUMNS` (`MARIUSM_AUTO`): toate cele 14 coloane din lista corecta
|
||||
(`RO24NB/NT, RO20NB/NT, RO21NB/NT, RO11NB/NT, RO19NB/NT, RO9NB/NT, RO5NB/NT`) exista, cu acelasi nume,
|
||||
in **ambele** `JC2007` si `JV2007` (NUMBER(18,4)). `ID_FACT` exista in ambele (NUMBER(20)).
|
||||
|
||||
**CONTRAZICE PLANUL:** coloana `TVA_INCASARE` **nu exista** in `JC2007` nici in `JV2007` — nu e
|
||||
"de confirmat", e absenta confirmata. `TVA_INCASARE` traieste pe `DOCUMENTE` (header-ul facturii,
|
||||
`ID_DOC` = `id_fact`, cf. `pack_contab.creeaza_note_tva_incasare`: `select nract from documente where
|
||||
id_doc = tnIdFact`), plus pe view-urile `VJC2025`/`VJV2025` care deja o aduc alaturi de toate cele 14
|
||||
coloane de cota (verificat pe `ALL_TAB_COLUMNS`) — acelasi view pe care `cauta_facturaTVAEx` il
|
||||
foloseste deja (`vjv2025`/`vjc2025`, `.pck:430, 443`).
|
||||
|
||||
O interogare literala "peste jc2007 + jv2007" cu filtru `tva_incasare = 1`, asa cum e formulat in
|
||||
plan la Pasul 3, ar da eroare Oracle (coloana inexistenta). Recomandare: interogarea sa foloseasca
|
||||
`VJC2025`/`VJV2025` (deja au `AN`, `LUNA`, `ID_FACT`, toate cele 14 coloane, `TVA_INCASARE`) in loc de
|
||||
`JC2007`/`JV2007` brute — consecvent cu precedentul din acelasi pachet (`cauta_facturaTVAEx`), sau
|
||||
alternativ un JOIN explicit `jc2007/jv2007` -> `documente` pe `id_doc = id_fact`.
|
||||
|
||||
Interogare-draft testata pe date reale (VJC2025/VJV2025, fara restrictie an/luna, deci scanare completa
|
||||
ca sa vada volumul maxim):
|
||||
|
||||
```sql
|
||||
select id_fact from vjc2025
|
||||
where tva_incasare = 1
|
||||
and (ro24nb+ro24nt+ro20nb+ro20nt+ro21nb+ro21nt+ro11nb+ro11nt+ro19nb+ro19nt+ro9nb+ro9nt+ro5nb+ro5nt) <> 0
|
||||
union
|
||||
select id_fact from vjv2025
|
||||
where tva_incasare = 1
|
||||
and (ro24nb+ro24nt+ro20nb+ro20nt+ro21nb+ro21nt+ro11nb+ro11nt+ro19nb+ro19nt+ro9nb+ro9nt+ro5nb+ro5nt) <> 0;
|
||||
```
|
||||
|
||||
Rezultate (fara filtrul de an/luna, deci acesta e volumul-plafon, nu volumul unei singure salvari):
|
||||
5711 randuri in `VJC2025`, 15506 in `VJV2025`, care se filtreaza la interogarea reala pe `an`/`luna`
|
||||
curente plus intersectia locala cu `tact`. `ID_FACT` nu e niciodata null pe niciuna din cele doua
|
||||
(`count(*) where tva_incasare=1 and id_fact is null` = 0 pe amandoua).
|
||||
|
||||
**VERDICT: coloanele de cota si `id_fact` sunt confirmate pe `JC2007`/`JV2007` (lista corecta e
|
||||
completa acolo). `tva_incasare` NU e acolo — planul trebuie corectat sa citeasca din `VJC2025`/
|
||||
`VJV2025` (sau JOIN cu `DOCUMENTE`), altfel Pasul 3 pica la implementare cu eroare Oracle de coloana
|
||||
inexistenta.**
|
||||
|
||||
---
|
||||
|
||||
## C. `defalca_tva_incasare` poate intoarce zero randuri sau `id_fact` problematic — **INCHIS, cu
|
||||
intarire fata de plan**
|
||||
|
||||
Din sursa (`.pck:121-415`): cursorul returnat de `creeaza_note_tva_incasare` seteaza mereu
|
||||
`id_fact = tnIdFact` (parametrul de intrare, literal — `.pck:169`) — deci `id_fact` NU poate fi NULL
|
||||
in cursor decat daca parametrul insusi era NULL, ceea ce VFP nu trimite (`Str()` pe un numeric).
|
||||
**Zero randuri e insa posibil**: filtrul final `WHERE A1.ID_JTVA_COLOANA IS NOT NULL AND SIGN(V_SUMA)
|
||||
* A1.totctva > SIGN(V_SUMA) * A1.DIF` (`.pck:412-413`) poate exclude toate liniile.
|
||||
|
||||
Codul VFP care insereaza din cursor (`omodificari.vc2:12400-12422`,
|
||||
`Insert Into &tcCursorAct(...) ... FROM (lcCursorDefTVA) a`) nu are protectie explicita pe 0 randuri —
|
||||
un `INSERT INTO ... SELECT` dintr-un cursor gol insereaza tacut 0 randuri, fara eroare. Confirma
|
||||
citatul din plan (`oproceduri_inchidere.prg:843-848`, alta cale de apel, meniu -> `inchidere_tva_sold`,
|
||||
care TRATEAZA explicit `Reccount(lcCursorDefTVA) = 0`).
|
||||
|
||||
**Gasit in plus, mai relevant decat citatul din plan pentru drumul L3:** pe drumul
|
||||
`do_adauga_tva_exigibil` (butonul chiar din spatele avertizarii L3), exista un caz concret si usor de
|
||||
reprodus in care `tnIdFact` trimis catre Oracle e **santinela `-5`**, nu id-ul real:
|
||||
|
||||
```
|
||||
omodificari.vc2:12547-12552 (Case !Empty(perechec) And Left(scd,1)='5')
|
||||
loadd.id_fact = Iif(m.loadd.id_factc > 0, m.loadd.id_factc, -5)
|
||||
...
|
||||
llCalculeazaNoteTVA = m.llCalculeazaTVAEx
|
||||
```
|
||||
si simetric la `:12555-12561` pentru `id_factd`. Daca `llCalculeazaNoteTVA` e adevarat (bifat
|
||||
`chkTVAEX`), linia asta ajunge la `Thisform.creeaza_note_tva_incasare('tact', m.loadd, m.lnSuma)`
|
||||
(`:12601`), care citeste `lnIdFact = toRec.id_fact` (`:12378`) — posibil `-5` — si il trimite direct
|
||||
la `pack_contab.defalca_tva_incasare(-5, ...)` (`:12385-12389`). Nicio factura nu are `id_fact = -5`,
|
||||
deci cursorul Oracle vine garantat gol pe acest drum, de fiecare data cand id_factc/id_factd nu era
|
||||
deja completat.
|
||||
|
||||
**VERDICT: da, zero randuri e un caz real si reproductibil pe insusi drumul pe care il declanseaza
|
||||
butonul din dialogul L3 ("Adauga acum"), nu doar pe calea de meniu citata in plan. Flagul anti-bucla
|
||||
de la Pasul 5 e strict necesar — confirmarea e mai tare decat presupunea planul.** `id_fact` NULL nu
|
||||
e posibil prin acest pachet (mereu = parametrul trimis); riscul real e parametrul insusi fiind
|
||||
santinela, nu NULL.
|
||||
|
||||
---
|
||||
|
||||
## D. Kill-switch: unde se pune — **CONTRAZICE PLANUL pe mecanism**
|
||||
|
||||
Planul (Pasul 0.5) presupune "Optiune in `Optiuni_FIRMA`/`Optiuni_PROGRAM`" — DBF-urile locale din
|
||||
`D:\ROA\ROACONT\DATE\` (`Optiuni_FIRMA.dbf`, `Optiuni_PROGRAM.dbf`, `Optiuni_LOCAL.dbf` — exista pe
|
||||
disc, confirmat). **`RC_ANAF_VERIF_SELECTIE` NU foloseste aceste DBF-uri.** Mecanismul real, verificat
|
||||
in cod:
|
||||
|
||||
- Functia care citeste nivelul: `ANAF_NivelVerificare` (`COMUN\programe\ocautare.prg:242-276`).
|
||||
- Kill-switch propriu-zis, verificat PRIMUL: fisier `.ini`, nu DBF —
|
||||
`getini(gcGeneralIniFile, 'anaf', 'verificare_selectie')`; doar valoarea explicita `'0'` opreste
|
||||
(`ocautare.prg:247-249`). Absenta cheii NU opreste nimic (cascada continua).
|
||||
- Optiune per-utilizator/per-firma: cursoarele `crsOptiuniUtilizator`/`crsOptiuni`, incarcate din
|
||||
Oracle la pornire — tabelele Oracle `optiuni_util` / `optiuni` (`actualizeaza_optiuni_utilizator` /
|
||||
`actualizeaza_optiuni`, `oinit_optiuni.prg:709-722, 784-798`), citite prin
|
||||
`citeste_optiune_utilizator` / `citeste_optiune` (`oinit_optiuni.prg:725-742, 802-823`; apel efectiv
|
||||
la `ocautare.prg:264-266`). Cache pe sesiune intr-o `Collection` (`goCacheANAF_Nivel`,
|
||||
`ocautare.prg:253-259`), cheia fiind schema + utilizator.
|
||||
- Scriere: `scrie_optiune_utilizator` cheama `PACK_SESIUNE.SetOptiuneUtilizator` (`oinit_optiuni.prg:
|
||||
764`) — deci store-ul de adevar e Oracle, nu DBF local.
|
||||
- Aparitia in UI: intrare de meniu, nu ecran de optiuni cu DBF —
|
||||
`ON SELECTION BAR 3 OF optiuniuti DO ANAF_ComutaVerificare IN ocautare.prg`
|
||||
(`Meniuri\CONT2000.MPR:210`), care cheama `ANAF_ComutaVerificare` (`ocautare.prg:324-382`) — un
|
||||
toggle interactiv (citeste valoarea curenta, cere valoarea noua), nu un formular cu campuri DBF.
|
||||
|
||||
**VERDICT: modelul real de urmat pentru kill-switch-ul L3 e Oracle (`optiuni`/`optiuni_util` +
|
||||
`citeste_optiune`/`citeste_optiune_utilizator` + cache in Collection) plus, daca se vrea si oprire
|
||||
per-masina, INI-ul (`getini(gcGeneralIniFile, ...)`) — NU `Optiuni_FIRMA`/`Optiuni_PROGRAM.dbf` din
|
||||
`DATE\`. Planul trebuie corectat inainte de Pasul 0.5.**
|
||||
|
||||
---
|
||||
|
||||
## E. Acoperirea drumurilor de instantiere — **INCHIS, lista din plan e completa**
|
||||
|
||||
Cautare `rg --no-ignore` in tot `D:\ROA\ROACONT` (inclusiv `COMUN\`) dupa
|
||||
`Createobject([frm_modific2007]...)` / `Createobject([frm_modific2024]...)`. Rezultat (excluzand
|
||||
`.BAK`, fisiere de test, si documentul de plan insusi): **exact aceleasi 14 situri** din listă:
|
||||
`ocont2003.prg:416,1230,1679,2141`; `oproceduri_incasari.prg:299`; `frm_import_extrase_banca.sc2:1652`;
|
||||
`anaf_efactura.vc2:12733,12940`; `frm_initializare_facturi_balanta.sc2:1803`; `comun.vc2:2436`;
|
||||
`oproceduri_inchidere.prg:719,902,1007,1438`; `frm_import_note_a4200.sc2:1651`;
|
||||
`frm_import_note_facturi_clienti.sc2:895`; `ooperatii_comune.prg:1137`. Nimic lipsa.
|
||||
|
||||
(Gasit in plus, dar nu conteaza pentru acoperirea de productie: `COMUN\utile\Teste\
|
||||
achizitie_import\test_repro_cnrcrt_footer.prg:82` — harness de test, nu drum de productie.)
|
||||
|
||||
**Verificare bucla** (subagent, citire directa a codului din jurul fiecarui `Createobject`): din cele
|
||||
14 situri, **niciunul altul** nu instantiaza formularul intr-o bucla activa — toate `SCAN`/`FOR` din
|
||||
procedurile respective se incheie inainte de linia cu `Createobject`. Singura exceptie sintactica:
|
||||
`oproceduri_inchidere.prg:719` e in interiorul unui `Do While`, dar urmat imediat de un `Exit`
|
||||
necondiționat dupa `loForm.Show(1)` — functional tot instantiere unica, nu bucla reala.
|
||||
|
||||
**VERDICT: candidatii pentru flagul de lot (Pasul 0.6) raman exact cei trei numiti in plan —
|
||||
`anaf_efactura.vc2:12733`, `:12940`, `comun.vc2:2436`. Nu mai sunt altii.**
|
||||
|
||||
---
|
||||
|
||||
## Ce ramane neverificat (in afara scopului A-E, de mentionat)
|
||||
|
||||
- Comportamentul `goExecutor` la timeout/conexiune cazuta — nu a fost testat (ar necesita simularea
|
||||
unei conexiuni cazute); contractul de cod (`lnSucces < 0` la esec, in toate apelurile vazute) e
|
||||
vizibil, dar nu a fost validat prin scenariu de esec real.
|
||||
- Volumul real de linii pe un decont de curier/procesator la clienti — nu exista date de productie
|
||||
disponibile in schema de dev (`MARIUSM_AUTO`) ca sa fie masurat; ramane pe baza estimarii din plan.
|
||||
|
||||
---
|
||||
|
||||
## Fisiere generate
|
||||
|
||||
- `docs\local\PACK_CONTAB.pck` — export sursa `pack_contab` (PACKAGE + PACKAGE BODY), 451 linii,
|
||||
`ALL_SOURCE` din `MARIUSM_AUTO`.
|
||||
182
docs/handoff_transa3_deschise.md
Normal file
182
docs/handoff_transa3_deschise.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# TRANSA 3 (L3) — cele doua puncte ramase din "Ce ramane neverificat"
|
||||
|
||||
Data: 27.07.2026. Read-only (Oracle: doar SELECT; cod: doar citire). Nimic modificat, nimic comis.
|
||||
Nu ating `docs\handoff_transa3_conditii.md` (al colegului T3-cond).
|
||||
|
||||
## VERDICT GENERAL
|
||||
|
||||
- **Punctul 1 (goExecutor la timeout/conexiune cazuta) — CONTRAZICE PLANUL.** Comportamentul implicit
|
||||
NU e "se sare, cu linie in goLog": pe conexiune cazuta apare mereu un dialog modal blocant, care la
|
||||
Cancel face `QUIT` (inchide toata aplicatia). Pattern-ul defensiv cerut de plan **nu are niciun
|
||||
precedent** azi in codebase — trebuie construit, nu copiat.
|
||||
- **Punctul 2 (linii pe decont) — RAMAS DESCHIS pe cifra exacta**, dar decizia arhitecturala a
|
||||
planului (fara lista `IN(...)`) ramane intemeiata independent de cifra. Schema dev nu are volum
|
||||
reprezentativ pentru batch-uri reale de extras/decont.
|
||||
|
||||
---
|
||||
|
||||
## Punctul 1 — comportamentul `goExecutor` la timeout / conexiune cazuta
|
||||
|
||||
Sursa reala (cautata cu `rg --no-ignore`... de fapt Grep a gasit-o direct, COMUN nu era exclus in
|
||||
aceasta sesiune): clasa `oexecutor` e definita in `COMUN\programe\oproceduri_comune.prg:69-547`
|
||||
(NU in `anaf_efactura.vc2` — de acolo doar se apeleaza). Instantiata o singura data:
|
||||
`goExecutor = Createobject("oExecutor")`, `Programe\roacont.prg:588`.
|
||||
|
||||
### Ce intoarce `oExecute()` la esec
|
||||
|
||||
Functie normala, **nu arunca eroare VFP**. `SQLExec()` esuat intoarce direct `< 0`, prins de codul
|
||||
existent — niciun `THROW`/`ERROR()` implicat. Return: `CT_INSUCCES` (`= -1`,
|
||||
`COMUN\include\comun.h:10`) daca `lnSucces < 1`, altfel `CT_SUCCES` (`= 1`)
|
||||
(`oproceduri_comune.prg:496`, `Return Iif(lnSucces >= 1, CT_SUCCES, CT_INSUCCES)`).
|
||||
Cursorul de iesire nu se creeaza pe esec (Use-ul din urma nu ruleaza).
|
||||
|
||||
`oExecuta()` (wrapper cu litera mica, folosit in ~jumatate din apeluri) doar impacheteaza
|
||||
`oExecute()` si adauga necontitionat `amessagebox(This.oPrelucrareEroare(), 16, "Eroare")` pe orice
|
||||
esec (`:149-152`) — **indiferent de parametri**. Diferenta fata de `oExecute()` (raw) e semnificativa
|
||||
pentru L3.
|
||||
|
||||
### Urca eroarea la `ErrorHandler` global? NU, direct — DAR
|
||||
|
||||
Nu urca la `ON ERROR` (nu e o exceptie VFP). Insa exista un dialog modal **necontitionat de
|
||||
`tlShowError`**, la eroare ODBC (`lnEroare1 = 1526`) cu cod de eroare in lista
|
||||
`12152, 3113, 3114, 12560, 4068, 28, 12` (`oproceduri_comune.prg:383`) — **exact codurile de
|
||||
conexiune cazuta/protocol** (3114 = NOT CONNECTED TO ORACLE, 3113 = end-of-file on communication
|
||||
channel, 12560 = protocol adapter error):
|
||||
|
||||
```
|
||||
lnRaspuns = amessagebox('Eroare de conectare.' + ... + 'Doriti reconectare?', 4 + 32, 'Eroare')
|
||||
```
|
||||
|
||||
(`:390`) — apare **mereu** cand `llReconnect = .T.`, chiar daca apelantul a lasat toti parametrii
|
||||
default. Daca utilizatorul raspunde "Nu" (`lnRaspuns <> 6`): `Quit` + `Retry` (`:412-413`) —
|
||||
**inchide toata aplicatia**, nu doar sare peste verificare.
|
||||
|
||||
`llReconnect` e recalculat **la fiecare apel**, ignorand orice setare anterioara pe obiect
|
||||
(`:220-224`):
|
||||
```
|
||||
If SQLGetprop(lnHandle, "Transactions") = 2 && TRANZACTIE MANUALA
|
||||
This.lReconnect = .F.
|
||||
Else
|
||||
This.lReconnect = .T. && cazul normal, in afara unei tranzactii manuale
|
||||
Endif
|
||||
```
|
||||
si apoi, daca apelul are sub 8 parametri (cazul general in tot codebase-ul), `llReconnect` preia
|
||||
`This.lReconnect` — deci **.T. implicit** pentru orice verificare in afara unei tranzactii manuale.
|
||||
Singurul mod de a opri acest modal e sa dai explicit al 8-lea parametru (`tlReconnect = .F.`) la
|
||||
apel — vezi mai jos, nu exista niciun apel asa in tot codebase-ul.
|
||||
|
||||
**CONTRAZICE PLANUL:** cerinta "orice esec (... conexiune cazuta ...) -> se sare, cu linie in
|
||||
`goLog`. Niciodata tacut... Esecul nu blocheaza salvarea" (plan, `:445-448`) **nu e comportamentul
|
||||
implicit** pentru exact acest caz (conexiune cazuta). E opusul: un dialog modal blocant, care poate
|
||||
opri toata aplicatia. Pentru orice ALTA eroare (SQL gresit, tabela inexistenta — `ORA-00942`,
|
||||
coloana lipsa — `ORA-00904`), comportamentul implicit CHIAR e "se sare, log, fara dialog" —
|
||||
`llShowError` e `.F.` implicit si acel dialog nu e conditionat decat de el. Deci planul are dreptate
|
||||
pentru clasa generala de erori, dar nu pentru "conexiune cazuta" — exact cazul numit explicit in
|
||||
text.
|
||||
|
||||
`goLog.Log(...)` SE cheama pe toate drumurile de esec (`:368-370`, `:384-387`, `:422-424`) — de
|
||||
partea asta planul are dreptate necontitionat, indiferent de tipul erorii.
|
||||
|
||||
In plus, pe orice esec (`lnSucces < 0`), independent de parametri, codul posteaza automat eroarea la
|
||||
endpoint-ul de erori (`goMyXMLHTTP.postError(...)`, `:463-471`) — un apel HTTP sincron in plus pe
|
||||
drumul de salvare, la fiecare esec, inclusiv la cele care ar trebui "sarite silentios".
|
||||
|
||||
### Timeout configurat?
|
||||
|
||||
Nu exista niciun `SQLSETPROP` cu `QueryTimeout`/`ConnectTimeout`/`WaitTime` pe handle-ul Oracle,
|
||||
nicaieri in `oExecutor`/`oConn` (`oproceduri_comune.prg:662-731`, `Connect` foloseste doar
|
||||
`Sqlstringconnect(lcString)` cu `dsn=...;Uid=...;Pwd=...`, fara parametri de timeout). Singurul
|
||||
`ConnectTimeout` gasit in tot fisierul (`:4105-4118`) e pentru verificarea HTTP de update-uri, fara
|
||||
legatura cu conexiunea Oracle. **Concluzie: un query care ramane agatat (nu eroare, ci hang) nu are
|
||||
niciun timeout care sa-l intrerupa — ar bloca formularul la nesfarsit**, ceva ce nici planul, nici
|
||||
codul actual nu adreseaza. De consemnat separat, dincolo de "esec" (eroare) — un hang nu e un esec,
|
||||
e o blocare fara iesire.
|
||||
|
||||
### Tiparul de apel defensiv "corect" deja folosit in codebase — NU EXISTA
|
||||
|
||||
Am cautat toate apelurile `oExecute(`/`oExecuta(` din COMUN si Programe (peste 150) — **niciunul nu
|
||||
trece de 2 parametri** (`tcSql`, `tcCursor`). Nimeni nu foloseste vreodata parametrii 6-8
|
||||
(`tlShowError`, `tlQuitOnError`, `tlReconnect`) explicit. Deci pattern-ul "cheama cu
|
||||
`tlReconnect = .F.` ca sa eviti dialogul de reconectare" **nu are niciun precedent** — L3 ar fi
|
||||
PRIMUL loc din codebase care il foloseste.
|
||||
|
||||
Cel mai apropiat precedent (nu perfect, dar cel mai aproape de "se sare fara dialog"):
|
||||
- `oproceduri_inchidere.prg:1297`: `goExecutor.oExecuta(lcSql, "imob_conturi")` urmat doar de
|
||||
`If m.llSucces ... Endif` — la esec nu se face nimic in plus (dar `oExecuta` tot arata singura
|
||||
`amessagebox` interna, deci nu e cu adevarat silentios).
|
||||
- Pattern mai bun de citat ca baza (foloseste `oExecute`, nu wrapper-ul `oExecuta`):
|
||||
`COMUN\clase\baza.vc2:1807`, `lnSucces = goExecutor.oExecute(lcSql,lcCursor)`, fara parametri
|
||||
suplimentari — la 2 parametri, `llShowError`/`llQuitOnError` raman `.F.` (fara dialog pe erori
|
||||
generice), dar `llReconnect` tot devine `.T.` implicit, deci tot apare dialogul de reconectare pe
|
||||
conexiune cazuta.
|
||||
|
||||
**Recomandare pentru L3** (nu e sarcina mea sa implementez, doar de raportat ca gasire): interogarea
|
||||
noua trebuie sa apeleze `goExecutor.oExecute(...)` (NU `oExecuta`, care are mesaj propriu
|
||||
necontitionat), cu toti cei 8 parametri, ultimul (`tlReconnect`) explicit `.F.`, si verificarea
|
||||
proprie a rezultatului fara niciun `amessagebox` propriu — un tipar care azi nu exista nicaieri in
|
||||
cod si trebuie scris de la zero, nu copiat.
|
||||
|
||||
---
|
||||
|
||||
## Punctul 2 — numarul real de linii pe un decont de curier/procesator
|
||||
|
||||
### Ce s-a verificat despre sursa datelor
|
||||
|
||||
Confirmat din cod (`Programe\oproceduri_import.prg:100-264`): importul de extrase/deconturi e
|
||||
**strict pe fisier local** (`Getfile()` la `:138`, parsat client-side in cursoare VFP
|
||||
`C_IMPORT_TEMP` -> `cActTemp`). Oracle NU pastreaza niciun tabel de staging cu "lot de import" si
|
||||
numar de linii — abia dupa validare, liniile devin note (`ACT`/`ACTACTAN`) si se salveaza individual.
|
||||
Deci **nu exista in Oracle o coloana/tabela care sa raspunda direct la intrebare** — a trebuit
|
||||
reconstruita indirect.
|
||||
|
||||
`nom_fdoc`: `id_fdoc = 40` = `EXTRAS CON` (extras cont), `id_fdoc = 33` = `DECONT` (decont
|
||||
curier/procesator).
|
||||
|
||||
### Reconstructie indirecta (proxy, nu masuratoare directa)
|
||||
|
||||
`ACT` nu are o coloana de "id lot" — am grupat notele salvate prin apropierea `DATAORA` (momentul
|
||||
efectiv al salvarii, cu ora), pe acelasi `id_util`, cu prag de 10 minute intre randuri consecutive ca
|
||||
limita de lot. E o aproximare (poate sparge/uni loturi reale), nu o masuratoare exacta din aplicatie.
|
||||
|
||||
**Rezultate (schema `MARIUSM_AUTO`, dev):**
|
||||
- `DECONT` (id_fdoc=33): **doar 2 randuri in toata baza**, un singur lot de 2 linii (25.06.2026).
|
||||
Date insuficiente pentru orice concluzie.
|
||||
- `EXTRAS CON` (id_fdoc=40): 222 randuri, pe 32 zile distincte, din 19.01.2008 pana in 29.05.2026 —
|
||||
40 loturi estimate. **min 1, max 70, medie 5.6, percentila 95 ≈ 10 linii/lot.**
|
||||
|
||||
**CONTRAZICE PLANUL, cu rezerva explicita de mai jos:** cifra afirmata in plan ("un extras obisnuit
|
||||
are 300-2000 linii/luna") e cu un ordin de marime peste orice lot gasit in aceasta schema (maximul
|
||||
absolut observat e 70).
|
||||
|
||||
**De ce nu extrapolez asta la "planul gresit pe cifra":** `MARIUSM_AUTO` e schema de dezvoltare a lui
|
||||
Marius (confirmat in `COMUN\docs\oracle_export.md`), nu un client real cu volum de productie. Loturile
|
||||
gasite arata a teste punctuale facute de-a lungul anilor (o inserare la cateva luni sau ani), nu
|
||||
activitate de contabilitate lunara reala pe un cont bancar activ. **Schema dev NU are date
|
||||
reprezentative pentru volumul real al unui client — nu pot confirma sau infirma cifra 300-2000 pe
|
||||
aceasta baza.** Ramane RAMAS DESCHIS strict pe cifra exacta.
|
||||
|
||||
**Corroborare slaba, doar indicativa:** fisierul-sablon real din `Alte\Extras_de_cont_11634808MT
|
||||
940.txt` (extras MT940 pentru o singura zi, un singur cont) are 11 linii de tranzactie (`:61:`) pentru
|
||||
acea zi. Extrapolat naiv la ~20-22 zile lucratoare/luna ar da ~220-240 linii/luna pentru un cont de
|
||||
activitate medie — aproape de capatul de jos al intervalului din plan (300), dar e un singur esantion
|
||||
de o zi, pentru o singura firma, nu o distributie.
|
||||
|
||||
### Ce ramane solid, indiferent de cifra exacta
|
||||
|
||||
Decizia arhitecturala a planului de la Pasul 3 ("fara lista `IN(...)`", `:421-431`) **nu depinde**
|
||||
de cifra 300-2000 ca sa fie corecta: o interogare unica, de lungime fixa, cu intersectia facuta local
|
||||
in VFP, elimina o clasa intreaga de eroare (`ORA-01795`, prag 1000) **indiferent daca lotul real are
|
||||
10 sau 2000 de linii** — nu exista un prag sub care revenirea la `IN(...)` ar fi de preferat, pentru
|
||||
ca varianta cu interogare unica nu are dezavantaj de cost fata de o lista `IN` mica. Deci verdictul
|
||||
practic: **decizia ramane intemeiata**, chiar daca premisa numerica citata in text nu e verificata
|
||||
(si, pe aceasta schema, pare supraestimata).
|
||||
|
||||
---
|
||||
|
||||
## Alte observatii utile
|
||||
|
||||
- `oExecuta()` (wrapper) vs `oExecute()` (raw): distinctia conteaza mult pentru L3 si nu era
|
||||
evidenta din plan. `oExecuta` are propriul `amessagebox` necontitionat pe esec — pentru cerinta
|
||||
"niciodata dialog, doar log", trebuie folosit `oExecute`, nu `oExecuta`.
|
||||
- `oPrelucrareEroare()` (folosit de mesajele proprii de eroare) nu a fost citit in detaliu — nu era
|
||||
necesar pentru cele doua puncte cerute.
|
||||
704
docs/plan-anaf-tva-efactura-4-lucrari.md
Normal file
704
docs/plan-anaf-tva-efactura-4-lucrari.md
Normal file
@@ -0,0 +1,704 @@
|
||||
# Plan: 4 lucrari ROACONT (ANAF perioada TVA, validare CNP, avertizare exigibilizare, borderou eFactura)
|
||||
|
||||
Data: 27.07.2026. Autor livrare: marius.mutu.
|
||||
Versiune consolidata dupa runda 2 de review si poarta de decizie. **Aceasta e versiunea de
|
||||
executat** — incorporeaza toate deciziile. Istoricul review-ului e in Anexa, la final, si nu
|
||||
contine nimic de implementat.
|
||||
|
||||
Plan de test insotitor:
|
||||
`~/.gstack/projects/ROACONT/mmari-main-eng-review-test-plan-20260727-194744.md`
|
||||
|
||||
## Livrare in TREI TRANSE separate
|
||||
|
||||
Cele 4 lucrari nu au nicio dependenta functionala intre ele, dar au clase de risc si povesti de
|
||||
retragere incompatibile. Impachetate impreuna, o retragere pentru L3 ar lua cu ea si view-ul deja
|
||||
aplicat in schema clientului.
|
||||
|
||||
| Transa | Continut | Blast radius | Retragere | Blocata de |
|
||||
|---|---|---|---|---|
|
||||
| 1 | L1 + L2 | 2 fisiere `.prg` in COMUN | un pas | nimic — se poate incepe |
|
||||
| 2 | L4 | script DB + o expresie in client | doi pasi coordonati | 2 conditii de intrare |
|
||||
| 3 | L3 | drumul de salvare al notelor, toata suita ROA | un pas, dar afecteaza tot | 1 conditie de intrare |
|
||||
|
||||
Fiecare transa se inchide in SVN inainte de a incepe urmatoarea.
|
||||
|
||||
---
|
||||
|
||||
# TRANSA 1 — L1 + L2
|
||||
|
||||
Ambele in `COMUN\programe\ocautare.prg` + `COMUN\programe\validare.prg`. Lane secvential: L1 apoi L2.
|
||||
Fara DB, fara drum de salvare. Reversibil prin revenire la binarul anterior.
|
||||
|
||||
## L1 — de cand este platitor / neplatitor de TVA
|
||||
|
||||
### Problema
|
||||
|
||||
Verificarea ANAF de la alegerea partenerului spune doar starea la data documentului
|
||||
("ANAF: platitor TVA la 27.07.2026"). Pentru un cod fiscal care si-a schimbat atributul,
|
||||
utilizatorul nu vede DE CAND s-a schimbat.
|
||||
|
||||
### Ce exista deja (verificat, nu se construieste)
|
||||
|
||||
- `ParseJsonANAFv8` (`validare.prg:2001-2114`) pune DEJA in cursor toate campurile necesare:
|
||||
`data_inceput_ScpTVA`, `data_sfarsit_ScpTVA`, `data_anul_imp_ScpTVA`, `mesaj_ScpTVA`
|
||||
(citite din `inregistrare_scop_tva.perioade_tva[1]`, liniile 2060-2072).
|
||||
- Cele trei coloane de data sunt DEJA de tip `D` in `CREATE CURSOR` (`validare.prg:2012`).
|
||||
Nu e nevoie de normalizare, doar de garda pe gol.
|
||||
- Informatia se pierde in `ANAF_VerdictDinCursor` (`validare.prg:1657-1689`), care ia din cursor
|
||||
doar `cui`, `scpTVA`, `statusInactivi`, `denumire`, `mesaj` (`:1670-1675`).
|
||||
- Cache-ul de sesiune `goCacheANAF_Sesiune` pastreaza **obiectul intreg** (`ocautare.prg:127`
|
||||
`.Add(m.loRezANAF, ...)`, `:130` `.Item(...)`). Proprietatile noi supravietuiesc. Nu se modifica.
|
||||
- `lDiscordanta` exista deja: `ocautare.prg:143`,
|
||||
`(loRezANAF.scpTVA <> loOut.lAreRO) Or loRezANAF.statusInactivi`. Banda se ramifica deja pe ea
|
||||
la `:651`. Nu se scrie detectie noua.
|
||||
|
||||
Lucrarea e strict propagare + afisare. Nu se schimba apelul HTTP, nu se face al doilea apel.
|
||||
|
||||
### Modificari
|
||||
|
||||
**1. `validare.prg`, `ANAF_VerdictDinCursor` (~1657-1689)**
|
||||
|
||||
Pe obiectul rezultat se adauga patru proprietati, toate citite din cursorul deja parsat:
|
||||
|
||||
- `dInceputScpTVA`, `dSfarsitScpTVA`, `dAnulareScpTVA` — din coloanele de tip `D`, cu `Nvl` si
|
||||
garda pe gol.
|
||||
- `cMesajScpTVA` — din coloana **`mesaj_ScpTVA`** (`C(244)`), NU din `mesaj`.
|
||||
|
||||
Motiv: `validare.prg:2012` declara `mesaj_ScpTVA C(244)` dar `mesaj V(100)`, iar `:2109` face
|
||||
`loDate.mesaj = loDate.mesaj_ScpTVA` urmat de `Insert Into` la `:2112` — VFP taie tacut la 100
|
||||
din 244 de caractere. Proprietatea `mesaj` deja expusa contine mesajul ANAF trunchiat la 41%.
|
||||
|
||||
Toate patru se citesc **aici**: cursorul se inchide la `:1683` si nu mai exista alta ocazie.
|
||||
|
||||
**2. `ocautare.prg`, `ANAF_StarePartener`, blocul de verdict (`136-145`)**
|
||||
|
||||
Propaga cele patru proprietati in `loOut`.
|
||||
|
||||
Citirea se face cu `Pemstatus(loRezANAF, 'dInceputScpTVA', 5)` **aici, la `:140-145`** — nu in
|
||||
`TextAnaf`. `ocautare.prg` e incarcat si de produse ROA care pot avea un `validare.prg` mai vechi
|
||||
(garda existenta la `:63-66`); citirea neprotejata ar arunca eroare in acest bloc, inainte sa se
|
||||
ajunga vreodata la `TextAnaf`.
|
||||
|
||||
**3. `ocautare.prg`, `TextAnaf` (`683-695`) — cand si unde apare data**
|
||||
|
||||
Data de perioada apare in banda **doar pe trei conditii**. In rest banda ramane identica cu azi,
|
||||
iar perioada completa se vede in F4.
|
||||
|
||||
| Conditie | Data in banda |
|
||||
|---|---|
|
||||
| `lDiscordanta` = .T. (ROA difera de ANAF, sau partener inactiv) | DA |
|
||||
| `dAnulareScpTVA` nevid (anulare din oficiu) | DA |
|
||||
| `dSfarsitScpTVA` < `Date()` (perioada s-a incheiat deja) | DA |
|
||||
| rest (cazul normal, concordant) | NU |
|
||||
|
||||
**Regula de pozitionare, obligatorie:** data se lipeste **imediat dupa starea de TVA, inaintea
|
||||
oricarui segment `, Inactiv`**.
|
||||
|
||||
`TextStare` (`ocautare.prg:680`) produce `Platitor TVA, Inactiv`. Forma gresita
|
||||
`ANAF: Platitor TVA, Inactiv din 01.03.2019` afirma ca partenerul e inactiv din 2019, cand de fapt
|
||||
aceea e data de inceput a perioadei de TVA. Cum `lDiscordanta` include `statusInactivi`, cazul
|
||||
inactiv e chiar unul dintre cele aduse in banda — deci regula nu e optionala.
|
||||
|
||||
Forme corecte:
|
||||
|
||||
```
|
||||
ANAF: Platitor TVA din 01.03.2019, Inactiv (DENUMIRE... RO12345678) (F4 = detalii)
|
||||
ANAF: Platitor TVA din 01.03.2019 (DENUMIRE... RO12345678) (F4 = detalii)
|
||||
ANAF: Platitor TVA 01.03.2019 - 31.03.2026 (DENUMIRE... RO12345678) (F4 = detalii)
|
||||
ANAF: Neplatitor TVA din 12.03.2026 (DENUMIRE... 12345678) (F4 = detalii)
|
||||
ANAF: Neplatitor TVA, anulat din 12.03.2026 (DENUMIRE... 12345678) (F4 = detalii)
|
||||
```
|
||||
|
||||
Precedenta cand ambele date sunt nevide: pe `dAnulareScpTVA` — anularea din oficiu e informatia
|
||||
mai grava, iar `anulat` e cuvantul pe care contabilul il cauta. Cele doua date NU se contopesc:
|
||||
`data_sfarsit_ScpTVA` (incetarea inregistrarii) si `data_anul_imp_ScpTVA` (anulare din oficiu) au
|
||||
consecinte diferite asupra dreptului de deducere.
|
||||
|
||||
Cand perioada apare in banda, data documentului redundanta (`' la ' + Dtoc(toStare.dData)`) se
|
||||
scoate din text, ca sa nu rezulte doua date cu doua prepozitii alaturate.
|
||||
|
||||
Banda are voie 2-3 randuri: `lb_anaf` are `WordWrap = .T.`, `Height = 46`,
|
||||
`Width = toForm.Width - 20` (`ocautare.prg:472-476`). Riscul real nu e latimea, ci ca un sufix de
|
||||
lungime variabila muta punctul de wrap si `(F4 = detalii)` sare intre randuri la derularea cu
|
||||
sagetile. Regula de mai sus il reduce mult: ~95% din randuri pastreaza banda de azi.
|
||||
|
||||
**4. `ocautare.prg`, `Detalii` (`787-873`)**
|
||||
|
||||
Bloc nou in dialog, dupa starea curenta: perioada de inregistrare in scopuri de TVA (inceput /
|
||||
sfarsit / anulare, cele nevide, cu etichete distincte) si, daca `cMesajScpTVA` e nevid, mesajul
|
||||
textual primit de la ANAF, **integral**.
|
||||
|
||||
Perioada apare in F4 **intotdeauna** cand ANAF a trimis-o, inclusiv in cazul concordant in care
|
||||
banda nu o arata.
|
||||
|
||||
**5. `validare.prg` (`2064-2072`) — logul pe parsare esuata**
|
||||
|
||||
Se logheaza cazul in care `perioade_tva[1]` exista, sirul sursa e nevid, dar data parsata e goala.
|
||||
|
||||
Conditia se scrie **explicit**, NU in `CATCH`: `CTOD` nu arunca exceptie pe format necunoscut, ci
|
||||
intoarce data goala. `CATCH`-ul de la `:2070` prinde doar erori de acces la `perioade_tva[1]`, deci
|
||||
un log pus acolo nu s-ar declansa niciodata pe cazul pentru care a fost cerut.
|
||||
|
||||
(Parsarea e corecta cat timp ANAF trimite `YYYY-MM-DD`, sub `Set Date To YMD` de la `:2023`,
|
||||
restaurat in `Finally` la `:2131`.)
|
||||
|
||||
### Limita de acceptat
|
||||
|
||||
ANAF v9 intoarce O SINGURA perioada — cea care acopera data interogata. Textul afisat descrie
|
||||
perioada relevanta pentru data documentului, nu tot istoricul.
|
||||
|
||||
---
|
||||
|
||||
## L2 — validare CNP la codurile de 13 cifre
|
||||
|
||||
### Problema (bug raportat)
|
||||
|
||||
`ARGHIR MARIA (CUI: 2540324131210, ID: 149) ANAF nu a raspuns - verificarea a fost sarita.`
|
||||
|
||||
Mesajul e fals. `ANAF_StarePartener` (`ocautare.prg:82-84`) intoarce `.Null.` pentru codurile de
|
||||
13 cifre FARA a seta `tcClasaEsec`. CNP-ul din exemplu este VALID.
|
||||
|
||||
Localizarea exacta a defectului:
|
||||
- BANDA nu acuza ANAF: `.Null.` cu clasa goala cade pe `Case Isnull(m.loStare)` (`:648-650`) ->
|
||||
promptul neutru. Nu e gresit, dar nu spune nimic.
|
||||
- DIALOGUL F4 e singurul care minte: `Detalii`, `:799-804`, ultima ramura a `Iif`-ului imbricat
|
||||
(`:803`) -> 'ANAF nu a raspuns - verificarea a fost sarita.'
|
||||
- `VerificaAlegere` (`:875+`) intoarce `.T.` tacut pe `oStare` nul — acolo nu e nimic de reparat.
|
||||
|
||||
Defectul e mai larg decat cazul raportat: `EvalueazaRand` sterge explicit clasa de esec cand codul
|
||||
e invalid (`:600`, `This.cClasaEsec = ''`). Deci pentru ORICE cod fiscal invalid, banda spune corect
|
||||
"CNP invalid" / "CIF invalid", dar F4 afiseaza tot 'ANAF nu a raspuns'. Cazul raportat e una din
|
||||
doua instante ale aceluiasi defect.
|
||||
|
||||
### Ce exista deja (verificat)
|
||||
|
||||
- Validarea locala RULEAZA DEJA: `EvalueazaRand` apeleaza `ANAF_ValidareCod` la `:594` si iese
|
||||
devreme pe orice rezultat nevid (`595-604`), INAINTE de apelul ANAF. Deci "CNP invalid (...)" si
|
||||
"CIF invalid (...)" se afiseaza deja azi. Nu se scrie validare noua.
|
||||
- Consecinta: un cod care pica validarea nu ajunge niciodata pe drumul ANAF. Ramurile
|
||||
"CNP invalid" sub clasa noua si "CUI valid/invalid" sub `FARA_RASPUNS` sunt INACCESIBILE prin
|
||||
constructie si NU se implementeaza.
|
||||
- `ANAF_ValidareCod` (`:208-227`) decide CNP vs CIF cu prioritate pe `tip_persoana`, altfel lungime 13.
|
||||
- `VALIDARE_CNP` (`validare.prg:1296-1312`), `VALIDARE_CIF` (`validare.prg:1225-1294`).
|
||||
- Clasa noua `COD_INVALID` urmeaza tiparul existent `COD_NENUMERIC` de la `ocautare.prg:643-646`.
|
||||
|
||||
### Modificari
|
||||
|
||||
1. `ocautare.prg`, `EvalueazaRand` (`:600`): `This.cClasaEsec = 'COD_INVALID'` in loc de `''`.
|
||||
2. `ocautare.prg`, `ANAF_StarePartener` (`82-84`): seteaza `tcClasaEsec = 'CNP'` inainte de
|
||||
`Return .Null.`
|
||||
3. `ocautare.prg`, `ANAF_StarePartener`: primeste in plus `tnTipPersoana`, iar conditia de la `:82`
|
||||
devine `Len(m.lcCui) = 13 And m.lnTipPersoana <> 1`.
|
||||
|
||||
Motiv: `:82` decide "persoana fizica" doar pe lungime, ignorand `tip_persoana`, in timp ce
|
||||
`ANAF_ValidareCod` (`:222`) decide invers, cu prioritate pe `tip_persoana`. Divergenta e mascata
|
||||
azi pentru ca banda cade pe promptul neutru si nu afirma nimic. L2 pune acolo
|
||||
"Persoana fizica - CNP corect", deci pentru un partener extern cu cod numeric de 13 cifre
|
||||
aplicatia ar **afirma pe ecran** ceva fals, unde azi tace. Cauza e preexistenta, consecinta
|
||||
vizibila ar fi introdusa de L2.
|
||||
4. `ocautare.prg`, `EvalueazaRand` (`636-657`): ramura noua inaintea lui `Case Isnull(m.loStare)`,
|
||||
pe clasa `'CNP'` — banda arata `Persoana fizica - CNP corect`, culoare NEUTRA
|
||||
(`SeteazaLabel(..., .F., .T.)`), nu verde.
|
||||
|
||||
De ce nu verde: verdele si formularea scurta stau in acelasi loc si in aceeasi culoare cu
|
||||
confirmarea reala de la ANAF. O cifra de control nu este o verificare la ANAF.
|
||||
5. `ocautare.prg`, `Detalii` (`799-804`): doua ramuri noi in `Iif`-ul imbricat:
|
||||
- `'CNP'` -> `Persoana fizica - CNP corect.`
|
||||
- `'COD_INVALID'` -> `Cod fiscal invalid - nu s-a interogat ANAF. Corectati codul in fisa partenerului.`
|
||||
|
||||
Informativ, fara blocare si fara dialog de confirmare — cascada `RC_ANAF_VERIF_SELECTIE` ramane
|
||||
neatinsa.
|
||||
|
||||
---
|
||||
|
||||
# TRANSA 2 — L4: borderou eFactura, taxare inversa
|
||||
|
||||
Nu se incepe inainte ca transa 1 sa fie in SVN.
|
||||
|
||||
### Problema
|
||||
|
||||
In borderoul eFactura, facturile primite cu taxare inversa apar gri (diferenta fata de registrul de
|
||||
cumparari). In XML-ul eFactura taxarea inversa are TVA 0 (`ClassifiedTaxCategory/ID = 'AE'`), dar in
|
||||
contabilitate se inregistreaza `4426 = 4427`, deci `jc2007.totctva` contine si acest TVA. Diferenta
|
||||
rezultata e exact TVA-ul de taxare inversa si nu e o eroare reala.
|
||||
|
||||
Importul face deja corectia inversa la generarea notelor (`anaf_efactura.vc2:12096-12106`), dar
|
||||
numai `IF thisform.lPrimite`.
|
||||
|
||||
### Decizie
|
||||
|
||||
Corectia se face din datele contabile REALE, prin view-ul Oracle — nu prin recalcul cu cota
|
||||
standard (care ar da gresit pe facturi mai vechi la 19%). Scope: DOAR facturi primite.
|
||||
|
||||
**Coloana vizibila in grid NU se face.** Se livreaza doar corectia interna a expresiei `diferenta`.
|
||||
|
||||
### Conditii de intrare (ambele obligatorii inainte de a scrie scriptul)
|
||||
|
||||
1. **Trasare cap-coada** a unei facturi reale: linie XML cu `ClassifiedTaxCategory/ID = 'AE'` ->
|
||||
`id_jtva_coloana` -> coloana din `jc2007`. Se confirma pe date ca acolo sta suma.
|
||||
2. **Definitia curenta a lui `anaf_vefactura_trimis` se ia din `USER_VIEWS.TEXT` din schema tinta**,
|
||||
nu din arhiva CLAR.
|
||||
|
||||
Motiv: scriptul-model `2025\06\ff_2025_06_16_02_COMUN_EFACTURA.sql` redefineste NUMAI
|
||||
`anaf_vefactura_primit` (`:3-53`). Corpul lui `anaf_vefactura_trimis` e in alt fisier, mai vechi
|
||||
(`2024\08\ff_2024_08_22_01_COMUN_EFACTURA.sql:63-112`); cele doua au divergat cu ~10 luni si
|
||||
exista 10 scripturi in arhiva care il redefinesc. Cine il rescrie "dupa model" luand fisierul
|
||||
gresit revine tacut la o versiune veche a view-ului.
|
||||
|
||||
### Modificari
|
||||
|
||||
**1. Script de migrare nou**, in `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\07\`
|
||||
|
||||
`create or replace view` pentru AMBELE view-uri, cu o coloana noua `jtva_ti`:
|
||||
|
||||
- `anaf_vefactura_primit`: `jtva_ti` = suma coloanelor de TVA de taxare inversa din `jc2007`, cu
|
||||
EXACT aceeasi potrivire ca cea folosita azi pentru `jtotctva` (an/luna/dataact/regexp pe numar act
|
||||
si cod fiscal emitent).
|
||||
- `anaf_vefactura_trimis`: `jtva_ti` = constanta `0`. La facturi emise nu se inregistreaza nota
|
||||
contabila de TVA pentru taxare inversa, deci `diferenta` de acolo ramane identica cu azi.
|
||||
|
||||
Coloana e obligatorie in AMBELE: `import_efactura.prg:40` foloseste `FROM <<m.lcTabel>>`, un
|
||||
singur SELECT pentru ambele view-uri (`lcTabel` setat la `:27`). Fara ea, borderoul de facturi
|
||||
TRIMISE crapa cu ORA-00904.
|
||||
|
||||
**Lista de coloane** — CORECTATA 28.07.2026, verificata pe `USER_TAB_COLUMNS`.
|
||||
|
||||
Expresia din `Programe\oproceduri_decont.prg:8670` NU se poate copia: e scrisa peste view-ul
|
||||
`VJC2025` (`FROM VJC2025 J`, `:8677`), nu peste tabela. In acel view `ti19t` si `ti09t` sunt
|
||||
ALIASURI calculate (`SUM(ti19bct+ti19bvt+ti19bft) as ti19t`, `SUM(ti09bvt+ti09bft) as ti09t`).
|
||||
**Pe `jc2007` coloanele `TI19T` si `TI09T` nu exista.** Un `create or replace view` care le
|
||||
foloseste direct pica cu `ORA-00904` — si, cum acelasi script redefineste si
|
||||
`anaf_vefactura_trimis`, ar rupe borderoul pe AMBELE sensuri.
|
||||
|
||||
Lista corecta pe `jc2007` are **13 termeni**, nu 10 (`TI09` nu are varianta `BC`, asimetric fata
|
||||
de `TI19`):
|
||||
|
||||
```
|
||||
NVL(j.TI21T,0)+NVL(j.TI11T,0)+NVL(j.TI24T,0)+NVL(j.TI20T,0)
|
||||
+ NVL(j.TI19BCT,0)+NVL(j.TI19BVT,0)+NVL(j.TI19BFT,0)
|
||||
+ NVL(j.TI09BVT,0)+NVL(j.TI09BFT,0)
|
||||
+ NVL(j.XX21TIT,0)+NVL(j.XX11TIT,0)+NVL(j.XX19TIT,0)+NVL(j.XX9TIT,0)
|
||||
```
|
||||
|
||||
Familia NU este `XX*TI*` singura. Importul eFactura trece prin `ProcentTva2IdJtva`
|
||||
(definita in `COMUN\programe\oproceduri_comune.prg:5836`, doar apelata din
|
||||
`anaf_efactura.vc2:12093`), care pentru cumparari cu taxare inversa da id-urile 216/218/141/145;
|
||||
in `jtva_coloane`, 216 = 'TX. INV. 21%' -> `TI21B` (pereche 217 = `TI21T`), 218 = 'TX. INV. 11%' ->
|
||||
`TI11B` (219 = `TI11T`). Coloanele `XX*TIT` sunt achizitii NON-CE, pe care importul eFactura nu le
|
||||
scrie. Toate confirmate ca existente in `jc2007`: `TI21T`=217, `TI11T`=219
|
||||
(`2026\03\ff_2026_03_09_02_COMUN_PACK_CONTAFIN_10G_ROMCONSTRUCT.pck:4991-4993`), `XX19TIB`=192,
|
||||
`XX19TIT`=193 (`2026\01\PACK_CONTAFIN_ROMCONSTRUCT...pck:4891-4892`).
|
||||
|
||||
**Performanta:** `jtotctva` e deja un subselect corelat peste `jc2007` cu `REGEXP_SUBSTR` +
|
||||
`REGEXP_REPLACE` in `WHERE` — neindexabil, scanare per rand. Un al doilea subselect identic pentru
|
||||
`jtva_ti` ar dubla exact acest cost. Se scrie **un singur subselect care intoarce ambele sume**.
|
||||
|
||||
Se pastreaza `EXEC pack_migrare.UpdateVersiune(...)` + `COMMIT`. Fisierul se scrie cu **CRLF**.
|
||||
Se bumpeaza `versiune_db.txt`. Scriptul se incheie cu o verificare de obiecte invalide: view-urile
|
||||
`anaf_vefactura_primit_detaliu` si `anaf_vefactura_trimis_detaliu`
|
||||
(`2024\08\ff_2024_08_28_02_COMUN_EFACTURA.sql:84`, `:122`) sunt construite peste cele doua si se
|
||||
recompileaza automat, dar invaliditatea trebuie sa nu treaca neobservata.
|
||||
|
||||
**2. `COMUN\programe\import_efactura.prg` — o singura expresie**
|
||||
|
||||
Linia `:36`:
|
||||
|
||||
```
|
||||
NVL(total_cu_tva,0.00) - (NVL(jtotctva,0.00) - NVL(jtva_ti,0.00)) as diferenta
|
||||
```
|
||||
|
||||
**`lcSchema` (`:31-33`) NU se modifica.** `jtva_ti` apare doar ca termen intr-o expresie, nu ca
|
||||
coloana de iesire, deci numarul de coloane al cursorului ramane acelasi. `lcSchema` e o schema
|
||||
**pozitionala** imperecheata cu `lcSelect` in `gencursor` (`:50`); orice coloana noua de iesire ar
|
||||
cere modificarea ambelor, iar modificarea uneia singure ar strica intreg borderoul.
|
||||
|
||||
**3. Degradare gratioasa la lipsa coloanei**
|
||||
|
||||
Inainte de a construi `lcSelect`, se testeaza o data existenta coloanei (`SELECT jtva_ti FROM ...
|
||||
WHERE 1=2` intr-un `TRY`, sau interogare pe `user_tab_columns`) si se construieste `lcSelect` cu sau
|
||||
fara termenul `jtva_ti`.
|
||||
|
||||
Motiv: exe-ul ajunge la client prin update automat, iar migrarea CLAR ruleaza pe alta cadenta. Fara
|
||||
sonda, prima combinatie gresita da ORA-00904 si borderoul nu se deschide deloc, nici primite nici
|
||||
trimise. Cu sonda, ordinea de livrare devine optimizare, nu conditie de functionare.
|
||||
|
||||
Ordinea recomandata ramane: **scriptul se aplica INAINTE de build** — de scris in nota de release.
|
||||
|
||||
**4. Ce NU se atinge**
|
||||
|
||||
Colorarea ramane pe `diferenta <> 0` (`anaf_efactura.vc2:6020-6041` Page2 si `12790-12817`
|
||||
`frm_import_efactura`) — se corecteaza doar sursa numarului. NU se inventeaza o a treia culoare:
|
||||
randurile cu taxare inversa nu sunt de investigat, sunt corecte prin constructie, iar falsurile
|
||||
pozitive omoara marcajul de exceptie. NU se ating Page1 / Page3 si filtrul `chkDiferente`
|
||||
(`anaf_efactura.vc2:5347-5349`) — sunt facturi emise. Nu se editeaza niciun binar `.vcx`.
|
||||
|
||||
### Limita cunoscuta, de consemnat
|
||||
|
||||
O taxare inversa inregistrata la cota GRESITA face ca diferenta sa se anuleze reciproc si randul sa
|
||||
devina alb. Fara coloana in grid nu mai exista nicio parghie vizuala pentru acest caz. E pretul
|
||||
deciziei de a nu adauga coloana si trebuie sa fie scris, nu descoperit.
|
||||
|
||||
---
|
||||
|
||||
# TRANSA 3 — L3: avertizare de exigibilizare TVA la salvarea notelor
|
||||
|
||||
Ultima, singura. Nu se incepe inainte ca transele 1 si 2 sa fie in SVN.
|
||||
|
||||
### Scopul lucrarii — ca sa nu se citeasca gresit
|
||||
|
||||
Singura modificare de cod e in `COMUN\clase\omodificari.vc2`, in `inainte_de_do_termin` al celor
|
||||
doua clase de formular de note: `frm_modific2007` (`:5001`) si `frm_modific2024` (`:13131`).
|
||||
|
||||
**NU** se modifica `oproceduri_inchidere.prg`. **NU** se modifica `do_adauga_tva_exigibil`.
|
||||
**NU** se genereaza nimic automat in afara butonului din dialog.
|
||||
|
||||
`oproceduri_inchidere.prg` apare mai jos doar ca drum de test: exigibilizarea din meniu deschide
|
||||
chiar `frm_modific2007` (`:902`, `Createobject([frm_modific2007], ...)`, cu titlul
|
||||
'Exigibilizare TVA Incasare'), deci avertizarea se declanseaza si acolo fara ca cineva sa fi atins
|
||||
acel fisier.
|
||||
|
||||
### Conditie de intrare
|
||||
|
||||
Cotele 21% si 11% in `pack_contab.defalca_tva_incasare` si `pack_contab.cauta_facturaTVAEx`.
|
||||
Partial inchisa: exista suport 21%/11% in `2025\08\ff_2025_08_08_02_COMUN__PACK_CONTAB.sql`
|
||||
(comentariu "creeaza_note_tva_incasare TVA 21%, 11%"). De confirmat pe date.
|
||||
|
||||
### Ce exista deja (verificat)
|
||||
|
||||
- `Command5` -> `Thisform.do_adauga_tva_exigibil()` (`omodificari.vc2:13776-13778`).
|
||||
Captionul DIFERA intre clase: `:2643` = "Adauga nota TVA devenit exigibil" (`frm_modific2007`),
|
||||
`:6923` = "Adauga TVA exigibilizat" (`frm_modific2024`).
|
||||
- `do_adauga_tva_exigibil` (`:12483+`) lucreaza pe conditia
|
||||
`ales and (scc = '4428' or scd = '4428' or id_factd > 0 or id_factc > 0)` (`:12509`).
|
||||
**Nu contine nicio lista de cote** — lucreaza pe liniile notei si pe `proc_tva`, si deleaga
|
||||
defalcarea Oracle-ului. Deci e agnostic la cota si functioneaza la 21%.
|
||||
- `cmdSelect.Click` = "Selecteaza tot" (`:13640-13658`) — face doar `Replace All ales With .T.`
|
||||
- Precedent identic ca forma in acelasi hook: avertizarea 4426-4428 (`:13165-13176`), cu
|
||||
`amessagebox(..., 4+32, ...)` si `Return .F.`
|
||||
- `tact` poarta `tipnota`, `id_fact`, `id_factd`, `id_factc`, `ales`, `id_act`. Cursorul e construit
|
||||
de fiecare apelant, nu de `omodificari.vc2`. Codul insusi nu are incredere ca `tipnota` exista:
|
||||
`:4752` si `:12847` folosesc `If TYPE('tact.tipnota') = 'N' AND ...`
|
||||
- `Return .F.` din `inainte_de_do_termin` opreste salvarea: apelantul din `_frm_base.vc2`
|
||||
(`PROCEDURE do_termin`) nu face Release/Hide si **nu seteaza `buton`/`gnButon`**, iar toti
|
||||
apelantii testeaza `If buton = 1` inainte de a scrie. Nicio subclasa a celor doua clase nu exista
|
||||
in arbore, deci niciun override nu poate sari peste hook.
|
||||
|
||||
### Modificari — algoritm
|
||||
|
||||
**Pasul 0 — pozitionare in hook.** Verificarea se aseaza sub acelasi `IF m.llRet` ca avertizarea
|
||||
existenta (`:13165`) si **dupa** `SELECT tact` / `SET FILTER TO` de la inceputul procedurii
|
||||
(`:5001-5005`, `:13131-13135`). Altfel apare peste dialogul de eroare de la
|
||||
`verificare_note_contabile`, sau filtrul gridului ii ascunde randuri.
|
||||
|
||||
Ordinea dialogurilor la o singura apasare de Salvare: `verificare_note_contabile` -> avertizarea
|
||||
4426-4428 -> avertizarea noua. Prima semnaleaza o greseala facuta, a doua o omisiune.
|
||||
|
||||
**Pasul 0.5 — kill-switch.** Optiune implicit pornita. Daca e oprita: nicio avertizare, nicio
|
||||
interogare, in tot produsul. L1/L2 stau deja in spatele `RC_ANAF_VERIF_SELECTIE`; L3 intra pe drumul
|
||||
de salvare al intregii suite si nu are voie sa fie fara oprire.
|
||||
|
||||
**Mecanismul — CORECTAT 28.07.2026.** NU se folosesc `Optiuni_FIRMA`/`Optiuni_PROGRAM.dbf` din
|
||||
`DATE\`: acele tabele exista pe disc, dar nu sunt calea folosita si nu apar deloc in cod. Modelul de
|
||||
urmat este chiar `RC_ANAF_VERIF_SELECTIE`, care are trei straturi (`ocautare.prg:255-285`, `:341-381`):
|
||||
|
||||
1. kill-switch INI: `getini(gcGeneralIniFile, 'anaf', 'verificare_selectie')`, doar `'0'` opreste;
|
||||
2. optiuni Oracle (`optiuni` / `optiuni_util`), citite cu `citeste_optiune` /
|
||||
`citeste_optiune_utilizator` din `oinit_optiuni.prg`, cu cache intr-o `Collection`;
|
||||
3. UI = intrare de meniu (`Meniuri\CONT2000.MPR:210`, `ON SELECTION BAR ... DO ANAF_ComutaVerificare`),
|
||||
nu ecran cu campuri DBF.
|
||||
|
||||
**Pasul 0.6 — flag de lot.** Apelantii care instantiaza formularul in bucla seteaza un flag public
|
||||
"rulez in lot", iar verificarea se sare. `anaf_efactura.vc2:12733` instantiaza `frm_modific2024`
|
||||
**per factura importata**: un import de 150 de facturi ar insemna 150 de `AMESSAGEBOX` succesive
|
||||
plus 150 de interogari Oracle sincrone. Acelasi lucru la `:12940` si `comun.vc2:2436`.
|
||||
|
||||
**Pasul 1 — colectare.** Din `tact`, id-urile `id_factd` / `id_factc` > 0. Daca nu exista niciunul:
|
||||
nimic, cost zero, fara interogare Oracle.
|
||||
|
||||
**Pasul 2 — suprimarea platilor deja acoperite.**
|
||||
|
||||
Regula: exista in `tact` o linie cu `tipnota = 1` SI `id_fact = <id>`.
|
||||
|
||||
Citirea lui `tipnota` se face prin `TYPE('tact.tipnota') = 'N'`, ca la `:4752` si `:12847` —
|
||||
`tact` e construit de apelant, posibil din alt produs ROA.
|
||||
|
||||
**Santinela `-5` NU intra in regula.** `do_adauga_tva_exigibil` scrie `-5` numai cand id-ul
|
||||
facturii nu se poate rezolva (`:12531`, `:12542`, `:12551`, `:12559`), iar comentariul din cod spune
|
||||
ce inseamna: "pun -5 ... ca sa-i completez id_fact la scrie_in_act" — adica **"de completat la
|
||||
scriere"**, nu "rezolvat". Pentru liniile colectate la pasul 1 (`id_factd`/`id_factc` > 0) codul
|
||||
scrie intotdeauna id-ul real, deci `-5` e imposibil prin constructie pe multimea urmarita. In
|
||||
schimb, o disjunctie `SAU id_fact = -5` nu ar fi conditionata de id: o singura linie cu `-5`
|
||||
oriunde in `tact` ar stinge avertizarea pentru TOATE platile din lot, tacut.
|
||||
|
||||
Calificarea pe `tipnota = 1` se pastreaza: fara ea, excluderea ar prinde si notele MANUALE
|
||||
`4426=4428` — exact cele despre care avertizarea existenta de la `:13165` spune ca sunt probabil
|
||||
gresite.
|
||||
|
||||
> Nota de reconciliere: o decizie intermediara a review-ului (D23) ceruse mutarea cheii de pe
|
||||
> `tipnota` pe perechea de conturi, pe motiv ca notele generate de `inchidere_tva_sold` au
|
||||
> `tipnota = 0` (`oproceduri_inchidere.prg:884`). Motivul a cazut: acel drum nu ajunge niciodata la
|
||||
> regula, pentru ca `INSERT INTO actactan` (`:848-854`) nu completeaza `id_factd`/`id_factc`, deci
|
||||
> pasul 1 nu colecteaza nimic. Cheia ramane pe `tipnota`, fara `-5`.
|
||||
|
||||
**Pasul 3 — interogarea, fara lista IN.**
|
||||
|
||||
O singura interogare `goExecutor`, care intoarce `id_fact`-urile cu `tva_incasare = 1` si sold
|
||||
neexigibil `<> 0`. **Intersectia cu `tact` se face local, in VFP.**
|
||||
|
||||
**Sursa — CORECTATA 28.07.2026.** Interogarea NU se poate scrie peste `jc2007` + `jv2007`:
|
||||
**coloana `tva_incasare` nu exista pe cele doua tabele** (verificat pe `USER_TAB_COLUMNS`). Ea sta pe
|
||||
`DOCUMENTE` (`id_doc = id_fact`) si pe view-urile `VJC2025` / `VJV2025`. Se interogheaza view-urile:
|
||||
au deja tot ce trebuie (cotele, `tva_incasare`, `an`/`luna`, `id_fact`) si sunt exact ce foloseste
|
||||
deja `pack_contab.cauta_facturaTVAEx`. Cele 14 coloane de cota de mai jos exista, in schimb, si pe
|
||||
`jc2007`/`jv2007` — verificat.
|
||||
|
||||
Nu se construieste lista `IN (...)`. Pragul Oracle de 1000 (ORA-01795) se atinge la utilizare
|
||||
normala, nu la 10x: acelasi formular deserveste, dupa propriul caption, "Import extrase bancare,
|
||||
deconturi curieri, procesatori plati" (`anaf_efactura.vc2:12941`), iar imperecherea se face linie cu
|
||||
linie (`oproceduri_import.prg:729, 755, 782, 808`). Un extras obisnuit are 300-2000 linii/luna; un
|
||||
decont de procesator, mult mai mult. Un singur SQL de lungime fixa elimina o clasa intreaga de esec
|
||||
de pe drumul de salvare al intregii suite.
|
||||
|
||||
**Formula de sold neexigibil** — NU se copiaza din registru. Filtrul existent la
|
||||
`Clase\ovanzcump.vc2:38011` foloseste
|
||||
`ro24nb+ro24nt+ro20nb+ro20nt+ro19nb+ro19nt+ro9nb+ro9nt+ro5nb+ro5nt`, care OMITE cotele 21% si 11%,
|
||||
in vigoare din august 2025 (`RO21NB/RO21NT/RO11NB/RO11NT`, id-uri 214/215,
|
||||
`2025\07\ff_2025_07_21_01_COMUN_TVA21.sql:134-140`). Cu formula copiata, avertizarea nu s-ar
|
||||
declansa NICIODATA pe o factura din 2025 incoace — exact pe facturile pentru care a fost ceruta.
|
||||
|
||||
Lista corecta:
|
||||
```
|
||||
ro24nb+ro24nt+ro20nb+ro20nt+ro21nb+ro21nt+ro11nb+ro11nt+ro19nb+ro19nt+ro9nb+ro9nt+ro5nb+ro5nt
|
||||
```
|
||||
|
||||
**Robustete.** Verificarea ruleaza doar dupa ce `verificare_note_contabile` a trecut si doar cu
|
||||
conexiune valida. Orice esec (tabela inexistenta in alt produs ROA, conexiune cazuta, timeout) ->
|
||||
**se sare, cu linie in `goLog`**. Niciodata tacut: o verificare care moare invizibil e mai rea decat
|
||||
una absenta, pentru ca nimeni nu afla ca nu mai merge. Esecul nu blocheaza salvarea.
|
||||
|
||||
**Cum se obtine asta — PRECIZAT 28.07.2026, dupa citirea clasei.** `oexecutor` e in
|
||||
`COMUN\programe\oproceduri_comune.prg:69-547`. Comportamentul real:
|
||||
|
||||
- `oExecute()` NU arunca eroare VFP pe SQL esuat: intoarce `CT_INSUCCES` (-1). Deci nu urca la
|
||||
`ON ERROR` global. `goLog.Log` se apeleaza pe toate drumurile de esec. Pana aici, cerinta e
|
||||
indeplinita din oficiu.
|
||||
- **DAR** pe eroare ODBC de conexiune cazuta (cod 1526 cu subcod 12152/3113/3114/12560/4068/28/12 —
|
||||
exact cazul numit mai sus) se deschide un `amessagebox` "Doriti reconectare?"
|
||||
(`oproceduri_comune.prg:390`) NECONDITIONAT de `tlShowError`, iar raspunsul "Nu" duce la `QUIT` —
|
||||
**inchide aplicatia**, in mijlocul salvarii. Exact opusul cerintei.
|
||||
- Deci apelul TREBUIE facut cu reconectarea dezactivata explicit. **Nu exista precedent**: din 150+
|
||||
apeluri `oExecute`/`oExecuta` din codebase, niciunul nu trece de 2 parametri. Tiparul se scrie
|
||||
aici prima oara — de verificat pozitia exacta a parametrului in semnatura inainte de a-l folosi.
|
||||
- Se foloseste `oExecute`, NU `oExecuta` (aceasta din urma afiseaza mesaj propriu, neconditionat, pe
|
||||
orice esec). Nu se adauga niciun `amessagebox` propriu.
|
||||
- Nu exista niciun timeout Oracle configurat (`SQLSETPROP QueryTimeout`/`ConnectTimeout`) nicaieri:
|
||||
un query agatat blocheaza la nesfarsit, nu doar da eroare. De avut in vedere la testare.
|
||||
|
||||
**Pasul 4 — dialogul.**
|
||||
|
||||
Trei butoane:
|
||||
|
||||
```
|
||||
Exista <N> plati/incasari pe facturi cu TVA la incasare pentru care nu s-a adaugat
|
||||
nota de TVA exigibilizat.
|
||||
|
||||
[Adauga acum] [Continua] [Anuleaza]
|
||||
```
|
||||
|
||||
- **Adauga acum** — ruleaza `do_adauga_tva_exigibil` pe liniile deja identificate de interogare,
|
||||
apoi continua salvarea.
|
||||
- **Continua** — salveaza fara exigibilizare.
|
||||
- **Anuleaza** — `Return .F.`, ramane in formular fara sa salveze.
|
||||
|
||||
De ce buton si nu instructiune: sistemul stie deja care plati au nevoie de exigibilizare — asta e
|
||||
chiar interogarea de la pasul 3. O modala care spune "du-te si apasa un buton" ar fi fost
|
||||
inexecutabila in doua feluri: captionul difera intre cele doua clase (`:2643` vs `:6923`), iar
|
||||
`Command5.Enabled` se calculeaza dupa **randul curent** (`:5661-5667`, `:13850`) si `cmdSelect.Click`
|
||||
nu il recalculeaza — deci butonul poate fi gri exact dupa "Selecteaza tot".
|
||||
|
||||
`<N>` — de fixat inainte de implementare daca numara facturi distincte sau linii din `tact`.
|
||||
|
||||
**Pasul 5 — flag anti-bucla.**
|
||||
|
||||
Proprietate de formular `lAvertizatExigibilizare`, setata dupa prima avertizare; a doua oara in
|
||||
aceeasi sesiune de formular nu se mai avertizeaza.
|
||||
|
||||
Motiv: cand `chkTVAEX` e bifat si linia e plata/incasare, `do_adauga_tva_exigibil` cheama
|
||||
`creeaza_note_tva_incasare` (`:12598-12600`), unde `id_fact` vine din cursorul intors de
|
||||
`pack_contab.defalca_tva_incasare` (`:12412`, `a.id_fact As id_fact`). Daca procedura nu intoarce
|
||||
randuri, nu se insereaza nimic potrivit -> suprimarea nu prinde niciodata -> avertizare -> buton ->
|
||||
avertizare -> buton (**dubland notele generate**) -> avertizare, fara iesire in afara de "Continua".
|
||||
Ca "zero randuri" e un caz real: `oproceduri_inchidere.prg:843-848` il trateaza explicit.
|
||||
|
||||
### Acoperire — drumuri de instantiere
|
||||
|
||||
`frm_modific2007` / `frm_modific2024` sunt instantiate din: `ocont2003.prg:416, 1230, 1679, 2141`;
|
||||
`oproceduri_incasari.prg:299`; `frm_import_extrase_banca.sc2:1652`;
|
||||
`anaf_efactura.vc2:12733, 12940`; `frm_initializare_facturi_balanta.sc2:1803`; `comun.vc2:2436`;
|
||||
`oproceduri_inchidere.prg:719, 902, 1007, 1438`; `frm_import_note_a4200.sc2:1651`;
|
||||
`frm_import_note_facturi_clienti.sc2:895`; `ooperatii_comune.prg:1137`.
|
||||
|
||||
Premisa "prinde si casa, si banca, si notele manuale" TINE.
|
||||
|
||||
> Nota de metoda: `COMUN/` e in `.gitignore`, deci Grep/ripgrep il sare implicit. Cautarile de tip
|
||||
> "cine apeleaza" se fac cu `rg --no-ignore` sau cu cale explicita, altfel intorc zero fals.
|
||||
|
||||
---
|
||||
|
||||
# NU intra in scop (amanat, cu motiv)
|
||||
|
||||
**Defectele din drumul de exigibilizare din meniu** (`inchidere_tva_sold`). De adaugat in TODOS.md
|
||||
cu descrierea de mai jos, care **inlocuieste** formularea anterioara — aceea descria un defect
|
||||
inexistent si ar fi trimis pe cine preia lucrarea catre o harta gresita.
|
||||
|
||||
Ce este de fapt:
|
||||
|
||||
1. `oproceduri_inchidere.prg:833` testeaza `Iif(m.lnCota = 21, m.lnSuma21, m.lnSuma11)` intr-o bucla
|
||||
`For lnCota = 1 To 7` (`:829`). `lnCota` nu ajunge niciodata 21, deci `lnSuma21` e cod mort, iar
|
||||
la `lnCota = 6` se ia soldul de 11% cu cota 1.21 (`:834`). Linia vecina `:837` o face corect
|
||||
(`Iif(m.lnCota = 6, m.lnSuma21T, ...)`). Este o greseala de tipar `6` -> `21`.
|
||||
2. `:802-803` citesc `soldn21` / `soldn11` neconditionat din `crsTVAIncasareTemp`. Aliasurile sunt
|
||||
emise doar de formele 2025 (`ovanzcump.vc2:44220-44225`, `:55069-55073`). Pe formele 2010
|
||||
(`:39660`, `:51403`) nu exista -> eroare VFP 12, modala, la apasarea butonului. Exigibilizarea
|
||||
din registru e rupta pe perioadele anterioare lui 2025.
|
||||
3. `lnSuma21`, `lnSuma11`, `lnSuma20`, `lnSuma19` lipsesc din lista `Local` (`:770-773`) — devin
|
||||
PRIVATE si se scurg in stiva de apel.
|
||||
|
||||
Ce NU este: `ovanzcump.vc2:39660` nu "pierde 24/20"; e forma 2010, folosita pe perioade < 2025, al
|
||||
carei cursor sursa `vjc2010`/`vjc2013` nu are deloc coloanele `ro21*`/`ro11*` (`oproceduri_decont.prg:18795-18801`),
|
||||
deci acolo omisiunea e corecta.
|
||||
|
||||
Nu afecteaza L3: butonul catre care trimite avertizarea L3 este `do_adauga_tva_exigibil`, care nu
|
||||
foloseste nicio lista de cote. Sunt doua butoane diferite, pe doua drumuri diferite.
|
||||
|
||||
**De scris in nota de release:** pe o factura cu TVA la incasare 21%, L3 avertizeaza corect, dar
|
||||
utilizatorul care merge pe drumul din meniu (registru -> exigibilizare) gaseste lista goala. Butonul
|
||||
din formular functioneaza.
|
||||
|
||||
Alte lucruri amanate:
|
||||
- Istoricul complet al atributului de TVA (mai multe perioade). ANAF v9 intoarce o singura perioada.
|
||||
- Al doilea apel ANAF la data curenta ("era platitor la data documentului, dar nu mai este azi").
|
||||
- Persistarea totalului cu TVA de taxare inversa pe randul din `anaf_efactura` la import: nu ar
|
||||
acoperi facturile deja importate; view-ul repara si istoricul.
|
||||
- Derivarea listelor de cote din `jtva_coloane` in loc de enumerare in mai multe locuri. E cauza
|
||||
radacina a defectelor gasite la L3 si L4.
|
||||
|
||||
---
|
||||
|
||||
# Ce exista deja (si se reutilizeaza)
|
||||
|
||||
| Sub-problema | Cod existent | Se reutilizeaza? |
|
||||
|---|---|---|
|
||||
| Perioada TVA de la ANAF | `ParseJsonANAFv8`, `validare.prg:2001-2114` | Da, integral. Se propaga, nu se parseaza din nou |
|
||||
| Detectia discordantei ROA vs ANAF | `lDiscordanta`, `ocautare.prg:143` | Da. Nu se scrie detectie noua |
|
||||
| Cache de sesiune | `goCacheANAF_Sesiune`, `ocautare.prg:127`, `:130` | Da, nemodificat |
|
||||
| Validare CNP / CIF | `VALIDARE_CNP` / `VALIDARE_CIF`, apelate prin `ANAF_ValidareCod` la `:594` | Da, integral |
|
||||
| Generarea notelor de exigibilizare | `do_adauga_tva_exigibil`, `omodificari.vc2:12483+` | Da (rulat din butonul dialogului) |
|
||||
| Tiparul de avertizare in `inainte_de_do_termin` | `omodificari.vc2:13165-13176` | Da, se copiaza forma |
|
||||
| Lista canonica de coloane TVA taxare inversa | `oproceduri_decont.prg:8670` | Da, se preia ca atare |
|
||||
|
||||
---
|
||||
|
||||
# Reguli de livrare
|
||||
|
||||
- Fiecare transa livreaza `docs\diff_runda<N>_<subiect>.patch`; write-back in binar
|
||||
(`txt2vcx.ps1`) si commit DOAR dupa aprobare. Patch-urile nu se comit.
|
||||
- Comentarii: o singura intrare cumulativa in antetul fisierului, `*!* DD.MM.YYYY` /
|
||||
`*!* marius.mutu` / 1-2 fraze. Fara comentarii in corpul codului. La L2 (corectie de eroare) nu se
|
||||
adauga comentariu.
|
||||
- `ocautare.prg`, `validare.prg` si `omodificari.vc2` contin octeti cp1252 (0xBA). Orice scriere cu
|
||||
Edit/Write ii corupe in `EF BF BD`. Se editeaza TOT ce e de editat, si abia DUPA ultima scriere se
|
||||
verifica byte-level si se repara o singura data, luand octetul corect din `svn cat`.
|
||||
- Scripturile `.sql` din SCRIPTURI_CLAR se scriu cu **CRLF**.
|
||||
- `changelog_roacont.txt`: cate o intrare scurta per transa. L1/L3/L4 = `:nou:` sau `:modificare:`;
|
||||
L2 = `:eroare:` (mesajul fals a ajuns la utilizatori).
|
||||
|
||||
---
|
||||
|
||||
# Ce ramane neverificat
|
||||
|
||||
Stare la 28.07.2026, dupa verificarea pe date (schema dev `MARIUSM_AUTO`). Detalii in
|
||||
`docs\handoff_transa2_conditii.md`, `handoff_transa3_conditii.md`, `handoff_transa3_deschise.md`.
|
||||
|
||||
- ~~Comportamentul `goExecutor` la timeout / conexiune cazuta~~ — INCHIS, vezi "Robustete" mai sus.
|
||||
- ~~Daca `pack_contab.defalca_tva_incasare` poate intoarce `id_fact` null/0~~ — INCHIS. `id_fact` in
|
||||
cursor e mereu parametrul trimis, deci nu poate fi null. Zero randuri ESTE posibil (filtrul final
|
||||
poate exclude tot), si e chiar garantat pe drumul `omodificari.vc2:12547-12561`, unde santinela
|
||||
`-5` ajunge ca parametru la `defalca_tva_incasare(-5, ...)`. **Flagul anti-bucla de la Pasul 5 e
|
||||
confirmat necesar, nu preventiv.**
|
||||
- ~~Cotele 21/11 in `pack_contab`~~ — INCHIS. `defalca_tva_incasare` deleaga la
|
||||
`creeaza_note_tva_incasare`, care are `DECODE` explicit pe `id_jtva_coloana` 211/215 (JC) si 38/42
|
||||
(JV) pentru `RO21*`/`RO11*`; `cauta_facturaTVAEx` filtreaza si el pe `RO21NT`/`RO11NT`.
|
||||
**Conditia de intrare a transei 3 e indeplinita.**
|
||||
- Numarul real de linii pe un decont de curier/procesator — RAMANE DESCHIS pe cifra. Schema dev nu
|
||||
are date reprezentative (`DECONT`: 2 randuri in toata baza; `EXTRAS CON`: p95 ~10 linii/lot, cu un
|
||||
ordin de marime sub estimarea din plan, dar pe loturi de test, nu activitate reala). **Nu schimba
|
||||
decizia**: o interogare unica de lungime fixa elimina `ORA-01795` indiferent de volum, deci nu
|
||||
exista prag sub care lista `IN(...)` ar fi de preferat.
|
||||
- Trasarea cap-coada a unei facturi cu linie `AE` (transa 2) — RAMANE DESCHISA pe date reale.
|
||||
In schema dev NU exista nicio factura venita din import eFactura cu taxare inversa (`anaf_efactura`:
|
||||
487 randuri primite, 8 cu `id_fact`, zero suprapunere cu randuri `TI*` nenule). Mecanismul a fost
|
||||
demonstrat numeric doar pe un caz construit din `jc2007` (`id_fact=8007136`, `ti19bft=19`,
|
||||
`totctva=119`: diferenta falsa de -19 se anuleaza exact cu `jtva_ti`). **De consemnat in nota de
|
||||
release**: verificarea finala ramane de facut pe prima factura reala de taxare inversa importata
|
||||
dupa aplicarea scriptului.
|
||||
|
||||
---
|
||||
---
|
||||
|
||||
# ANEXA — istoricul review-ului
|
||||
|
||||
Nimic de implementat aici. Se pastreaza pentru trasabilitate.
|
||||
|
||||
## Metoda
|
||||
|
||||
Doua runde: `/autoplan` (CEO -> Design -> Eng) pe 27.07, apoi runda 2 cu trei voci independente
|
||||
(subagenti fara context de review) confruntate cu verificare proprie pe cod. Codex indisponibil pe
|
||||
masina, deci consensul e "voce independenta + verificare proprie", nu Claude/Codex. Faza DX sarita:
|
||||
produsul nu e pentru dezvoltatori.
|
||||
|
||||
## Afirmatii verificate pe cod
|
||||
|
||||
CONFIRMATE: `ParseJsonANAFv8` pune datele in cursor (`validare.prg:2012`); `ANAF_VerdictDinCursor`
|
||||
expune doar 5 campuri (`:1670-1675`); cache-ul pastreaza obiectul intreg (`ocautare.prg:127`,
|
||||
`:130`); `tact` poarta campurile necesare (`omodificari.vc2:4496`, `:5661`, `:13166`); precedentul
|
||||
de avertizare (`:13165-13172`); un singur SELECT pentru ambele view-uri (`import_efactura.prg:40`);
|
||||
coloanele `TI21T`=217, `TI11T`=219, `XX19TIB`=192, `XX19TIT`=193; `lb_anaf` multi-rand
|
||||
(`ocautare.prg:472-476`); localizarea defectului L2 in `Detalii` (`:648-650`, `:803`);
|
||||
`Return .F.` opreste salvarea (`_frm_base.vc2`, `do_termin`).
|
||||
|
||||
INFIRMATE: tipul coloanelor de perioada era declarat incert — sunt deja `D`; `mesaj` NU e
|
||||
echivalent cu `mesaj_ScpTVA` (V(100) vs C(244)); santinela `-5` inseamna "de completat la scriere",
|
||||
nu "rezolvat"; capcana `inchidere_tva_sold` e evitata prin `id_factd`/`id_factc` necompletate, nu
|
||||
prin `tipnota`; defectul de cote amanat era descris gresit.
|
||||
|
||||
## Decizii
|
||||
|
||||
D1-D21 (runda 1, `/autoplan`): mod SELECTIVE EXPANSION; lista de coloane `TI*`+`XX*TI*`; coloana in
|
||||
ambele view-uri; conditie de intrare prin trasare cap-coada; lista de cote cu 21/11; defect
|
||||
preexistent semnalat nu reparat; texte distincte pentru sfarsit vs anulare; log pe parsare esuata;
|
||||
eliminarea ramurilor inaccesibile din L2; corectarea localizarii defectului L2; data lipita de
|
||||
stare; banda multi-rand; interval pentru perioada inchisa; `Pemstatus`; defectul L2 mai larg
|
||||
(`:600`); banda neutra pentru CNP; regula de suprimare pe `tipnota`; `jtva_ti` coloana vizibila;
|
||||
fara a treia culoare; ordinea DB-inainte-de-exe.
|
||||
|
||||
D22-D33 (runda 2): N1 `mesaj_ScpTVA` in loc de `mesaj` (rastoarna D7); N2/N3/N4/N5/N6/N7;
|
||||
`4+32+256`; conditie de intrare pe `pack_contab`; rescrierea textului amanarii.
|
||||
|
||||
D34-D37 (poarta, marius.mutu): trei livrari separate, fixurile N7 raman amanate cu text rescris;
|
||||
L3 cu buton de actiune in dialog; L4 fara coloana vizibila; L1 cu data si la `lDiscordanta`.
|
||||
|
||||
Contradictie rezolvata la consolidare: D23 (cheia de suprimare pe perechea de conturi) cade in
|
||||
favoarea E.2 (`tipnota = 1 AND id_fact`, fara `-5`) — motivul lui D23 a disparut odata cu E.3.
|
||||
|
||||
Deciziile D36 si D37 au dizolvat trei constatari: N5, K-1 si N6 nu mai au obiect fara coloana
|
||||
vizibila; N3 si N4 nu mai au obiect cu butonul in dialog.
|
||||
|
||||
## Teme transversale
|
||||
|
||||
**Tema 1 — "corect pe hartie, inexecutabil de utilizator".** Trei constatari independente (caption
|
||||
diferit, buton conditionat de randul curent, coloana invizibila din cauza preferintelor de grid) au
|
||||
avut aceeasi forma. Toate trei au fost eliminate prin deciziile de la poarta.
|
||||
|
||||
**Tema 2 — planul verifica listele de cote in VFP si nu deschide niciun pachet Oracle.** De aici
|
||||
conditia de intrare pe `pack_contab` pentru transa 3.
|
||||
Reference in New Issue
Block a user