sync SVN r18077
This commit is contained in:
245
docs/cercetare/rec_d42_efactura.md
Normal file
245
docs/cercetare/rec_d42_efactura.md
Normal file
@@ -0,0 +1,245 @@
|
||||
# Implementarea deciziei 42 — articole needitabile pe factura trimisa in eFactura
|
||||
|
||||
Scris 10.08.2026. Implementare + testare + write-back verificat. **ZERO commit** (git/svn),
|
||||
conform interdictiei primite.
|
||||
|
||||
> ## COMPLETARE, 10.08.2026 ora ~12:55 — discountul de antet intra sub garda
|
||||
>
|
||||
> Agentul care a scris acest raport a apucat sa faca **modificarea de cod si write-back-ul**, apoi a
|
||||
> cazut pe limita de sesiune **inainte de verificare**. Blocul de mai jos e scris de orchestrator,
|
||||
> care a preluat si a dus verificarea la capat.
|
||||
>
|
||||
> **Decizia lui Marius**: `txtDiscountArt` (discountul de antet) **se blocheaza si el** cand documentul
|
||||
> e trimis in eFactura — schimba totalurile unui document deja depus la ANAF, chiar daca nu atinge
|
||||
> nicio linie.
|
||||
>
|
||||
> **Codul**: `omodificari.vc2:14813` — `This.pgfArticole.PAGE3.txtDiscountArt.ReadOnly =
|
||||
> This.lArticoleReadOnly`, prin acelasi flag, fara mecanism nou.
|
||||
>
|
||||
> **A doua cale de scriere — cautata si exclusa**: `txtDiscountArt.Valid` (`:16592`) doar cheama
|
||||
> `Thisform.ActualizeazaBaraTotaluri()`, deci **recalculeaza afisajul, nu scrie discountul nicaieri**.
|
||||
> Nu exista buton sau apel programatic care sa-l seteze ocolind caseta, deci garda dubla care a fost
|
||||
> necesara la butoanele de articole (`Click`) **nu isi are rostul aici**. Salvarea propriu-zisa trimite
|
||||
> discountul ca parametru catre `recalculeaza_totaluri_vanzari` (decizia 41), luand valoarea din caseta.
|
||||
>
|
||||
> **Verificat de orchestrator pe disc, dupa caderea agentului**:
|
||||
> - **Write-back complet**, dovedit prin reconversie binar -> text in cache temporar si comparatie
|
||||
> **octet cu octet**: identic, 540712 octeti. Cens de octeti `2 aa . 2 e3 . 2 fe`, zero `EF BF BD`.
|
||||
> - **Regresia rerulata integral pe starea de pe disc**, dupa write-back (binar 12:33:09):
|
||||
> `test_page3_articole` **14/2** (artefactul headless cunoscut), `test_adauga_linie_articol` **20/0**,
|
||||
> `test_adauga_linie_valuta` **16/0**, `test_ui_sterge_linie` **8/0**, `test_verdict_act_rul` **26/0**,
|
||||
> `test_incarca_vanzare_din_nota` **5/0**, `test_s5_validari_articole` **35/0**. Nicio regresie.
|
||||
> - **Acoperire noua**: `test_efactura_readonly.prg` extins cu doua asertii si rerulat —
|
||||
> **23 PASS / 0 FAIL** (de la 21). Cele doua noi: `caz A: txtDiscountArt.ReadOnly = .T.` pe documentul
|
||||
> real trimis in eFactura, si `caz B: txtDiscountArt.ReadOnly = .F. (neregresat)` pe cel netrimis.
|
||||
> Garda e verificata deci **in ambele sensuri**, nu doar pe cazul pozitiv.
|
||||
> - Zero procese `vfp9.exe` ramase, zero commituri.
|
||||
>
|
||||
> **Ce NU e acoperit**: suita UI vizibila (`test_ui_efactura_readonly.prg`, 14/0) **nu a fost rerulata**
|
||||
> dupa adaugarea discountului — ea verifica `.When`-urile de celula, neatinse de aceasta completare,
|
||||
> deci riscul e mic, dar golul e declarat, nu ascuns.
|
||||
>
|
||||
> Diff-ul consolidat (COMUN + ROAGEST) e regenerat in diff aplicat (sters).
|
||||
|
||||
## Ce s-a schimbat, si unde
|
||||
|
||||
### `COMUN\clase\omodificari.vc2` (`frm_modific2024`)
|
||||
|
||||
- **Proprietate noua** `lArticoleReadOnly` (Boolean, implicit `.F.`): `*p:` la `:6827`, valoare
|
||||
implicita la `:6866`.
|
||||
- **`Show`** (`:14788-14827`): calculeaza flagul in acelasi bloc unde se determina
|
||||
`lAreArticoleVanzari`/`nIdVanzare`/`nTipVanzare` (adica doar cand `ofacturare_editare.prg` e
|
||||
incarcat si documentul are rand in `VANZARI`):
|
||||
`This.lArticoleReadOnly = EsteInEFactura(Nvl(tvanz.id_fact,0))` (`:14798`). In blocul care
|
||||
pregateste `PAGE3`, aplica flagul: `cmdAdaugaArticol.Enabled`/`cmdStergeArticol.Enabled` =
|
||||
`!lArticoleReadOnly` (`:14811-14812`), `lblArticoleReadOnly.Visible = lArticoleReadOnly`
|
||||
(`:14813`). **`PAGE3` continua sa se pregateasca si sa se afiseze normal** —
|
||||
`PregatesteArticoleFacturaEditare`/`PageCount=3`/`grdArticoleFactura.Refresh()` raman neatinse,
|
||||
conform corectiei explicite a lui Marius (articolele raman vizibile).
|
||||
- **Control nou** `pgfArticole.PAGE3.lblArticoleReadOnly` (`ADD OBJECT` la `:12776`): eticheta
|
||||
discreta, `Visible=.F.` implicit, pozitionata pe randul butoanelor (`Top=4`, `Left=360`,
|
||||
`Width=390`) — la dreapta lui `cmdAdaugaArticol` (care se termina la `Left+Width=345`), deci
|
||||
**nu ia spatiu din grid** (gridul ramane la `Top=26`). Text: „Articole needitabile - factura
|
||||
trimisa in eFactura", `ForeColor RGB(180,120,0)` (aceeasi nuanta de atentionare folosita deja
|
||||
la verdictul ACT/RUL divergent).
|
||||
- **Garda pe butoane** (`cmdAdaugaArticol.Click` `:16488`, `cmdStergeArticol.Click` `:16531`):
|
||||
`OR Thisform.lArticoleReadOnly` adaugat la conditia de `RETURN` timpuriu — belt-and-suspenders
|
||||
fata de `Enabled=.F.`, pentru ca `Enabled` nu blocheaza un apel programatic al metodei `.Click()`.
|
||||
- **Garda pe celule** — cele patru `.When` care controleaza editabilitatea pe rand (mecanismul
|
||||
din S5): `cCantitateArt.Text1.When` (`:16549`), `cPretAchizitieArt.Text1.When`,
|
||||
`cPretArt.Text1.When` (`:16570`), `cPretCuTvaArt._checkbox1.When` (`:16587`) — toate primesc
|
||||
`Thisform.lArticoleReadOnly OR ...` (respectiv `!Thisform.lArticoleReadOnly AND ...` pe
|
||||
checkbox, unde conditia veche era inversa). Se construieste **peste** mecanismul de
|
||||
editabilitate per rand din S5 (`id_vanzare_set`/`id_vanzare_det`), nu-l inlocuieste.
|
||||
- **Notele/rulajele nu sunt atinse**: `Grid1` (nota contabila), `grdRulaje`/`grdRulajeObinv`
|
||||
(paginile 1/2) raman complet neschimbate — verificat explicit in test (`Grid1.ReadOnly` ramane
|
||||
`.F.` pe documentul din eFactura).
|
||||
|
||||
### `COMUN\programe\ofacturare_editare.prg`
|
||||
|
||||
Corectie necesara descoperita in timpul lucrului (vezi mai jos „Decizie/corectie luata pe
|
||||
parcurs"): `EsteInEFactura` se apeleaza cu `VANZARI.ID_FACT`, **nu** cu `id_vanzare` — sunt doua
|
||||
coloane distincte (verificat pe date: 0 potriviri `id_fact = id_vanzare` din 142 facturi tip=1).
|
||||
Contractul existent (`ofacturare_comun.vc2:3764`, neatins) apela deja `EsteInEFactura(lnIdFact)`
|
||||
cu `lnIdFact = crsfacturi.id_fact`. `tvanz` (populat de `IncarcaVanzareNota`) nu avea aceasta
|
||||
coloana.
|
||||
|
||||
- `CreeazaCursorTvanzGol` (linia 153 din fisier): adaugat `id_fact I NULL` la structura cursorului
|
||||
gol (fallback pe eroare Oracle/cod lipsa).
|
||||
- `IncarcaVanzareNota` (linia 177): adaugat `v.id_fact` la lista de coloane selectate din
|
||||
`VANZARI`. Restul interogarii (join, filtre) neatins.
|
||||
- Antetul fisierului (o singura intrare cumulativa, rescrisa): data actualizata la 10.08.2026,
|
||||
mentiunea `id_fact` adaugata la lista de campuri incarcate.
|
||||
|
||||
## Decizie/corectie luata pe parcurs — de raportat, nu era in briefing
|
||||
|
||||
Implementarea initiala folosea `EsteInEFactura(This.nIdVanzare)` (adica `id_vanzare`). Verificare
|
||||
pe `MARIUSM_AUTO`:
|
||||
|
||||
```sql
|
||||
SELECT COUNT(*) total, SUM(CASE WHEN id_fact = id_vanzare THEN 1 ELSE 0 END) equal_cnt
|
||||
FROM vanzari WHERE tip = 1 AND sters = 0;
|
||||
-- 142 total, 0 equal_cnt
|
||||
```
|
||||
|
||||
`id_fact` si `id_vanzare` sunt spatii de ID complet diferite (`id_fact` are valori de forma
|
||||
`8008013`, `id_vanzare` valori mici de forma `1013`) — cu `id_vanzare` gardarea nu s-ar fi
|
||||
declansat NICIODATA in productie (nicio coincidenta intamplatoare intre cele doua plaje). Corectat
|
||||
inainte de scrierea testelor, folosind exact coloana pe care o foloseste deja calea din
|
||||
`ofacturare_comun.vc2:3764` (`lnIdFact = crsfacturi.id_fact`).
|
||||
|
||||
## Write-back — verificat prin reconversie + diff, nu pe mtime
|
||||
|
||||
`txt2vcx.ps1 -AllowComun` rulat de trei ori (prima incercare a picat fidelity-check-ul din cauza
|
||||
ordinii gresite a blocului `ADD OBJECT` — proprietatile/obiectele dintr-o clasa `.vcx` trebuie in
|
||||
ordine STRICT alfabetica dupa nume, nu dupa ZOrder; a doua rulare a picat pentru ca lipsea
|
||||
corectia `id_fact`; **a treia rulare, OK**, fidelity check trecut).
|
||||
|
||||
Verificare **independenta** de fidelity-check-ul intern al `txt2vcx.ps1`: reconversie separata a
|
||||
binarului proaspat scris (`vcx2txt.ps1 -Source omodificari.vcx` intr-un cache temporar izolat) +
|
||||
`diff`/`cmp` octet cu octet fata de `.vc2`-ul din proiect:
|
||||
|
||||
```
|
||||
diff -q omodificari.vc2 <reconversie>/omodificari.vc2 -> IDENTIC
|
||||
cmp omodificari.vc2 <reconversie>/omodificari.vc2 -> BYTE-IDENTIC
|
||||
```
|
||||
|
||||
Text si binar sunt sincrone, dovedit, nu presupus.
|
||||
|
||||
## Cens de octeti (regula cp1250) — inainte/dupa, identic cu baseline
|
||||
|
||||
`omodificari.vc2` are diacritice cp1250 preexistente (tooltip-uri „Renunțare/Adăugare/Ștergere",
|
||||
octeti `0xFE`/`0xE3`/`0xAA`). **Baseline: `2 aa / 2 e3 / 2 fe`, zero `EF BF BD`.**
|
||||
|
||||
Editarea celor doua proprietati noi (`*p:`/`*<PropValue>`) s-a facut initial cu tool-ul `Edit`
|
||||
(2 apeluri) — asta a **stricat** censul (`6 ef / 6 bf / 6 bd`, adica `EF BF BD` x2 aparitii x3
|
||||
octeti), exact capcana documentata (`Edit`/`Write` re-encodeaza tot fisierul la orice scriere,
|
||||
indiferent cat de mica). **Reparat** inainte de a continua: octetii corecti (`Renun[FE]are`,
|
||||
`Ad[E3]ugare`, `[AA]tergere`) preluati din `git cat-file blob HEAD:clase/omodificari.vc2`
|
||||
(varianta necorupta, comisa) si inlocuiti inapoi punctual. Toate editarile ulterioare (Show(),
|
||||
garzile pe butoane/celule, blocul `ADD OBJECT` al etichetei noi) s-au facut **pe octeti**, cu
|
||||
Perl (`<:raw`/`>:raw`, cautare/inlocuire literala `\Q...\E`, fara nicio decodare de encoding),
|
||||
tocmai ca sa nu se repete problema. **Cens final: `2 aa / 2 e3 / 2 fe`, zero `EF BF BD`** —
|
||||
identic cu baseline, verificat dupa fiecare grup de editari.
|
||||
|
||||
`ofacturare_editare.prg` nu are octeti `>=0x80` (cens gol inainte si dupa) — editat direct cu
|
||||
`Edit`, fara risc.
|
||||
|
||||
## Regresie — cifre numarate din loguri, toate DUPA ultima editare de cod
|
||||
|
||||
Ultima editare de cod: `omodificari.vc2` scris in binar la `11:37:23` (a treia rulare
|
||||
`txt2vcx.ps1`, cu corectia `id_fact`); `ofacturare_editare.prg` editat inainte de asta. Toate
|
||||
rularile de mai jos sunt **dupa** acel moment.
|
||||
|
||||
| Suita | Rezultat | Baseline | Stare |
|
||||
|---|---|---|---|
|
||||
| `test_page3_articole.prg` | 14 PASS / 2 FAIL | 14/2 | **neregresat** (cele 2 FAIL = artefactul headless cunoscut, ColumnCount/ReadOnly pe grid needitabil sub `-A -T`) |
|
||||
| `test_adauga_linie_articol.prg` | 20 PASS / 0 FAIL | 20/0 | **neregresat** |
|
||||
| `test_adauga_linie_valuta.prg` | 16 PASS / 0 FAIL | 16/0 | **neregresat** |
|
||||
| `test_ui_sterge_linie.prg` | 8 PASS / 0 FAIL | 8/0 | **neregresat** |
|
||||
| `test_verdict_act_rul.prg` | 26 PASS / 0 FAIL | 26/0 | **neregresat** |
|
||||
| `test_incarca_vanzare_din_nota.prg` | 5 PASS / 0 FAIL | 5/0 | **neregresat** |
|
||||
| `test_s5_validari_articole.prg` | 35 PASS / 0 FAIL | 35/0 | **neregresat** (linia care contine cuvantul "FAIL" e text descriptiv al unei ramuri moarte deja documentate, nu un esec real — `REZULTAT: 35 PASS / 0 FAIL`) |
|
||||
|
||||
Zero regresii pe toate cele sapte suite existente.
|
||||
|
||||
## Suite noi
|
||||
|
||||
### `COMUN\utile\Teste\editare_factura\test_efactura_readonly.prg` (headless) — **21 PASS / 0 FAIL**
|
||||
|
||||
Documente REALE, gasite prin interogare (nu inventate):
|
||||
- **Caz A — trimis in eFactura**: `id_vanzare=1013` (`cod=1140509`, an=2025, luna=8),
|
||||
`VANZARI.ID_FACT=8008013`, prezent in `ANAF_EFACTURA`.
|
||||
- **Caz B — NEtrimis** (regresie): descoperit prin proprietate (`DescoperaCazTest`,
|
||||
`FACTURA_ARTICOLE`), `cod=1140895` (id_vanzare=1050, documentul deja folosit de restul suitei).
|
||||
|
||||
Acopera: `EsteInEFactura` direct (cu `0` si cu `8008013`); `lArticoleReadOnly` corect pe ambele
|
||||
cazuri; **`PAGE3` NU e suprimata** (`PageCount=3`, `RecordSource` neschimbat, `tvd` cu linii);
|
||||
`cmdAdaugaArticol`/`cmdStergeArticol.Enabled`; vizibilitatea etichetei; garda pe
|
||||
`cmdStergeArticol.Click()` (apelat direct, fara dialog modal — confirma ca linia nu se modifica
|
||||
pe documentul din eFactura si ca se modifica normal pe cel obisnuit); `Grid1.ReadOnly` neatins
|
||||
(nota ramane editabila). Nu scrie in Oracle.
|
||||
|
||||
**Ce nu acopera** (documentat explicit in fisier, nu ascuns): editabilitatea per-celula
|
||||
(`.When()` pe coloanele gridului) — coloanele **nu se materializeaza sub `-A -T`**
|
||||
(`ColumnCount=0`, eroare 1925 „Unknown member" la accesul pe nume), artefact cunoscut si
|
||||
documentat (`grid-coloane-nu-se-materializeaza-headless`). Mutat in suita UI de mai jos.
|
||||
|
||||
### `COMUN\utile\Teste\editare_factura\test_ui_efactura_readonly.prg` (UI vizibil) — **14 PASS / 0 FAIL**
|
||||
|
||||
Rulat prin harnessul corect (`vfp_ui_harness.ps1 -TestPrg ... -Steps @(...) -SyncDir ...`), nu
|
||||
prin lansare directa — o incercare initiala prin `Start-Process` direct a dat tot `ColumnCount=0`;
|
||||
cauza reala **nu era lansarea**, ci lipsa apelului `IncarcaArticoleFactura(1013,
|
||||
'crsArticoleFactura')` **inainte** de `Createobject` — gridul se leaga o singura data, la
|
||||
construire (in `Load()`), pe cursorul `tvd` existent atunci; fara precarcare, `Load()` creeaza
|
||||
`tvd` GOL, iar fallback-ul din `Show()` il **recreeaza prin SQL** dupa constructie — cursor diferit
|
||||
de cel pe care s-a legat gridul, deci `ColumnCount` ramane 0. Corectat dupa tiparul deja folosit de
|
||||
`test_ui_s5_grid_pret_achizitie.prg`.
|
||||
|
||||
Acopera, pe acelasi document real (`id_vanzare=1013`, in eFactura): gridul are 15 coloane
|
||||
(neregresat); `.When()` pe toate cele patru controale (`cCantitateArt`, `cPretArt`,
|
||||
`cPretAchizitieArt`, `cPretCuTvaArt._checkbox1`) intorc `.F.` — **needitabile pe orice linie
|
||||
normala, nu doar pe liniile din set**; caz sintetic de control (`lArticoleReadOnly` comutat manual
|
||||
pe `.F.` pe acelasi document/aceleasi obiecte) — cele trei celule redevin editabile, deci gating-ul
|
||||
e demonstrat pe flag, nu pe o coincidenta a documentului ales. Captura:
|
||||
`screenshots_efactura\step_0_grid_efactura_readonly.png`. Nu scrie in Oracle.
|
||||
|
||||
## Ce NU s-a putut testa, si de ce
|
||||
|
||||
- **Dialogul de adaugare articol** (`frm_articol_factura`, `Show(1)` modal): garda de pe
|
||||
`cmdAdaugaArticol.Click()` (Enabled=.F. + guard in cod) nu s-a putut exercita prin click real
|
||||
headless — consecvent cu limitarea deja documentata pe restul suitei S4/S5 (dialog modal). Doar
|
||||
`Enabled=.F.` verificat direct.
|
||||
- **Ramura moarta preexistenta, gasita dar NEATINSA** (nu in scope): linia
|
||||
`IF !Used('tvd') OR !This.lAreArticoleVanzari OR Thisform.lArticoleReadOnly` din
|
||||
`cmdAdaugaArticol.Click` (`:16497`) foloseste `This.lAreArticoleVanzari` — `This` acolo e
|
||||
butonul, nu formularul, deci proprietatea nu exista pe el. Ramane neexecutata in practica pentru
|
||||
ca `!Used('tvd')` e `.F.` de fiecare data cand butonul chiar e vizibil (short-circuit VFP), deci
|
||||
runtime-ul nu ajunge niciodata sa evalueze operandul gresit. Preexistenta editarii mele
|
||||
(adaugarea mea e doar `OR Thisform.lArticoleReadOnly`, corect scris cu `Thisform`), nu se
|
||||
repara aici — in afara scope-ului deciziei 42.
|
||||
- **Verificarea vizuala pe ecran de Marius**: eticheta discreta, pozitionarea ei fata de butoane,
|
||||
culoarea, comportamentul real la click de mouse pe grid.
|
||||
|
||||
## Stare finala verificata
|
||||
|
||||
- **Write-back facut si dovedit** pentru `omodificari.vc2` (reconversie + diff octet cu octet,
|
||||
identic). `ofacturare_editare.prg` e `.prg` — sursa directa, fara pas de write-back.
|
||||
- Cens de octeti pe `omodificari.vc2`: **`2 aa / 2 e3 / 2 fe`, zero `EF BF BD`** — identic cu
|
||||
baseline, verificat dupa ultima editare.
|
||||
- Zero procese `vfp9.exe` ramase (verificat cu `tasklist`) dupa toate rularile mele. Procesul
|
||||
`vfp9.exe` al agentului `s8-creare-variante` (fereastra „S8 - creare documente") a ramas
|
||||
intact, neatins.
|
||||
- Zero scrieri in Oracle in toata sesiunea — toate interogarile (`EsteInEFactura`,
|
||||
`IncarcaCursoareModificareNota`, `IncarcaVanzareNota`, `IncarcaArticoleFactura`) sunt `SELECT`.
|
||||
- Zero commit (git/svn).
|
||||
- Diff consolidat: diff aplicat (sters) (ambele fisiere).
|
||||
- Fisiere noi, necomise: `COMUN\utile\Teste\editare_factura\test_efactura_readonly.prg` (+ log),
|
||||
`COMUN\utile\Teste\editare_factura\test_ui_efactura_readonly.prg` (+ log + screenshot in
|
||||
`screenshots_efactura\`).
|
||||
|
||||
## Interzis — respectat
|
||||
|
||||
`ofacturare.vc2`, `ofacturare_comun.vc2`, `comun.vc2`: neatinse (verificat — niciun `Edit`/`Write`
|
||||
pe ele in aceasta lucrare). `actualizeaza_vanzari`, `PACK_CONTAFIN`, `PACK_FACTURARE`: neatinse.
|
||||
Niciun `INSERT`/`UPDATE` pe `id_vanzare` `1049`/`1050`/`1048`.
|
||||
Reference in New Issue
Block a user