docs: cercetarile comune trec in COMUN, reziduul #6 dispare, progres.md la zi

Curatenie ceruta dupa inchiderea lui #6. Folderul cercetare\ NU se putea sterge
in bloc: plan_13 se sprijina pe el cu 85 de trimiteri, deci e baza de dovezi a
planului aflat in lucru. Impartirea:

- 14 cercetari trans-proiect trec in COMUN\docs\cercetare\ - valuta si curs,
  TVA/VANZARI, consumatorii VANZARI din toata suita, integrarile #10/#11/#12,
  watchdog VFP, proiectarea Oracle a lui S5, view-ul VVANZARI_ARTICOLE. Nu sunt
  ale ROAFACTURARE, iar #10/#11/#12 se reiau chiar din ele.
- 20 de rapoarte de executie ale lui #6, nereferite de nimic viu, sterse.
- 91 raman, neatinse.

Trimiterile catre handoff-urile si diff-urile intermediare deja desfiintate au
fost curatate peste tot (39 de fisiere): 50 catre handoff-uri, 37 catre diff-uri
aplicate, plus caile celor mutate in COMUN. Zero trimiteri rupte ramase.

progres.md preia rolul de predare: ce ramane din #6 (cele sase documente
parazite, cele doua esecuri reale din S8 pe factura din aviz), cifrele de test
citite din log, si cele doua capcane de mediu platite - .FXP vechi executat in
locul .prg-ului, si GETFONT() care atarna un formular instantiat fara goApp.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
This commit is contained in:
2026-08-11 22:31:42 +03:00
parent fc9c3780df
commit b5a7108f34
73 changed files with 227 additions and 6757 deletions

View File

@@ -1,6 +1,6 @@
# Briefing — S5, testul cu scriere reala in Oracle
Misiune pentru un agent proaspat. Se citeste **impreuna cu** `docs\handoff_s5.md` (starea blocului) si
Misiune pentru un agent proaspat. Se citeste **impreuna cu** handoff intermediar (sters) (starea blocului) si
`COMUN\docs\reguli_lucru.md` (regulile de livrare si testare). Nu relua cercetarea — e facuta.
## De ce exista acest test
@@ -66,7 +66,7 @@ linia finala a suitei (`REZULTAT` sau `done`, dupa tipar).
## Aprobare si costuri
**Scrierea reala e aprobata de Marius** (09.08.2026), aprobarea e consemnata in `handoff_s5.md`.
**Scrierea reala e aprobata de Marius** (09.08.2026), aprobarea e consemnata in handoff intermediar (sters).
**Consuma date de test ireversibil**: `cod`-ul documentului se realoca la fiecare salvare (la testul
precedent, `1140886 -> 1140893 -> 1140894`). Alege un document de test, **nu** unul folosit ca baza de
regresie de alte suite daca poti evita, si **consemneaza in raport `cod`-urile consumate**.
@@ -88,7 +88,7 @@ regresie de alte suite daca poti evita, si **consemneaza in raport `cod`-urile c
1. `COMUN\utile\Teste\editare_factura\test_s5_scriere_reala.prg` — suita.
2. `D:\ROA\ROAFACTURARE\docs\cercetare\rec_s5_scriere_reala.md` — raportul: ce s-a dovedit, ce nu,
`SELECT`-urile de verificare cu rezultatele lor, `cod`-urile consumate, cifrele din loguri.
3. `D:\ROA\ROAFACTURARE\docs\diff_s5_test_scriere_reala.patch` — diff-ul.
3. diff aplicat (sters) — diff-ul.
Raspunsul catre orchestrator e **scurt**: „GATA" + cifrele + ce nu s-a dovedit. **Nu trimite raportul
in text** — el sta pe disc.
@@ -96,6 +96,6 @@ in text** — el sta pe disc.
## Predarea contextului (REGULA ZERO)
Daca ajungi la **~200-250k** context: **opreste-te**, adu tot la o stare consistenta pe disc, scrie
`D:\ROA\ROAFACTURARE\docs\handoff_s5_scriere_reala.md` cu **starea** (ce e facut, ce nu, ce e
handoff intermediar (sters) cu **starea** (ce e facut, ce nu, ce e
periculos: tranzactie deschisa, proces viu, date consumate), si anunta. Nu continua „ca mai e putin" —
si **nu lasa niciodata o tranzactie deschisa** in Oracle.

View File

@@ -1,128 +0,0 @@
# Contul inregistrat pe o linie de vanzare, cu/fara politica de pret
**Raspuns scurt**: nu exista, nicaieri in codul cercetat (VFP `ofacturare*` + Oracle
`pack_facturare`), un "cont de venit" (707/704/706/708) legat de linia de factura. Singurul cont
propagat pe linie e coloana `CONT` din `VANZARI_DETALII`/`VANZARI_DETALII_TEMP` (varchar 4
caractere) — si aceasta e contul de **gestiune/stoc** (371 marfuri, 301-303 materii prime, 357
custodie etc.), folosit pentru descarcarea de gestiune, nu un cont de venit. El **nu vine din
politica de pret** (`CRM_POLITICI_PRET_ART` nu are coloana `CONT` — verificat, nicio
`CREATE`/`ALTER TABLE CRM_POLITICI_PRET_ART ADD CONT` in `D:\ROA\DATABASE\SCRIPTURI_CLAR`), ci din
nomenclatorul de articole si din lotul de stoc ales. Asta inseamna ca "adaugarea directa din
nomenclator, fara politica de pret" **nu schimba mecanismul de completare a acestui camp** — el
oricum nu depinde de politica azi. Ramane neverificat unde/daca se decide efectiv un cont de venit
707/704/706/708 pentru nota contabila (nu e in `pack_facturare`).
## 1. Unde e stocat / de unde se ia campul `CONT`
- **Tabel/coloana tinta**: `VANZARI_DETALII_TEMP.CONT` si `VANZARI_DETALII.CONT`, populate prin
`pack_facturare.adauga_articol_factura` / `_deviz` / `_stoc`
(`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:4690,4711,4735` / `:4761,4792,4814` /
`:5013,5247,5277`).
- **Sursa 1 — `NOM_ARTICOLE.CONT`** (prin view `vnom_articole`/`vnom_articole_crm`): coloana `a.cont`
e adusa in grila de cautare a articolelor, `COMUN\programe\ocautare.prg:1671,1683,1687` (`caut_articol`,
folosit de formularul unificat de facturare la alegerea articolului). Confirmata ca fiind pe
`NOM_ARTICOLE` prin `alter table NOM_ARTICOLE add ... A.CONT ...` (`D:\ROA\DATABASE\SCRIPTURI_CLAR\2019\12\ff_2019_12_20_02_COMUN.sql:12`, coloana veche, prezenta din 2009-2010).
- **Sursa 2 — `STOC.CONT`** (contul de pe lotul de stoc): `pack_facturare.cursor_gestiuni_articol`
(`ff_...:4358-4452`) — `SELECT ... A.CONT ... FROM STOC A2 ...` — folosit cand articolul e
**gestionabil** si se alege un lot din stoc (`frm_facturare_articole.do_alege_stoc`,
`COMUN\clase\ofacturare.vc2:13239-13345`, care seteaza `poArticol.Cont = Alltrim(Cont)` la
`:13345` din cursorul intors de Oracle).
- **Sursa 3 — `NOM_GESTIUNI.CONT`**: fallback cand nu exista lot de stoc, vezi punctul 2
(`cursor_gestiuni_articol_stoc0`).
- **Politica de pret** (`CRM_POLITICI_PRET_ART`): are `PRET`, `PROC_TVAV`, `ID_VALUTA`,
`PRETFTVA` (vazute in `adauga_articol_factura`, declaratiile `V_PRET`, `V_PROC_TVAV` etc. la
`ff_...:5033-5036`) — **nicio coloana de cont**. Cautarea in `SCRIPTURI_CLAR` pentru
`ALTER TABLE CRM_POLITICI_PRET_ART ADD ... CONT` nu a gasit nimic.
- Nu exista `CONT_VENIT`/`ID_CONT_VENIT`/`COD_CONT` nicaieri in
`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql` (grep pe fisierul intreg, 17020 linii — zero
potriviri) si nici in `NOM_ARTICOLE`/`CRM_POLITICI_PRET_ART` (cautat in `SCRIPTURI_CLAR`).
## 2. Cum se decide efectiv la scriere — `cursor_gestiuni_articol` / `_stoc0`
Cand articolul e gestionabil si exista stoc, `cursor_gestiuni_articol` (`ff_...:4358-4452`) ia
contul direct de pe lotul de stoc:
```
SELECT 0 AS ALES, A.ID_GESTIUNE, A.CANTITATE, A.CONT, ...
FROM (SELECT ... A2.CONT, ... FROM STOC A2 ...) A
LEFT JOIN NOM_GESTIUNI B ON A.ID_GESTIUNE = B.ID_GESTIUNE
```
— `A.CONT` = `STOC.CONT`, fara nicio alta sursa, fara fallback (daca lotul de stoc are `CONT`
`NULL`, ramane `NULL`).
Cand articolul e gestionabil dar **nu exista stoc** (optiunea `RF_FACTURARE_FARA_STOC = 1`),
`cursor_gestiuni_articol_stoc0` (`ff_...:4459-4558`) foloseste un lant `NVL2` explicit
(`ff_...:4472-4473`):
```sql
CAST(NVL2(B.CONT, B.CONT, NVL2(A.CONT, A.CONT, '371')) AS VARCHAR2(4)) AS CONT,
```
unde `B` = `NOM_GESTIUNI` (contul implicit al gestiunii) si `A.CONT` = ultimul cont vazut in
`STOC` pentru articol (an curent/precedent). Ordinea reala: **cont gestiune -> ultimul cont din
stoc -> `'371'` hardcodat**. Acesta e singurul loc din pachet cu un `COALESCE`/`NVL2` in cascada
pe `CONT`, si singurul cu un default hardcodat.
`adauga_articol_factura` (varianta apelata din `frm_facturare_articole.do_scrie_articole`, params
la `ff_...:4998-5024`) **nu recalculeaza** contul — il primeste ca parametru `V_CONT` si il scrie
ca atare (`V_CONT2 := V_CONT` daca `V_CONT <> 'XXXX'`, altfel ramane `NULL` — `ff_...:5044-5046`,
`V_CONT2` la INSERT `ff_...:5277`). `'XXXX'` e sentinela VFP pentru "fara valoare" — vezi
`COMUN\clase\ofacturare.vc2:6963,7123,7992` (`poDateGestiuneDest.Cont = Nvl(loCauta.Cont,[XXXX])`).
Aceeasi logica de trecere directa, fara recalcul, e in `adauga_articol_factura_deviz`
(`ff_...:4675-4745`, `V_CONT` scris direct in `CONT`, fara sentinela `'XXXX'`, fara `NVL`).
## 3. Precedent ROAAUTO — "Alte servicii" (articol din nomenclator brut, fara politica de pret)
Cursorul `lcCursorDeviz` (`ROAAUTO\Programe\oproceduri_devize.prg:880-887`) **nu are coloana
`Cont`**. `crsvanztemp` are `Cont c(4)` (`:1190-1192`) dar `INSERT INTO crsvanztemp(...)` de la
`:1201-1206` **nu o include** in lista de coloane si nici in `SELECT`-ul sursa — ramane la
valoarea implicita de camp caracter needatat, adica blank. La apel:
```
['] + Alltrim(Nvl(poArticol.Cont,'')) + [',] + ... -- oproceduri_devize.prg:1256
```
trimite un literal `''` (gol) catre `adauga_articol_factura_deviz(..., V_CONT IN NUMBER, ...)`
(`ff_...:4690`). Un literal `''` convertit implicit la `NUMBER` devine `NULL` in Oracle; `V_CONT`
ajunge `NULL` si e scris direct in `VANZARI_DETALII_TEMP.CONT` (`ff_...:4735`), fara `NVL`, fara
fallback. **Concluzie**: liniile "Alte servicii" din ROAAUTO (articol real, fara politica de pret,
pret tastat manual — vezi `roaauto_articole_lista_preturi.md`) ajung cu `CONT = NULL` in Oracle.
Nu exista in cod niciun raspuns explicit "cont pentru articol fara politica" — rezultatul e pur si
simplu absenta valorii, nu o valoare calculata.
## 4. Gestionabile vs. negestionabile
Difera **calea**, nu neaparat sursa initiala:
- **Gestionabil** (`poArticol.gestionabil <> 0`): `frm_facturare_articole.do_adauga_articol`
(`COMUN\clase\ofacturare.vc2:12871-12896`) cere alegerea unui lot/gestiune prin `do_alege_stoc`,
care suprascrie `poArticol.Cont` cu valoarea din `cursor_gestiuni_articol[_stoc0]` (punctul 2) —
deci `STOC.CONT`/`NOM_GESTIUNI.CONT`, nu `NOM_ARTICOLE.CONT`.
- **Negestionabil** (`poArticol.gestionabil = 0`) sau `gnScadereStoc = 0`: se instantiaza
`frm_articol_factura` direct (`:12871-12880`), fara trecere prin `do_alege_stoc` — `poArticol.Cont`
ramane cel citit initial la cautarea articolului, adica `NOM_ARTICOLE.CONT` (punctul 1, sursa 1),
neschimbat.
## 5. Ce se intampla daca nu se gaseste niciun cont
- Nicio exceptie/`RAISE_APPLICATION_ERROR` legata de `CONT` in tot pachetul (spre deosebire de
cota de TVA, unde lipsa produce explicit `FACT-012`/`FACT-013`/`FACT-018`,
`ff_...:5151-5153,5184-5187,5203-5206`).
- **Gestionabil, cu stoc**: `CONT` = `STOC.CONT`; daca acesta e `NULL` in stoc, ramane `NULL` —
fara fallback (punctul 2, `cursor_gestiuni_articol`).
- **Gestionabil, fara stoc** (`RF_FACTURARE_FARA_STOC=1`): fallback pana la `'371'` hardcodat
(punctul 2, `cursor_gestiuni_articol_stoc0`).
- **Negestionabil / articol adaugat fara trecere prin gestiune** (inclusiv "Alte servicii" ROAAUTO):
`CONT` ramane ce a venit din `NOM_ARTICOLE.CONT`; daca e gol, `Nvl(poArt.Cont,'')` -> `''` ->
`NULL` in Oracle (`adauga_articol_factura`, sentinela `'XXXX'` la `ff_...:5044-5046`) — linie
scrisa **fara cont**, fara eroare.
## Neverificat
- Unde (daca undeva) se determina un **cont de venit propriu-zis** (707/704/706/708) pentru nota
contabila a vanzarii — nu e in `pack_facturare`; grep pentru `707`/`704`/`706`/`708` in
`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql` si in `ROAFACTURARE\Programe`/`COMUN\programe\ofacturare_comun.prg`
nu a gasit nimic. Probabil intr-un pachet de contabilitate/note contabile separat, neinclus in
scriptul analizat — ar necesita identificarea acelui pachet (posibil in ROACONT sau un
`pack_contabilitate`/`pack_note_ct`) si urmarirea generarii notei contabile din `VANZARI`/`VANZARI_DETALII`.
- Continutul exact al coloanei `NOM_ARTICOLE.CONT` pentru articole de tip "serviciu" (daca e
populata cu conturi de cheltuiala/productie 6xx/3xx sau lasata goala) — ar necesita o interogare
pe schema Oracle live, in afara bugetului acestei cercetari (doar cod static disponibil).
- Rolul exact al `ID_VENCHELT`/`NOM_VENIT_CHELTUIELI` (parametru la nivel de `ACT`/factura, vazut
la `ff_...:191,1885` si in `initializeaza_date_factura`) — pare o clasificare
venituri/cheltuieli la nivel de document, nu un cont de venit per linie; nu am urmarit
consumatorul lui pana la capat (posibil in raportare, nu in inregistrarea contabila).

View File

@@ -59,7 +59,7 @@ directa `contabilizeaza_articol` in `proceduri_acnpro.prg`: zero rezultate). Not
documentului ACN o scrie **`pack_acn.salveaza_regdoc`**, o procedura complet separata, specifica ACN,
apelata cu parametri proprii (`?.id_articol, ?.id_locatia, ?.id_valuta, ?.id_client, ?.id_contract,
?.pret, ?.curs, ?.cantitate, ?.valval, ?.tvaval, ?.totval, ...`) — **fara `id_pol`** in lista de
parametri. Confirmat si de raportul deja existent `docs\cercetare\import_roris_roaacnpro.md`
parametri. Confirmat si de raportul deja existent `COMUN\docs\cercetare\import_roris_roaacnpro.md`
(sectiunea 3): "**nicio procedura Oracle stocata (`pack_*`) nu e apelata in etapa de import** ...
acestea sunt apelate abia la salvarea finala", si articolele/preturile vin din dialoage de calcul tarife
proprii ACN (`frm_calcul_tranzit`, `vctr_articole2`), nu din `CRM_POLITICI_PRET_ART`.

View File

@@ -1,164 +0,0 @@
# Investigatie: discount pe articol (linie de factura) — ROAFACTURARE
Intrebare: discountul pe articol e azi doar procentual, sau exista si discount in valoare
absoluta pe unitate / pe linie?
## 1. Model de date — DISCOUNT / DISCOUNT_UNITAR
**Concluzie**: Exista deja o coloana de discount **in valoare absoluta pe unitate**
(`DISCOUNT_UNITAR`) pe `VANZARI_DETALII` (si pe `VANZARI_DETALII_TEMP`, tabela de lucru din care
se compune factura), pe langa discountul de document `VANZARI.DISCOUNT` (valoare absoluta
rezultata dintr-un procent aplicat la baza, nu procent stocat). Exista si un flag boolean
`VANZARI.DISCOUNT_EVIDENTIAT`.
**Dovezi**:
- Tip coloana: `alter table VANZARI_DETALII modify discount_unitar NUMBER(22,6);` /
`alter table VANZARI_DETALII_TEMP modify discount_unitar NUMBER(22,6);` /
`alter table CRM_POLITICI_PRET_ART modify discount_unitar NUMBER(22,6);` —
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2024\06\ff_2024_06_13_02_COMUN_FACTURARE.sql:3,9,16`. Precizia
`(22,6)` e cea folosita la coloane de pret/valoare, nu la procente.
- Exista si la nivel de politica de pret (`CRM_POLITICI_PRET_ART.DISCOUNT_UNITAR`), deci
discountul unitar poate proveni din politica de pret a clientului, nu doar tastat pe linie.
- Coloana e folosita direct ca scadere din pret: `A.PRET - NVL(A.DISCOUNT_UNITAR, 0) AS PRET` —
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql:3315,3500`.
- Document-level: `v.discount as disc_fara_tva` / `v.discount_evidentiat` —
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2011\08\ff_2011_08_30_02_FACTURARE.sql:36-42,251-252,267,291`.
Discountul document e o valoare (lei/valuta), calculata din procent tastat de operator x baza
(vezi punctul 3), nu un procent stocat pe `VANZARI`.
## 2. VFP — grid-uri de linii factura (`frm_facturare_articole` si `frm_facturare_articole2`)
**Concluzie**: Ambele forme au coloane de grid pentru discountul unitar **in valoare absoluta**,
cu etichete explicite "Discount unitar cu TVA" / "Discount unitar in valuta fara TVA". In
`frm_facturare_articole` (forma standard) aceste coloane sunt read-only in grid (afisare, nu
editare directa pe linie); in `frm_facturare_articole2` (forma "noua", optionala) sunt editabile
si exista in plus o coloana de **procent pe linie** ("Procent discount", legata de campul
`procdisc`).
**Dovezi**:
- `frm_facturare_articole`: `Column5.ControlSource = "discountctva"`, `Column5.Name =
"cDiscountCTva"`, `Column5.ReadOnly = .T.` si `Column9.ControlSource = "vdiscountftva"`,
`Column9.Name = "cVdiscountftva"` (fara `ReadOnly`, deci editabil implicit) —
`D:\ROA\ROAFACTURARE\COMUN\clase\ofacturare.vc2:12311-12317, 12340-12345`. Header-e:
`Caption = "Discount unitar cu TVA"` (`:12409`), `Caption = "Discount unitar in valuta fara
TVA"` (`:12546`).
- `frm_facturare_articole2`: `Column5.Name = "cDiscountCTva", Column5.ReadOnly = .F.`
(`:16656-16657`), `Column9.Name = "cVdiscountftva", Column9.ReadOnly = .F.` (`:16687-16688`),
plus `Column14.ControlSource = "procdisc"`, `Column14.Name = "cProcentDiscount"`,
`Column14.Format = "RK"`, `Column14.InputMask = "99 999.99"`, `Column14.ReadOnly = .F.`
(`:16720-16727`), header `Caption = "Procent discount"` (`:16934-16940`).
- Vizibilitate conditionata: nu de `poDate.tip` direct, ci de `poDate.in_valuta` —
`If poDate.in_valuta = 0 ... RemoveObject([cVdiscountftva]) ... Else ...
RemoveObject([cDiscountctva])` — `ofacturare.vc2:15269-15278` (pattern analog si la `:19065`
pentru `frm_facturare_articole2`).
- `frm_facturare_articole2` e optionala, activata prin `gnFacturareNou = 1` cu un dialog Da/Nu
("Facturare noua (DA) sau standard (NU)?") — `COMUN\programe\ofacturare.prg:87-93`, instantiata
la `:929` (`lcObject = [frm_facturare_articole2]`).
## 3. Calculul + `discount_evidentiat`
**Concluzie**: `DISCOUNT_UNITAR` se scade direct din pretul unitar **fara TVA**, in valuta
documentului, inainte de a se aplica TVA-ul, apoi se inmulteste cu cantitatea. Flagul
`DISCOUNT_EVIDENTIAT` schimba doar mecanismul aritmetic (scade discountul din valoarea deja
calculata vs. din pretul unitar rotunjit), nu semantica — discountul ramane o valoare absoluta pe
unitate in ambele ramuri. In VFP, checkbox-ul corespunzator e etichetat "Se pune in evidenta
discount-ul pe articole in notele contabile si pe factura" — adica discountul e afisat separat pe
document/nota contabila vs. absorbit tacit in pret.
**Dovezi** (`FUNCTION calculeaza_total_fara_tva_fact`,
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql:15794-15847`):
```
IF V_DISCOUNT_EVIDENTIAT = 1 THEN
V_SUMA_FARA_TVA := ROUND((ROUND(curs*PRET,...) - DIFERENTA)*CANTITATE,...)
- ROUND(ROUND(curs*NVL(DISCOUNT_UNITAR,0),...)*CANTITATE,...)
ELSE
V_SUMA_FARA_TVA := ROUND((ROUND(curs*ROUND(PRET,...),...)
- ROUND(curs*ROUND(NVL(DISCOUNT_UNITAR,0),...),...) - DIFERENTA)*CANTITATE,...)
```
Aceeasi structura simetrica in `calculeaza_total_tva_fact` (`:15899-15944`). In VFP, sinteza
corespunzatoare: `valdiminuatftva WITH poArticol.pretftva - NVL(poArticol.discount_unitar,0)` —
`ofacturare.vc2:13126`, conversia cu-TVA: `discount_unitar_ctva =
discount_unitar*(proc_tvav-1) + discount_unitar` — `:13635-13636`. Checkbox:
`ADD OBJECT 'ck_discountevidentiat' AS _checkbox WITH ... Caption = "Se pune in evidenta
discount-ul pe articole in notele contabile si pe factura", ControlSource =
"poDate.discount_evidentiat"` — `:11300-11305`.
## 4. Oracle — parametrii `adauga_articol_factura`
**Concluzie**: procedura primeste discountul ca parametru numeric absolut
`V_DISCOUNT_UNITAR IN NUMBER` si il scrie direct in `VANZARI_DETALII_TEMP.DISCOUNT_UNITAR`, fara
nicio transformare procent->valoare. Discountul de document (`VANZARI.discount`) e separat,
aplicat/gestionat la alt nivel (agregare pe factura, cf. `do_calculeaza_discount` in VFP).
**Dovezi**: semnatura completa
`PROCEDURE adauga_articol_factura(V_ID_TEMP IN NUMBER, ... V_CANTITATE IN NUMBER,
V_DISCOUNT_UNITAR IN NUMBER, V_CONT IN VARCHAR2, ...)` —
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql:4972-4998`,
parametrul `V_DISCOUNT_UNITAR` la linia `4986`;
`INSERT INTO VANZARI_DETALII_TEMP (... DISCOUNT_UNITAR ...) VALUES (... V_DISCOUNT_UNITAR ...)` —
`:5219, 5249`.
## 5. Discount unitar in valoare absoluta — exista deja in suita
**Concluzie**: Da, exista deja in toata suita ROA — nu doar "conceptual", ci implementat si
cablat de la Oracle pana la grid. `COMUN\clase\ofacturare.vc2` (fisierul verificat pentru
ROAFACTURARE) e literalmente acelasi fisier partajat cu
`D:\ROA\ROAGEST\COMUN\clase\ofacturare.vc2` si `D:\ROA\ROAACNPRO\COMUN\clase\ofacturare.vc2`
(confirmat prin grep pe ambele arbore), la fel `pack_facturare`. Nu a fost nevoie de o cautare
separata in alt produs — e literalmente acelasi cod, aceeasi coloana.
**Dovezi**: `discount_unitar`/`discountunitar` apare identic in
`D:\ROA\ROAGEST\COMUN\clase\ofacturare.vc2`, `D:\ROA\ROAGEST\COMUN\clase\ofacturare_comun.vc2`,
`D:\ROA\ROAGEST\COMUN\programe\ofacturare*.prg`, `D:\ROA\ROAACNPRO\COMUN\clase\ofacturare.vc2` si
`D:\ROA\ROAACNPRO\COMUN\clase\ofacturare_comun.vc2`; SQL-uri de discount identice (ex.
`v.discount as disc_fara_tva`) gasite si in
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2021\02\ff_2021_02_03_01_VANZARI.sql:19-20,259-260,409-410,
481-482,612`.
## 6. Ce ar presupune un discount unitar in valoare absoluta — inventar (nu solutie, doar puncte de atins)
- **Coloana tabela**: deja exista (`VANZARI_DETALII.DISCOUNT_UNITAR`, `NUMBER(22,6)`, plus pe
`VANZARI_DETALII_TEMP` si `CRM_POLITICI_PRET_ART`) — nimic de adaugat.
- **Parametru Oracle**: deja exista (`adauga_articol_factura(... V_DISCOUNT_UNITAR ...)`,
`ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql:4986`) — nimic de adaugat.
- **Coloana grid**: deja exista in ambele forme (`cDiscountCTva`/`cVdiscountftva`); in
`frm_facturare_articole` (forma standard, majoritara) e read-only — de decis daca se face
editabila pe linie sau ramane doar afisaj derivat din politica de pret / discountul procentual
de pe factura.
- **Intrare pentru operator**: in forma standard nu s-a gasit un punct unde operatorul tasteaza
manual `discount_unitar` per linie la adaugarea articolului — pare alimentat din
`CRM_POLITICI_PRET_ART.DISCOUNT_UNITAR` (politica de pret a clientului) sau din redistribuirea
discountului procentual de pe factura (`do_calculeaza_discount`, `ofacturare.vc2:13405-13424`).
De clarificat fluxul exact inainte de a proiecta un input nou.
- **Recalcul**: formulele Oracle (`calculeaza_total_fara_tva_fact`/`calculeaza_total_tva_fact`)
deja trateaza `DISCOUNT_UNITAR` ca valoare absoluta — nimic de schimbat aritmetic daca se
reutilizeaza calea existenta.
- **Rapoarte `.frx`**: nu s-a verificat daca discountul unitar apare pe rapoartele tiparite de
factura — necunoscut, de verificat separat.
- **eFactura / SAF-T**: nu s-a verificat daca `discount_unitar` e mapat in XML-ul UBL/eFactura sau
in declaratia SAF-T — necunoscut, de verificat separat (fisierele `COMUN_EFACTURA*.sql` /
`COMUN_SAFT*.sql` contin "discount" dar nu au fost citite).
## Raspuns scurt la intrebare
Nu doar procentual: **discountul pe articol exista deja si ca valoare absoluta pe unitate**
(`DISCOUNT_UNITAR`, `NUMBER(22,6)`), implementat capat la capat — coloana Oracle pe
`VANZARI_DETALII`/`VANZARI_DETALII_TEMP`, parametru in `pack_facturare.adauga_articol_factura`,
formule de calcul care scad direct din pret, si coloane de grid in VFP cu eticheta explicita
"Discount unitar cu TVA"/"...in valuta fara TVA". Discountul de document (`VANZARI.discount`)
ramane procentual-la-origine (tastat ca procent, stocat ca valoare calculata). Ce nu e clar e daca
operatorul poate tasta liber discountul unitar pe linie in forma standard
(`frm_facturare_articole`, unde coloana e read-only) — in forma "noua" optionala
(`frm_facturare_articole2`, `gnFacturareNou=1`) e editabila si are si un procent-pe-linie separat.
## Necunoscute ramase
- Sursa exacta a valorii `discount_unitar` la adaugarea unui articol in forma standard (politica
de pret vs. redistribuire din discountul procentual de pe factura) — nu s-a urmarit tot lantul
`do_adauga`/`crsgestarticol`.
- Daca `discount_unitar` apare pe rapoartele `.frx` tiparite.
- Daca `discount_unitar` e transmis in eFactura (UBL) sau SAF-T.
- Cat de folosita e efectiv `frm_facturare_articole2` in productie (e optionala, per sesiune, cu
prompt).

View File

@@ -1,182 +0,0 @@
# Verificare discount pe linie de factura — frm_facturare_articole / VANZARI_DETALII
Investigatie read-only. Toate liniile citate au fost verificate pe fisierul text real din working
copy (`ofacturare.vc2`, 23087 linii, ultima scriere 07.08 22:18) si pe scripturile DDL din
`D:\ROA\DATABASE\SCRIPTURI_CLAR`. Nu s-a executat nimic pe baza de date.
## 1. Confirmare/infirmare afirmatii initiale
**Concluzie**: toate afirmatiile despre `frm_facturare_articole` sunt corecte, cu linii care se
potrivesc exact sau aproape exact. Confirmat via `vfp_symbols.ps1 -Where` ca formularul
`frm_facturare_articole` ocupa exact `ofacturare.vc2:10968-15739`.
**Dovezi**:
- `Column5.ControlSource = "discountctva"`, `Column5.Name = "cDiscountCTva"`, `Column5.ReadOnly = .T.`
— confirmat la `ofacturare.vc2:12311-12317` (identic cu afirmatia).
- `Column9.ControlSource = "vdiscountftva"`, `Column9.Name = "cVdiscountftva"`, **fara** `ReadOnly`
— confirmat la `ofacturare.vc2:12340-12345` (identic).
- Capete de coloana: `Caption = "Discount unitar cu TVA"` la `:12409`, `Caption = "Discount unitar in
valuta fara TVA"` la `:12546` — ambele confirmate exact.
- Excludere reciproca pe valuta la `ofacturare.vc2:15269-15278`:
```
15269 If poDate.in_valuta = 0
15270 Thisform.grd_factura.RemoveObject([cVpretFtva])
15271 Thisform.grd_factura.RemoveObject([cVdiscountftva])
15272 Thisform.grd_factura.RemoveObject([cVvaldiminuatftva])
15273 Else
15274 Thisform.grd_factura.RemoveObject([cPretFtva])
15275 Thisform.grd_factura.RemoveObject([cDiscountctva])
```
confirmat identic (linii exacte, nu doar apropiate).
- `VANZARI_DETALII.DISCOUNT_UNITAR NUMBER(22,6)` — confirmat, dar cu precizare: linia corecta in
`ff_2024_06_13_02_COMUN_FACTURARE.sql` e `:3` (nu si `:9`/`:16` cum lasa sa se inteleaga
formularea initiala — acelea sunt `VANZARI_DETALII_TEMP` si, respectiv, `CRM_POLITICI_PRET_ART`,
vezi punctul 4).
## 2. Consecinta practica pe ecran
**Concluzie**: pe factura in lei, coloana vizibila e **"Discount unitar cu TVA"** (`discountctva`)
si e **needitabila** in grid (`ReadOnly = .T.`). Pe factura in valuta, coloana vizibila e
**"Discount unitar in valuta fara TVA"** (`vdiscountftva`) si **este editabila direct in grid**
(nicio proprietate `ReadOnly` setata pe coloana sau pe `Text1`-ul ei → mosteneste default-ul VFP,
`.F.`).
**Dovezi**:
- Ramane pe ecran: cand `in_valuta = 0` se elimina cele 3 coloane "V..." (inclusiv
`cVdiscountftva`) → ramane `cDiscountCTva`. Cand `in_valuta <> 0` se elimina `cDiscountctva` (si
celelalte 3 coloane fara "V") → ramane `cVdiscountftva`. (`:15269-15278`, citat mai sus).
- Ca sa nu presupun ca lipsa lui `Column9.ReadOnly` inseamna implicit editabil, am verificat lantul
de clase: grid-ul `grd_factura` e `ADD OBJECT 'grd_factura' AS _grdrow` (`:12263`), fara
`ReadOnly` la nivel de grid intre `:12263-12364`; clasa `_grdrow` (`_grd_base.vc2:445`) nu
seteaza `ReadOnly` nicaieri in propriul body, iar parintele ei `_grdbase`/`_grid` de asemenea nu
(singurele 3 aparitii de `ReadOnly` in `_grd_base.vc2` sunt in clasa separata `_grdfooter`,
neinrudita). Deci Column9 chiar e editabila.
- Confirmare suplimentara: in formularul **`frm_facturare_articole2`** (prototip separat, clasa la
`ofacturare.vc2:15741-19355`, NU formularul in productie), aceleasi doua coloane apar cu
`ReadOnly` explicit: `Column5.ReadOnly = .F.` (`:16657`) si `Column9.ReadOnly = .F.` (`:16688`) —
adica in prototip discountul e editabil in ambele monede direct din grid; in formularul real
doar varianta in valuta e editabila din grid.
## 3. Poate operatorul introduce azi un discount pe linie, si pe ce cale
**Concluzie**: da, poate — dar nu prin `do_calculeaza_discount` de la
`frm_facturare_articole:13405-13424` (asta calculeaza discountul **global pe toata factura**,
`Thisform.ndiscfactron`/`ndiscfactval`, nicio legatura cu `discountctva`/`vdiscountftva` pe
linie — vezi corectia de la final). Calea reala e formularul **`frm_articol_factura`**
(`ofacturare.vc2:1108-2659`), deschis din `do_adauga_articol` la adaugarea unui articol
(`:12873`, `ofrmadarticol.Show(1)` doar daca `!tlImplicit`). Acolo exista metoda
`frm_articol_factura.do_calculeaza_discount` (`:1874-1976`) legata de 3 controale editabile:
`Clb_procent_discount.Text_simplu1` (procent), `Clb_discount_unitar.tx_suma_nat`/`tx_suma_val`
(suma in lei / valuta), `Clb_discountctva.tx_suma_nat`/`tx_suma_val` (varianta cu TVA) — toate cu
handler `Valid`/`InteractiveChange` care apeleaza `do_calculeaza_discount(valoare, tip)` cu
`tip=1` procent, `tip=2` lei, `tip=3` valuta (`:2602-2624`, `:2646-2649`).
**Lantul, cu linii**:
1. Operator tasteaza in unul din campurile de mai sus → `Valid`/`InteractiveChange` →
`Thisform.do_calculeaza_discount(valoare, tip)` (`ofacturare.vc2:2602-2649`).
2. `do_calculeaza_discount` (`:1874-1976`) scrie in obiectul `poArticol`:
`poArticol.discount_unitar`, `discount_unitar_val`, `discount_unitar_ctva`,
`discount_unitar_ctva_val` (ex. `:1898-1906`, `:1943-1951`).
3. La revenirea in `do_adauga_articol` (`:12813-13086`), `poArticol` e scris in `crsfactura` prin
`Gather`/`Replace`:
```
12956 Replace id_temp With Recno(), codmat With Nvl(poArticol.codmat, Space(50)), ;
...
12957 discountftva With poArticol.discount_unitar, discountctva With poArticol.discount_unitar_ctva, ;
vdiscountftva With Nvl(poArticol.discount_unitar_val, 0), vdiscountctva With Nvl(poArticol.discount_unitar_ctva_val, 0)
```
(linii `12956-12957`; varianta pentru selectie multipla de articole la `13003-13005`).
4. `discount_unitar` initial (inainte de tastare) e preluat din `crsarticole` (cursorul de stoc,
populat inainte de deschiderea dialogului) prin `do_initializeaza_articol` (`:13618` si urm.):
`toArticol.discount_unitar = Nvl(toArticol.discount_unitar, 0)` (`:13630`) — deci daca stocul /
politica de pret vine deja cu un discount populat, acela e valoarea implicita afisata in dialog,
pe care operatorul o poate suprascrie.
5. Cale suplimentara, directa: pe factura in valuta, cum `cVdiscountftva` e editabil in grid
(punctul 2), operatorul poate scrie si direct in celula `vdiscountftva` din `grd_factura` — dar
fara niciun `Valid`/`InteractiveChange` propriu definit pentru acea coloana in
`frm_facturare_articole` (cautat explicit `cVdiscountftva`/`cDiscountCTva` in intervalul
`10968-15739`: singurele hit-uri sunt definitiile de coloana si `RemoveObject`, niciun handler
de eveniment) — editarea directa in grid NU declanseaza recalcularea automata a
`vvaldiminuatftva`/totaluri, doar modifica valoarea bruta in `crsfactura`.
## 4. Structura reala a coloanelor de discount pe VANZARI_DETALII
**Concluzie**: nu exista un `CREATE TABLE VANZARI_DETALII` in `SCRIPTURI_CLAR` (arhiva incepe din
2009, iar tabela exista deja atunci — coloana `DISCOUNT_UNITAR` era deja in uz in pachete PL/SQL
din 2009, deci a fost creata inainte de arhiva). Singura coloana de discount pe
`VANZARI_DETALII`/`VANZARI_DETALII_TEMP` gasita in `SCRIPTURI_CLAR` e **`DISCOUNT_UNITAR`**, si
singura modificare de tip/precizie inregistrata e cea din 2024.
**Dovezi (cronologic, tot ce am gasit cu `DISCOUNT` in contextul acestei tabele)**:
- Nu exista niciun `CREATE TABLE VANZARI_DETALII` sau `ALTER TABLE VANZARI_DETALII ADD DISCOUNT...`
in toata arhiva `SCRIPTURI_CLAR` (2009-2026). Cel mai vechi hit pe `DISCOUNT_UNITAR` legat de
aceasta tabela e o declaratie de variabila `V_DISCOUNT_UNITAR VANZARI_DETALII.DISCOUNT_UNITAR%TYPE`
in pachetul `PACK_FACTURARE`, prezenta deja in scripturile din 2009 (ex.
`2009\9\ff_2009_09_03_01_FACTURARE_PACK_FACTURARE.sql`) — coloana exista deja atunci.
- Singura modificare de precizie gasita: `ff_2024_06_13_02_COMUN_FACTURARE.sql:3` —
`alter table VANZARI_DETALII modify discount_unitar NUMBER(22,6);` — si simetric pentru
`VANZARI_DETALII_TEMP` la linia `:9`, si pentru `CRM_POLITICI_PRET_ART` (tabela de **politici de
pret**) la linia `:16`. Deci forma finala confirmata: **`DISCOUNT_UNITAR NUMBER(22,6)`**, o
singura coloana de discount (valoare, nu procent), identica pe toate cele 3 tabele.
- Nu exista alte coloane `DISCOUNT%`/`VDISCOUNT%` la nivel Oracle pe `VANZARI_DETALII` — cele patru
campuri VFP `discountftva`/`discountctva`/`vdiscountftva`/`vdiscountctva` din `crsfactura` NU au
corespondent 1:1 in schema Oracle; la scriere (`Gather`/`Replace` in `do_adauga_articol`, punctul
3) doar `discount_unitar` (si varianta cu TVA calculata din el) ajunge, prin campurile
intermediare, la coloana unica Oracle.
- Convenția de interogare a bazei de dezvoltare, gasita in `COMUN\docs\scripturi-migrare-db.md:36-40`:
sursa de referinta pentru DDL e schema de dezvoltare **`MARIUSM_AUTO`** (bazata pe
`ROA_CENTRAL`), interogata prin `goExecutor`, niciodata o schema de client. Nu am rulat nimic pe
baza — doar raportez conventia, asa cum a cerut sarcina.
## 5. Coloana de procent de discount pe VANZARI_DETALII / campul procdisc
**Concluzie**: **nu** exista o coloana de procent de discount pe `VANZARI_DETALII` (doar
`DISCOUNT_UNITAR`, o valoare absoluta). Campul `procdisc` din `frm_facturare_articole2` e doar un
camp de lucru in grid, **fara nicio scriere in cursorul local si fara corespondent Oracle** —
practic un camp scaffolded si neconectat.
**Dovezi**:
- Cautare `DISCOUNT`+`PROCENT`/`PROC` in `ff_2024_06_13_02_COMUN_FACTURARE.sql` (scriptul care
fixeaza forma finala a coloanelor de discount): nicio potrivire — confirma ca nu exista un
"procent discount" ca si coloana pe `VANZARI_DETALII`.
- `procdisc` apare **o singura data** in tot `ofacturare.vc2`: `Column14.ControlSource = "procdisc"`
la `:16721`, in interiorul clasei `frm_facturare_articole2` (`15741-19355` — prototip, nu
formularul in productie).
- Nicio instructiune `Gather`/`Replace ... procdisc With ...` in tot fisierul (cautat pe tot
`ofacturare.vc2`) — camp fara sursa de populare in cod.
- Toate celelalte aparitii de "procdisc" din fisier sunt de fapt variabila de memorie
`gnMemProcDisc` ("memorare procent discount" — o optiune de aplicatie care controleaza daca
procentul de discount tastat se retine intre articole, `:2299`, `:2441`, `:12835` etc.), fara
legatura cu campul de cursor `procdisc`.
- Cautare `PROCDISC` in `SCRIPTURI_CLAR`: doar 2 hit-uri, ambele in scripturi din 2015 pentru
tabela de **optiuni firma** (`co_2015_12_09_01_OPTIUNI.sql`, `ff_2015_12_09_01_OPTIUNI.sql`) —
legate de aceeasi optiune `gnMemProcDisc`, nu de `VANZARI_DETALII`.
## Ce era gresit in afirmatiile de mai sus
- Formularea "linia 3, 9, 16" pentru coloana Oracle `DISCOUNT_UNITAR` grupa laolalta 3 tabele
diferite (`VANZARI_DETALII` la `:3`, `VANZARI_DETALII_TEMP` la `:9`, `CRM_POLITICI_PRET_ART` la
`:16`) ca si cum ar fi acelasi lucru repetat de 3 ori — corect ca valoare (toate devin
`NUMBER(22,6)`), dar sunt 3 tabele distincte, nu 3 confirmari ale aceleiasi coloane.
- Cea mai importanta corectie: linia indicata pentru "de unde se scrie discountctva/vdiscountftva
— din `do_calculeaza_discount` (`ofacturare.vc2:13405-13424`)" trimite la metoda gresita.
`frm_facturare_articole.do_calculeaza_discount` de la acea linie calculeaza discountul **global
pe factura** (`Thisform.ndiscfactron`/`ndiscfactval`), nu discountul pe linie. Metoda care chiar
calculeaza `discount_unitar`/`discount_unitar_ctva` (sursa reala pentru `discountctva` si
`vdiscountftva`) e **`frm_articol_factura.do_calculeaza_discount`**, o metoda cu acelasi nume dar
in alta clasa, la `ofacturare.vc2:1874-1976`. Cele doua metode au nume identic dar apartin la
doua clase diferite din acelasi fisier — o capcana reala de grep fara indexul de simboluri.
## Necunoscute ramase
- Nu am verificat daca `crsarticole` (cursorul de stoc din care pleaca `poArticol.discount_unitar`
la `do_initializeaza_articol:13630`) e populat vreodata cu un discount nenul direct dintr-o
interogare de politica de pret (`CRM_POLITICI_PRET_ART`) inainte de a ajunge in dialogul
`frm_articol_factura` — am gasit doar ca acea tabela are aceeasi coloana `discount_unitar`
(`NUMBER(22,6)`), nu am urmarit interogarea SQL efectiva care umple `crsarticole`/`crsartselectate`
(cod probabil in `Programe/`, in afara `ofacturare.vc2`, netrasat din lipsa de timp alocat).
- Nu am confirmat pe date reale (Oracle) daca exista astazi randuri cu `DISCOUNT_UNITAR` populat pe
`VANZARI_DETALII` provenind din editarea directa in grid pe factura in valuta (punctul 2/3,
ultimul paragraf) — doar am aratat ca acea cale exista in cod, fara handler de recalcul.
- Nu am cautat daca `frm_facturare_articole2` (prototipul) e instantiat undeva in productie sau e
cu adevarat mort/nefolosit — task-ul l-a framat deja ca "prototip" si am pastrat presupunerea.

View File

@@ -1,35 +0,0 @@
-- 08.08.2026 Marius Mutu
-- VVANZARI_ARTICOLE: liniile unei vanzari (VANZARI_DETALII) cu denumirea articolului, a gestiunii
-- si a valutei, pentru gridul de articole din formularul de modificare a notei. Valori brute, fara
-- conversie valutara si fara calcule - editarea scrie inapoi exact ce a citit. Filtrul STERS ramane
-- pe seama apelantului, ca la VACT_TOT / VRUL_TOT / VRUL_OBINV_TOT.
CREATE OR REPLACE VIEW VVANZARI_ARTICOLE AS
select vd.id_vanzare,
vd.id_vanzare_det,
vd.id_articol,
vd.cantitate,
vd.pret,
vd.pret_cu_tva,
vd.proc_tvav,
vd.discount_unitar,
vd.id_gestiune,
vd.cont,
vd.id_valuta,
vd.id_jtva_coloana,
vd.serie,
vd.explicatie,
vd.taxcode,
vd.lot,
vd.sters,
na.denumire,
na.codmat,
ng.nume_gestiune,
nv.nume_val
from vanzari_detalii vd
left join nom_articole na on na.id_articol = vd.id_articol
left join nom_gestiuni ng on ng.id_gestiune = vd.id_gestiune
left join nom_valute nv on nv.id_valuta = vd.id_valuta;
exec pack_migrare.UpdateVersiune('ff_2026_08_08_01_COMUN_VVANZARI_ARTICOLE');
commit;

View File

@@ -1,103 +0,0 @@
# Predare — deblocarea proprietatilor custom pe frm_modific2024
Bloc de lucru TERMINAT CU SUCCES (nu la prag de context — predare la incheierea blocului,
conform Regula zero).
## Concluzie
**Ipoteza principala ("FoxBin2Prg Prg2Bin nu poate crea proprietati noi intr-un .vcx") e
INFIRMATA**, cu dovada directa (test izolat, mai jos). Cauza reala era alta, si s-a reparat.
## Cauza reala, cu dovada
Proprietatile noi (`larearticolevanzari`, `nidvanzare`, `ntipvanzare`) fusesera adaugate de
agentul anterior **doar** in blocul `*<PropValue>` (valorile), dar **lipseau din
`*<DefinedPropArrayMethod>`** (lista `*p:` care inregistreaza o proprietate custom ca membru real
al clasei). Fara intrarea `*p:`, `Prg2Bin` scrie linia de valoare, dar VFP n-o materializeaza ca
proprietate pe obiect — de-asta `PEMSTATUS` intorcea `.F.` desi valoarea aparea in text si
supravietuia fidelity-check-ului (fidelity-ul verifica doar ca textul regenerat == textul editat,
nu ca proprietatea exista pe obiect).
Regula era deja documentata **pentru metode** in `COMUN\docs\flux-editare-vfp-text.md:76-78`
("Metoda noua de clasa cere `*m: nume` in `*<DefinedPropArrayMethod>`; fara ea, ... o arunca
tacut") — se aplica identic si proprietatilor (`*p:`), doar ca nu era scrisa explicit acolo. De
adaugat separat in acel fisier (nu am facut-o eu, e in afara sarcinii primite).
## Testul izolat care a transat ipoteza
Nu am atins `omodificari` pentru test. Am copiat `COMUN\clase\_pf_base.vcx/.vct/.vc2` (clasa
`_pfbase`, fara nicio importanta) intr-un folder complet izolat in scratchpad, am adaugat text-only
o proprietate noua (`ltestpropnoua`) cu intrare `*p:` corecta, write-back cu `txt2vcx.ps1` (proiect
izolat, nu ProjectRoot real), apoi `CREATEOBJECT` + `PEMSTATUS`:
```
PEMSTATUS(ltestpropnoua)=DA valoare=.T.
```
Confirma ca fluxul text->bin **poate** crea proprietati noi, cand sunt inregistrate corect.
**Bonus gasit tot in acest test**: FoxBin2Prg foloseste o colatie unde `_` sorteaza **dupa**
literele obisnuite (nu ordine ASCII simpla pe litere mici) — `nidvanzare` < `nid_set` alfabetic
pentru tool, desi `'_' (0x5F) < 'v' (0x76)` in ASCII brut pe litere mici. Confirmat printr-un al
doilea test izolat: am scris `*p: nid_set` inaintea lui `*p: nidvanzare` (ordine ASCII) — fidelity
check a **picat** cu exact acest motiv; textul canonic din `<staging>\verify\` a aratat ordinea
corecta, `nidvanzare` inaintea lui `nid_set`. Coincide cu ordinea deja existenta, corecta, din
`*<PropValue>`-ul real al lui `frm_modific2024`. De adaugat in `flux-editare-vfp-text.md` /
`foxbin2prg\CLAUDE.md` ca nota separata (nu am facut-o, in afara sarcinii primite).
## Ce am schimbat in `omodificari.vc2`/`.vcx`/`.vct`
`COMUN\clase\omodificari.vc2`, clasa `frm_modific2024` (`:6375-15856`), blocul
`*<DefinedPropArrayMethod>` — 3 linii `*p:` noi, in ordine alfabetica (colatia tool-ului):
- `*p: larearticolevanzari` — linia 6804 (inainte de `lavertizatexigibilizare`)
- `*p: nidvanzare` — linia 6811 (inainte de `nid_set`)
- `*p: ntipvanzare` — linia 6818 (dupa `ntaxcode`)
Blocul `*<PropValue>` **nu a fost atins** — valorile erau deja acolo, deja in ordinea corecta,
de la agentul anterior.
Write-back real cu `txt2vcx.ps1 -AllowComun` — **fidelity check OK**. Backup pastrat:
`COMUN\clase\omodificari.vc2.pre_proprietati_custom.bak` (starea dinainte de aceasta reparatie,
distinct de `.pre_s4runda1.bak` mai vechi).
**Capcana pe care am picat-o si am reparat-o singura**: prima incercare a folosit
`$lines.IndexOf(text_exact)` ca sa gasesc pozitia liniilor `*p:` tinta — a gasit o potrivire
falsa mult mai devreme in fisier (alta clasa cu proprietati cu nume asemanator), inserand 3 linii
in locul gresit. Am restaurat din backup **inainte** de a rula orice write-back cu starea gresita,
am refacut editarea cu index-uri de linie verificate explicit (assert pe continutul exact al
liniei), si abia apoi am scris pe disc. Fisierul de pe disc e curat, o singura editare corecta.
## Verificare finala — PASS complet
`test_page3_articole.prg` sub `watchdog_vfp.ps1 -AutoDismiss`: exit 0, 0 dialoguri.
```
cod=1140888: PageCount = 3 (asteptat 3), lAreArticoleVanzari = .T. (asteptat .T.), nIdVanzare = 1050 -> PASS
cod=1125486: PageCount = 2 (asteptat 2), lAreArticoleVanzari = .F. (asteptat .F.) -> PASS
```
Toate celelalte asertii din suita (verifica_vanzare_nota x3, verifica_coliziune_cod) tot PASS,
neschimbate. `PEMSTATUS(loForm,'lAreArticoleVanzari',5)` si `PEMSTATUS(loForm,'nIdVanzare',5)`
acum `.T.` (erau `.F.` la predarea anterioara).
## Starea la predare
- **Fara commit git/SVN.** `svn status` pe COMUN arata `M` pe `omodificari.vcx`/`.VCT` (write-back
real); `.vc2` e `I` (ignorat de SVN, urmarit doar de `comun.git`).
- `comun.git status` arata `omodificari.vc2` modificat — diff-ul cumuleaza **toata munca
necomisa de azi pe S4 runda 1** (PAGE3, grid, cele 3 proprietati), nu doar reparatia mea; nimic
neasteptat.
- **Fara tranzactii Oracle deschise** — testul de verificare face doar `SELECT`-uri prin
`goExecutor`, zero scriere.
- **Niciun proces `vfp9.exe` ramas viu** (verificat, `Get-Process vfp9` gol).
- Scratch-ul de test izolat (`_pf_base.vcx` copiat) a ramas doar in
`C:\Users\...\scratchpad\testproj\` — in afara working copy, nu necesita curatare.
## Ce ramane (in afara sarcinii primite azi)
Pasii 3-5 din `docs\progres.md` sectiunea „#6, S4 runda 1": scoaterea liniilor `[BISECT]`/`[DIAG]`
din test, stergerea `test_baseline_isolation.prg` (concluzia lui e nula, vezi handoff anterior),
scrierea `docs\diff_s4_runda1_page3.patch` + `docs\cercetare\rec_s4_runda1.md`, actualizarea
`COMUN\docs\testare-ui-vfp.md` cu cele trei capcane noi (`DO...WITH` prin referinta, `SET PATH`
ROACONT, watchdog fara input real) **plus** cele doua descoperite acum (`*p:` obligatoriu si
pentru proprietati, colatia cu `_` dupa litere) — raman pentru runda urmatoare.

View File

@@ -185,7 +185,7 @@ sesiune doar pentru asta).
alta depanare GUI.
3. Daca se rezolva: reruleaza `test_page3_articole.prg` complet, confirma PASS pe toate cazurile
(inclusiv `verifica_pagecount_form`), sterge `test_baseline_isolation.prg` + `.fxp` + log-ul lui,
scrie diff-ul (`docs\diff_s4_runda1_page3.patch`, `git diff --no-index <bak> <editat>`) si
scrie diff-ul (diff aplicat (sters), `git diff --no-index <bak> <editat>`) si
raportul (`docs\cercetare\rec_s4_runda1.md`) cerute initial de team-lead.
4. Daca team-lead sau alt agent scrie capcana "View Parameter / LOCAL vs PRIVATE" in
`testare-ui-vfp.md`, nu o duplica — team-lead a intrebat explicit cine o scrie.

View File

@@ -1,121 +0,0 @@
# Handoff — test real write-back buton=1 (do_editare_factura)
Predare la prag de context, conform Regula zero din `CLAUDE.md`. Fara analiza noua aici, doar
starea.
## CORECTIE IMPORTANTA fata de ce stie team-lead acum
Team-lead a verificat baza INAINTE de ultima rulare si a raportat "`id_vanzare=1048` e neatins,
nimic de curatat". **Nu mai e adevarat** - intre timp corectia `LOCAL` -> `PRIVATE` a fost aplicata
SI rulata, iar testul **a reusit complet, cu COMMIT real, de doua ori**. Documentul `id_vanzare=1048`
**a fost modificat legitim**, exact cum era scopul aprobat de Marius:
- `cod` a trecut `1140886` -> `1140893` (TEST 1, salvare fara modificari) -> `1140894` (TEST 2,
cu explicatia unui rand `ACT` modificata: "NOTA 1" -> "NOTA 1 (test writeback)").
- **Cod-ul curent activ in baza pentru acest document este `1140894`**, nu `1140886`.
- Randurile vechi (`cod=1140886` si `cod=1140893`) raman in `ACT`/`RUL` cu `STERS=1` - asta e
comportamentul normal, prin design (vezi "Fapte stabilite" din `docs\progres.md`).
- `VANZARI.total_cu_tva`/`total_fara_tva`/`total_tva`/`id_fact`/`sters` au ramas neschimbate,
verificat si din log VFP si independent prin `sqlplus` dupa rulare.
- `VANZARI_DETALII` a ramas neatins (verificat, cum era de asteptat pe aceasta cale).
**Raport complet deja scris**: `docs\cercetare\rec_test_writeback.md` (tabel cu cele 5 verificari
pe ambele teste, PASS pe toate, plus istoricul celor 2 incidente si cum s-au rezolvat). Rezultatul
a fost deja trimis catre team-lead prin mesaj ("PASS complet pe ambele teste, commit real
confirmat independent") - posibil incrucisat cu mesajul lui de STOP.
## 1. Starea fisierului de test
`COMUN\utile\Teste\editare_factura\test_writeback_buton1.prg` (ultima modificare azi, 08.08.2026).
- **Corectia `LOCAL` -> `PRIVATE` (linia ~133, acum ~149-153): DA, APLICATA.** Declararea curenta:
```foxpro
PRIVATE pnAn, pnLuna, lnCod, lnIdFact
LOCAL lnSters, llEProforma
LOCAL lnIdSet, lnIdFactD, lnSucces, llGasitRand
```
(restul variabilelor de test raman `LOCAL`, corect - nu sunt folosite ca bind `?` in SQL).
- `frm_modific2024` e ocolit COMPLET (nu se mai instantiaza deloc) - s-a blocat de doua ori
headless (a se vedea sectiunea 3) si s-a decis cu team-lead sa fie scos din harness. `buton=1`
e fortat direct in cod, `inainte_de_do_termin` NU se executa.
`Thisform.do_deschide_tranzactie`/`do_inchide_tranzactie` sunt reproduse inline in fisier
(`MyDeschideTranzactie`/`MyInchideTranzactie`, copiate dupa `_frm_base.vc2:252-302`).
- `PUBLIC gcMockUltimMesaj, gnMockUltimTip` + logare `goExecutor.cEroare` dupa fiecare pas: DA,
adaugate (procedura `LogMockSiEroare`, apelata dupa fiecare `OSCRIE_IN_FISIERE` si dupa
`finalizeaza_modificare_nota`).
- Logare granulara `[chk]` inainte/dupa fiecare sub-pas din ramura `buton=1`: DA, adaugata.
- **Fisierul e in stare FINALA, functionala - nu mai necesita nicio corectie pentru scopul cerut.**
Orice rulare viitoare pe acest script trebuie sa citeasca `cod`-ul curent din `VANZARI` (nu
presupune `1140886`), pentru ca scriptul insusi face asta (interogheaza `VANZARI` la inceputul
fiecarui apel al procedurii `test_editare_writeback`).
## 2. Comanda exacta de rulare
```powershell
$testPrg = 'D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_writeback_buton1.prg'
Start-Process 'C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe' -ArgumentList '-A','-T',"`"$testPrg`"" -PassThru
```
Log: `D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_writeback_buton1_log.txt`
(suprascris de la zero la fiecare rulare - `STRTOFILE(..., lcLog)` fara `,1` pe prima linie).
Inainte de orice rulare: verifica sa nu existe deja un `vfp9.exe` activ
(`Get-CimInstance Win32_Process -Filter "Name='vfp9.exe'"`) si sterge `.FXP`/`.ERR`/log vechi din
acelasi folder.
## 3. Ce s-a stabilit deja (nu se reia)
- Prima varianta a testului instantia `frm_modific2024` (modeless, `WindowType=0`, ca in
`test_page3_articole.prg`) - s-a blocat de doua ori, headless, fara nicio linie de eroare in
log: prima data pe un dialog nativ Windows **"Open"** (`#32770`, confirmat prin
`EnumWindows`/`GetWindowText` pe procesul viu), a doua oara (dupa ce s-a scos `frm_modific2024`
si inainte de corectia `PRIVATE`) pe un dialog **nativ VFP "View Parameter"** ("Enter the value
for pnLuna"), confirmat de captura de ecran trimisa de Marius si de `EnumWindows` local.
- **Ipoteza "backupset" (clasa `BackupXML`, `oproceduri_comune.prg:3685-3987`) respinsa**: foloseste
doar `CREATE CURSOR`/`Cursortoxml`/`Delete File`, niciun `USE` pe tabela lipsa; si oricum prima
rulare (cea cu `-1`) trecuse deja prin acelasi cod fara sa se blocheze.
- **Cauza reala a dialogului "View Parameter"**: `pnAn`/`pnLuna` erau declarate `LOCAL` in harness,
in loc de `PRIVATE` ca in codul real (`ofacturare_comun.vc2:3742`). `PRIVATE` le face vizibile
in josul stivei de apel, unde `goExecutor.oExecuta` rezolva bind-urile `?pnLuna`/`?pnAn` din
apelul catre `pack_contafin.finalizeaza_modificare_nota`. Cu `LOCAL`, VFP nu le gasea si deschidea
dialogul nativ de introducere manuala - niciodata catchabil prin `ON ERROR`/`TRY`/mock de
`amessagebox` (nu e un `AMESSAGEBOX`, e un mecanism VFP intern).
- **Dupa corectie (`PRIVATE`), ambele teste au trecut curat, cu COMMIT real** - vezi "CORECTIE
IMPORTANTA" de mai sus si `docs\cercetare\rec_test_writeback.md` pentru tabelul complet.
- Inainte de corectie, o rulare intermediara aratase `OSCRIE_IN_FISIERE(2,.T.,.T.) => -1` (esec
curat, cu ROLLBACK, fara nicio scriere) - **acel `-1` nu s-a mai reprodus dupa corectia
`PRIVATE`** (ambele `OSCRIE_IN_FISIERE` au intors `1` in rularea finala). Motivul exact al lui
`-1` din acea rulare intermediara **ramane neexplicat definitiv** (posibil efect secundar al
aceleiasi probleme de scope, posibil altceva) - nu mai e relevant, testul final a trecut, dar
daca reapare vreodata pe alt document, `gcMockUltimMesaj`/`goExecutor.cEroare` sunt deja logate
dupa fiecare pas.
## 4. Ce e interzis (neschimbat)
- Nu mock-ui `OSCRIE_IN_FISIERE`.
- Nu modifica codul aplicatiei (`ofacturare_comun.vc2`, `oscrie_in_fisiere.prg`,
`omodificari.vc2` etc.) - niciun bug de aplicatie n-a fost gasit, toate problemele au fost in
harness.
- Nu folosi `cod=1140888` / `cod=1140885` (baze de regresie ale `test_incarca_cursoare.prg`).
- Nu rula `git_sync.ps1` si nu atinge `omodificari.vc2`/`.vcx` (alt agent lucreaza in paralel pe
PAGE3, task separat).
## 5. Starea datelor - vezi CORECTIA de la inceputul fisierului
Pe scurt: `id_vanzare=1048` a fost editat legitim de doua ori prin testul aprobat. `cod` curent =
`1140894`. Nimic de reparat sau de facut rollback - e rezultatul dorit al testului. Daca se doreste
un test suplimentar pe alt document, se alege un `cod`/`id_vanzare` nou (nu `1140886`/`1140888`/
`1140885`).
## 6. Fisiere temporare
Nimic de sters in working copy. `test_writeback_buton1.FXP` si `test_writeback_buton1_log.txt`
din `COMUN\utile\Teste\editare_factura\` sunt artefacte normale, in acelasi tipar cu
`test_incarca_cursoare.FXP`/`test_page3_articole.FXP` deja existente in acel folder (folder de
teste, neurmarit ca binare in git). Fisierele de diagnostic SQL folosite pentru verificarea
independenta au fost in scratchpad-ul de sesiune (`C:\Users\...\Temp\claude\...\scratchpad\`), in
afara working copy - nu necesita curatare de catre urmatorul agent.
Un fisier `test_baseline_isolation.prg`/`.FXP`/`_log.txt` exista in acelasi folder, creat inainte
de aceasta sesiune si NU de agentul curent - probabil al agentului paralel de pe alta sarcina; nu
l-am atins.

View File

@@ -1,127 +0,0 @@
# Handoff — watchdog VFP + bisectie blocaj "View Parameter" gnAn
Predare la peste 310k context (Regula zero). **Doar stare, fara analize noi.** Raport analitic
complet (dovezi, log-uri, discutie): `docs\cercetare\rec_watchdog_vfp.md`.
## 1. Inventar livrabile, cu fisier:linie
**Utilitar**: `D:\ROA\ROAFACTURARE\COMUN\utile\Teste\watchdog_vfp.ps1`. Linia de comanda completa:
```
powershell -ExecutionPolicy Bypass -File "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\watchdog_vfp.ps1" -Script "<cale.prg>" -TimeoutSec 90 -AutoDismiss -MaxDialogs 10
```
Lanseaza `vfp9.exe -A -T "<script>"`, detecteaza orice fereastra noua diferita de
`Process.MainWindowHandle`, o captureaza (PNG + `WM_GETTEXT` pe titlu si controale copil) in
`<folderul scriptului>\watchdog_out\`, si cu `-AutoDismiss` incearca s-o inchida STRICT prin mesaje
Windows tintite pe handle (`BM_CLICK` pe buton Cancel/Anulare -> `WM_COMMAND IDCANCEL` ->
`WM_KEYDOWN`/`WM_KEYUP` ca mesaj -> `WM_CLOSE`) - **FARA input real** (vezi sectiunea 3). Omoara
procesul mereu la iesire (`finally`).
**Fisiere de test noi**:
- `COMUN\utile\Teste\watchdog_selftest.prg` - caz banal de validare (MESSAGEBOX), folosit doar ca
sa confirme ca watchdog-ul detecteaza/captureaza/dismite corect, inainte de cazul real.
- `COMUN\utile\Teste\editare_factura\test_repro_izolat_gnan.prg` - experimentul B (izolat): DOAR
`test_init_env_auto` + `update_jtva_coloane("", "crsJtvaTemp", 6)`, fara nimic din S4. NU
reproduce blocajul - dovada ca `update_jtva_coloane`/`updateserver.prg` sunt nevinovate.
**Fisier de test modificat**: `COMUN\utile\Teste\editare_factura\test_page3_articole.prg`:
- linia 176: `update_jtva_coloane("", "crsJtvaTemp", 6)` (parametrul schimbat din `0` in `6` -
necesar pentru indexul `id_jtva` cerut de `Column63.ControlSource` din `omodificari.vc2:9199`;
independent de defectul principal, fix cunoscut deja din `date_test_nnir.md`);
- `PROCEDURE bisect_log_gnan` (noua, la coada fisierului, ~linia 236) + apeluri `DO bisect_log_gnan
WITH <tag>, lcLog` inserate: in programul principal intre fiecare apel de nivel superior, si ca
PRIMA linie in interiorul fiecarei proceduri (`verifica_vanzare_nota`, `verifica_coliziune_cod`,
`verifica_pagecount_form`) - infrastructura de bisectie, ramasa in cod ca dovada;
- **liniile 37, 39, 50 - remediul APLICAT DE TEAM-LEAD** (nu de mine, sub pragul lui de editare
directa): `gnAn`/`gnLuna` parantezate - `(gnAn)`, `(gnLuna)` - in apelurile `DO verifica_vanzare_nota
WITH ...` (x2) si `DO verifica_pagecount_form WITH ...` (primul), cu comentariu explicativ deasupra
primei aparitii (liniile 34-36).
**Log-uri si capturi**: `test_page3_articole_log.txt` (log-ul aplicatiei, contine liniile `[BISECT]`),
`watchdog_out\*.png` + `watchdog_out\*_watchdog.log` (capturi + jurnal watchdog, per fisier de test),
toate in `COMUN\utile\Teste\editare_factura\`.
## 2. Ce e terminat, ce nu
**Terminat**:
- Watchdog-ul: scris, testat pe caz banal, testat pe cazul real, corectat (heuristica de fereastra
principala, bug de indexare PowerShell pe array cu 1 element, input real scos complet).
- Bisectia: COMPLETA, cauza CONFIRMATA cu date brute (nu deductie) - vezi sectiunea 4.
- Remediul: APLICAT de team-lead (liniile 37/39/50).
**Neterminat**: remediul NU a fost re-testat dupa aplicare. Ultima rulare a suitei (a mea) a fost
INAINTE de remediul team-lead-ului. Team-lead ruleaza el insusi suita, separat - **eu nu mai rulez
nimic** (interdictie explicita primita).
## 3. Stare fisiere - write-back
**Toate fisierele atinse in aceasta sesiune sunt `.prg`/`.ps1` (text simplu)** - NU exista
`.vc2`/`.sc2`/`.vcx`/`.vct` atinse, deci **NU exista niciun write-back nefacut**.
Confirmare explicita: `COMUN\clase\omodificari.vc2/.vcx/.vct` si `COMUN\programe\updateserver.prg`
sunt **NEATINSE** in aceasta sesiune (nici de mine, nici - din cate stiu - de altcineva). Fara
commit git/svn facut sau initiat.
## 4. Ce s-a stabilit deja - NU relua
- **Cauza CONFIRMATA, nu ipoteza**: `test_page3_articole.prg` (inainte de remediu) trecea
`gnAn`/`gnLuna` NEPARANTEZAT in `DO...WITH` (liniile 34, 36, 47 - numerotare dinainte de remediu).
`DO proc WITH var` paseaza variabile de memorie BY REFERENCE implicit in VFP; `LPARAMETERS`
primitor devine alias direct pe storage-ul original, iar numele original (`gnAn`) devine
inaccesibil (`TYPE()='U'`) STRICT pe durata acelui apel, revenind valid imediat dupa `RETURN`.
Confirmat simetric pe 3 apeluri afectate vs 2 neafectate (vezi tabelul din `rec_watchdog_vfp.md`
sectiunea 5).
- **`updateserver.prg`/`update_jtva_coloane` sunt nevinovate** - experimentul B (izolat, fara nimic
din S4) NU reproduce; functia merge perfect cand `gnAn` e vizibil normal.
- **`gnAn` NU e eliberata niciodata** - ramane valida (`TYPE()='N'`, 2026) la FIECARE checkpoint din
scope-ul PRINCIPAL, fara exceptie. Nu exista `CLEAR ALL`/`CLEAR MEMORY`/`RELEASE ALL EXTENDED` pe
lantul executat.
- **Nu e coliziune de nume in corpul procedurii**: `verifica_pagecount_form` NU are `gnAn` in
`LOCAL` (linia ei 148/159), si NU exista `PRIVATE gnAn`/`LOCAL gnAn` nicaieri in `COMUN\programe`.
Umbrirea vine din SINTAXA APELULUI (`DO...WITH` neparantezat), nu din declaratiile callee-ului.
- **Handler-ul de eroare** (`test_error_handler`/`ON ERROR`) doar logheaza (`STRTOFILE`) si continua
- nu ascunde nimic, util pentru diagnostic.
- **Incidentul de focus**: ESC-ul trimis de o versiune veche a watchdog-ului (cu `SetForegroundWindow`
+ `keybd_event`, SCOASA complet acum) a aterizat de fapt in PROPRIUL nostru proces de test, NU in
sesiunea utilizatorului - dar mecanismul tot nu are tinta si regula "fara input real" ramane
obligatorie indiferent (documentat in `rec_watchdog_vfp.md` sectiunea 1, corectat acolo dupa o
formulare initiala gresita).
## 5. Ce e interzis
- Input real de tastatura/mouse in watchdog (`keybd_event`, `SetForegroundWindow`, `SendInput`,
`mouse_event`) - masina e PARTAJATA. Deja scos din cod, verificat cu grep (zero hit-uri de cod,
doar comentarii care explica interdictia).
- Atingerea `COMUN\clase\omodificari.vc2/.vcx/.vct` si `COMUN\programe\updateserver.prg`.
- Commit git/svn.
- **Eu nu mai rulez suita** - team-lead o ruleaza separat dupa remediul lui.
## 6. Capcane de mediu platite in aceasta sesiune
- **Heuristica "prima fereastra vazuta = principala" e o cursa pierduta**: un dialog poate aparea in
aceeasi fractiune de secunda cu fereastra principala. Solutia corecta: `Process.MainWindowHandle`
(.NET), NU ordinea de aparitie si NU numele clasei (VFP foloseste clase `vfp9...` si pentru shell,
si pentru dialogurile proprii - `vfp99400000` vs `vfp994000002`).
- **Dialogurile proprii VFP (ex. "View Parameter") sunt owner-drawn** - `EnumChildWindows` intoarce
ZERO controale copil (butoanele sunt desenate, nu HWND-uri reale). `BM_CLICK` e imposibil pentru
ele; chiar si `WM_CLOSE` poate "reusi" aparent (`IsWindow` -> fals) FARA sa deblocheze de fapt
motorul VFP din spate (SQLEXEC ramas agatat, fara linie noua in log, pana la timeout) - un fals
"succes" de retinut daca cineva reia mecanismul de dismiss.
- **Bug PowerShell subtil**: un `List[string]` cu UN SINGUR element e "descompus" de PowerShell la
scalar string simplu la `return` din functie (fara `,` unar) - indexarea ulterioara `$x[0]` citeste
atunci primul CARACTER, nu primul element. Prins la dump-ul de text al dialogului "View Parameter"
(fara controale copil = un singur element in listă). Fix: `return , $lista.ToArray()`.
- **`.fxp` vechi blocat**: sterge intotdeauna `.fxp`-ul inainte de fiecare rulare (watchdog-ul o face
singur) - altfel VFP ruleaza tacut codul vechi compilat.
- **Bisectia**: `TRANSFORM(gnAn)` pe o variabila `TYPE()='U'` ARUNCA eroare catchabila ("Variable
'GNAN' is not found") - helper-ul `bisect_log_gnan` verifica `TYPE()<>'U'` INAINTE de a apela
`TRANSFORM()`, ca sa nu produca o eroare noua care ar fi intrerupt bisectia la primul checkpoint
"gol".
## Confirmare finala
**PID 16548 nu mai exista** (verificat cu `Get-Process -Id 16548` - inexistent la momentul acestui
handoff) si **niciun `vfp9.exe` nu ruleaza** (verificat cu `Get-Process vfp9` - lista goala). Nimic
in stare periculoasa: fara editare pe jumatate, fara cursor/tranzactie Oracle deschisa (doar
citiri), fara fisier binar atins. Sesiunea se opreste aici.

View File

@@ -1,210 +0,0 @@
# Anatomia butonului "Import Roris & Contracte" (ROAACNPRO)
Cercetare read-only in `D:\ROA\ROAACNPRO`, ca model pentru un buton generic
"importa articole din sursa" intr-un formular de facturare unificat in ROAFACTURARE.
Nicio editare de fisiere, niciun `git_sync.ps1`/`txt2vcx.ps1`, niciun commit — doar investigatie.
## 1. Localizare
**Concluzie**: Butonul e `cmdImport` (clasa `cmd_executa`) pe formularul `frm_factura`, definit in
`Clase\oacnpro.vc2`. Nu are `Click` propriu — mosteneste `Click` din clasa de baza a butoanelor,
care ruleaza metoda numita in proprietatea `caction`; `cmdImport` nu suprascrie `caction`, deci
ramane valoarea implicita `do_executa` mostenita de la clasa `cmd_executa`
(`COMUN\clase\cmd_butoane.vc2:474`). Codul efectiv e in `PROCEDURE do_executa` a formularului
`frm_factura`.
**Dovezi**:
- `Clase\oacnpro.vc2:6894-6905` — definirea controlului:
```
ADD OBJECT 'cmdImport' AS cmd_executa WITH ... Caption = "\<Import Roris & Contracte", ... Left = 597, Top = 65, Width = 169
```
- `COMUN\clase\cmd_butoane.vc2:474` — `caction = do_executa` (mostenit de `cmd_executa`).
- `COMUN\clase\_cmd_base.vc2:120-159` — `PROCEDURE Click` a clasei de baza: construieste
`lcCommand = [this.Parent.] + lcAction + ...` si il executa cu macro (`&lcCommand`).
- `Clase\oacnpro.vc2:7814-7836` — `PROCEDURE do_executa` a lui `frm_factura` (clasa incepe la
`oacnpro.vc2:6398 DEFINE CLASS frm_factura`, se termina la `8383`).
## 2. Preconditii
**Concluzie**: Butonul e activ doar daca (a) factura nu e inca salvata (`llFacturaEditabila`) si
(b) tipul facturii (`poDate.cTip`, ales din `cboTip`) e unul din
`TRANZIT, CHEIAJ, CHIRII, APA, PENALITATI`. In plus, la Click, `do_executa` verifica separat ca a
fost ales clientul.
**Dovezi**:
- `Clase\oacnpro.vc2:8117-8145`:
```
llFacturaEditabila = !This.lFacturaSalvata
llRorisSauContracte = INLIST(poDate.cTip, 'TRANZIT', 'CHEIAJ', 'CHIRII', 'APA', 'PENALITATI') && butonul import RORIS&Contracte este activ doar pentru RORIS sau contracte
...
.cmdImport.Enabled = m.llFacturaEditabila and m.llRorisSauContracte
```
- `Clase\oacnpro.vc2:7820-7823`:
```
IF EMPTY(NVL(this.nIdClient,0))
AMESSAGEBOX('Alegeti clientul!',0+48,_screen.Caption)
RETURN
ENDIF
```
- Fara client ales, butonul e vizibil/activ dar Click-ul se opreste cu acest mesaj.
## 3. Ce face efectiv
**Concluzie**: `do_executa` -> `factura_import()` (`Programe\proceduri_acnpro.prg:3151`) ramifica
dupa `poDate.cTip`:
- TRANZIT/CHEIAJ: `vizualizare_tranzit()` -> deschide dialogul `frm_tranzit` (selectie convoaie din
vederea Oracle `ips_vvoyages`) -> la confirmare, `calcul_tranzit()`/`calcul_cheiaj()` interogheaza
direct (SELECT-uri simple, nu pachete PL/SQL) tabelele/vederile `ips_vvoyage_members_calcul`,
`ips_vvoyage_locks`, apoi deschide un al doilea dialog de editare tarife (`frm_calcul_tranzit`).
- CHIRII/APA: `vizualizare_contract()` -> `calcul_contract()` -> SELECT din vederea
`vctr_articole2` (articole de contract) -> dialog `frm_calcul_contract`.
- PENALITATI: `vizualizare_penalitati()` -> `frm_penalitati` cu cursorul `crsCalculPenalitati`
calculat in VFP din vederile `vanzari`/`ireg_parteneri`/`penalitati`.
Dupa confirmarea dialogului (validat prin variabila globala `gnButon = 1`, standard framework
pentru formulare modale), se apeleaza `make_factura_tranzit` / `make_factura_cheiaj` /
`make_factura_contracte` / `make_factura_penalitati`, care insereaza direct in `crsFactura`.
**Important**: nicio procedura Oracle stocata (`pack_*`) nu e apelata in etapa de import — acestea
(`pack_facturare.*`, `pack_acn.salveaza_regdoc`, `pack_contafin.*`) sunt apelate abia la
**salvarea** finala a facturii (`factura_salvare_db`, `Programe\proceduri_acnpro.prg:3290+`), nu
la import.
**Dovezi**:
- `Programe\proceduri_acnpro.prg:3151-3212` (`Procedure factura_import`), `740-771`
(`calcul_tranzit`, sursa `ips_vvoyage_members_calcul`), `1127-1161` (`calcul_contract`, sursa
`vctr_articole2`).
- `Programe\proceduri_acnpro.prg:939-943`:
`loFrmTranzit = Crea("frm_calcul_tranzit", ...); loFrmTranzit.Show(1); llSucces = (m.gnButon = 1)`.
- `Programe\proceduri_acnpro.prg:3331-3467` — apelurile `pack_facturare.*`/`pack_acn.salveaza_regdoc`
sunt in `factura_salvare_db`, nu in `factura_import`.
## 4. Cum populeaza factura
**Concluzie**: Scrie **direct** in cursorul de articole al facturii, `crsFactura`, prin
`INSERT INTO crsFactura(...)` in fiecare `make_factura_*` — nu trece prin vreo metoda generica
"adauga articol" a formularului (exista o metoda separata `do_adauga_articol` pentru adaugare
manuala de linie, dar importul n-o foloseste). Liniile se **adauga** peste cele existente (nu
sterge/inlocuieste `crsFactura` inainte). Protectia la dublu-import e partiala:
- dupa un import reusit, `This.cmdImport.Enabled = .F.` dezactiveaza butonul (nu se mai poate
importa a doua oara in aceeasi sesiune de editare a facturii);
- pentru TRANZIT/CHEIAJ exista un avertisment (nu blocaj) daca pe convoaiele alese exista deja
facturi (`ips_vvoyages_vanzari.numar_act IS NOT NULL`) — utilizatorul poate continua oricum.
**Dovezi**:
- `Clase\oacnpro.vc2:7827-7834`:
```
llSucces = factura_import(m.tlImportCalculat)
IF m.llSucces
This.cmdImport.Enabled = .F. && nu mai import altceva
This.chkIntern.Enabled = .F.
This.ActiveazaSalvare()
...
```
- `Programe\proceduri_acnpro.prg:3601` (TRANZIT) / `3677-3678` (CHEIAJ) / `3764-3765`
(CHIRII/APA): `Insert Into crsFactura(nrcrt, id_articol, denumire, ...)`.
- `Clase\oacnpro.vc2:14915-14930` — avertisment dublu-import in `frm_tranzit.do_executa`:
```
SELECT numar_act, data_act, client FROM ips_vvoyages_vanzari WHERE vye_id in (...) AND numar_act is NOT null ...
IF RECCOUNT('cFacturiTranzitTemp') > 0
lcMesaj = 'Atentie! Exista facturi pe tranzitele alese!' + CHR(13)+CHR(10) + ...
AMESSAGEBOX(m.lcMesaj,0+48,_screen.Caption)
ENDIF
```
(mesaj informativ, apoi continua oricum cu `calcul_tranzit`/`calcul_cheiaj`).
## 5. Feedback catre utilizator
**Concluzie**: Mesaje punctuale prin `AMESSAGEBOX`, nu un sistem unitar de raportare:
- Client lipsa: `'Alegeti clientul!'` (`oacnpro.vc2:7821`).
- Convoi/liniile de import lipsa dupa dialog: `'Alegeti un convoi!'` in `make_factura_tranzit`
daca `poDate.uuid` (id-urile alese) e gol (`proceduri_acnpro.prg:3530`); analog pentru
CHIRII/APA prin `factura_salvare` (`'Alegeti convoiul'`/`'Adaugati prestatii'`,
`proceduri_acnpro.prg:3221`, dar aceasta e verificare la *salvare*, nu la import).
- Facturi deja existente pe convoaiele alese: avertisment neblocant (vezi punctul 4).
- Zero rezultate in dialogul de selectie (`frm_tranzit`/`frm_calcul_contract`): niciun mesaj
explicit gasit — grila ramane goala, iar la `Calculare`/`Terminat` fara nimic bifat `lcVyeIds`
ramane vid si `IF !EMPTY(m.lcVyeIds)` (`oacnpro.vc2:14912`) sare peste tot calculul, fara mesaj
catre utilizator (comportament implicit: butonul pare sa nu faca nimic).
- Eroare Oracle: nu exista tratare `TRY/CATCH` explicita in `factura_import`/`calcul_tranzit`/
`make_factura_*`; erorile SQL se propaga prin returul `.F.` al lui
`goExecutor.oExecuta`/`oSelecteaza2Value`, iar afisarea erorii tine de comportamentul standard
al `goExecutor` (framework comun, neexaminat in detaliu aici).
**Dovezi**: citatele de mai sus; pentru "zero rezultate fara mesaj" — `Clase\oacnpro.vc2:14898-14943`.
## 6. Selectivitate
**Concluzie**: Da, exista dialoage intermediare cu selectie, diferite pe tip:
- **TRANZIT/CHEIAJ**: `frm_tranzit` (`oacnpro.vc2:14492-15003`) — grid `grdTranzit` cu coloane
`Declaratia`, `Data decl.`, `Convoi`, `Origin`, `Destinatie` si o coloana checkbox `cAles`
(`ControlSource='crsConvoaie.ales'`), plus criterii de cautare (`Cb_tx_cautare1`,
`But_start_criterii1`/`But_reset_criterii1`) si buton `cmdCalculeaza` ("Calculare Tarife").
Utilizatorul bifeaza unul sau mai multe convoaie; daca nu bifeaza niciunul, se ia randul curent
(`lcVyeId` din `crsConvoaie` la pozitia curenta). Dupa `Calculare Tarife`, se deschide **al
doilea nivel** — `frm_calcul_tranzit`/`frm_calcul_cheiaj` — pentru editarea/confirmarea
tarifelor calculate, inainte de a reveni in factura.
- **CHIRII/APA**: `calcul_contract()` deschide `frm_calcul_contract` cu cursorul
`crsArticoleContract` (articol, perioada, um, pret, cantitate, valoare, valuta, locatie) din
vederea `vctr_articole2` filtrata pe `id_ctr` — practic toate articolele contractului curent,
editabile in acel dialog.
- **PENALITATI**: `frm_penalitati` cu grid `grdPenalitati` (`crsCalculPenalitati`), coloane
vizibile precum `cNrDoc`, `cSuma` ("Sold restant" in modul evaluare), `cDataDoc`.
Deci nu e un "importa tot" fara interventie — e mereu mediat de un dialog de vizualizare/calcul/
confirmare (`gnButon = 1` = utilizatorul a confirmat).
**Dovezi**: `Clase\oacnpro.vc2:14500-14515` (obiecte grid + `cAles`), `14801`
(`ControlSource='crsConvoaie.ales'`), `14594-14601` (`cmdCalculeaza`);
`Programe\proceduri_acnpro.prg:1137-1153` (`crsArticoleContract` din `vctr_articole2`);
`Programe\proceduri_acnpro.prg:545-555` (`frm_penalitati`, `grdPenalitati.cSuma`, `.cNrDoc`,
`.cDataDoc`).
## 7. Butoanele vecine
**Concluzie**: Pe `frm_factura`, `cmdImport` e plasat in zona antetului facturii
(`Left=597, Top=65`), langa `cboTip` (`Left=507, Top=67` — combo cu tipul facturii) si
`chkIntern` (`Left=412, Top=70`) — nu langa bara principala de butoane. Bara principala de sus
(`Top=0`) contine, in ordinea `Left`: `but_factura_noua` ("Nou", `Left=688`), `But_salveaza1`
("Salveaza", `Left=719`), `But_renunt1` ("Renunta", `Left=749`). Separat, langa grila
`grdFactura`, exista butoane de linie (`Top=120`): `But_nou1` ("Adauga linie", `Left=707`) si
`But_sterge1` ("Sterge linie", `Left=737`). Mai sunt `but_cautare_client`/`but_cautare_beneficiar`
(lupa cautare partener, langa campurile de client/beneficiar).
**Dovezi**: `Clase\oacnpro.vc2:6779-6818` (definitiile `but_factura_noua`, `But_nou1`,
`But_renunt1`, `But_salveaza1`, `But_sterge1` cu `Left`/`Top`), `6836-6851` (`cboTip`),
`6853-6863` (`chkIntern`), `6894-6905` (`cmdImport`).
## Ce e transferabil in ROAFACTURARE
Tiparul general merita copiat ca **model de arhitectura pentru un buton generic "importa
articole din sursa"**:
1. Buton activ conditionat de (a) factura editabila (nesalvata) si (b) tip de document care are o
sursa de import — exact ca `llFacturaEditabila and llRorisSauContracte`.
2. O metoda de intrare unica (`do_executa`/`factura_import`) care ramifica dupa tipul documentului
catre functii specializate de "vizualizare/selectie" — fiecare deschide un dialog modal de
selectie (grid cu coloana checkbox `ales`, criterii de cautare), returneaza succes/esec prin
variabila globala tip `gnButon = 1`.
3. Populare prin `INSERT INTO <cursor_articole>` direct, aditiv (nu sterge liniile existente), cu
dezactivarea butonului dupa import reusit ca protectie minimala la dublu-import — plus
(optional) un avertisment neblocant daca sursa a mai fost deja folosita in alta factura.
4. Separarea neta intre etapa de **calcul/import** (SELECT-uri simple pe vederi Oracle, fara
proceduri stocate) si etapa de **salvare** (unde intra pachetele PL/SQL) — util ca principiu:
importul nu trebuie sa scrie definitiv in baza, doar sa populeze cursorul local.
Ce e strict specific ACN/RORIS si **nu** se transfera: sursele de date (`ips_vvoyages`,
`ips_voyage_members_vanzari`, `ips_vberthing_details_vanzari`, `vctr_articole2`), logica de calcul
tarife/ecluzari/porturi, formularele `frm_tranzit`/`frm_calcul_tranzit`/`frm_calcul_contract`/
`frm_penalitati` ca atare, si valorile `poDate.cTip` (`TRANZIT/CHEIAJ/CHIRII/APA/PENALITATI`).
## Necunoscute ramase
- Comportamentul exact al `goExecutor.oExecuta`/`oSelecteaza2Value` la eroare Oracle (mesaj
afisat, retry, log) — n-a fost verificat in profunzime (functie framework comun).
- Continutul complet al dialogului `frm_calcul_tranzit`/`frm_calcul_cheiaj` (al doilea nivel,
editare tarife) — am confirmat doar ca exista si ca `gnButon=1` marcheaza confirmarea, dar nu am
detaliat coloanele/campurile lui.
- Detaliile `frm_calcul_contract` (butoane, posibilitate de deselectare articole individuale) nu
au fost citite integral — doar sursa cursorului.
- Nu am verificat daca exista vreo validare suplimentara de "acelasi convoi importat de doua ori
in aceeasi factura" dincolo de avertismentul cross-factura mentionat la punctul 4.

View File

@@ -74,7 +74,7 @@ tabel — e folosit exclusiv ca filtru intr-un calcul de disponibil.
Nu exista. DDL-ul complet nu e disponibil in acest repo (nu exista `CREATE TABLE VANZARI_DETALII` in
`docs/`; confirmat deja de cercetari anterioare — `docs/cercetare/discount_verificare2.md:104-111`,
`docs/cercetare/rec_tva_vanzari.md:19`), dar structura efectiva a fost verificata pe schema live in
`COMUN\docs\cercetare\rec_tva_vanzari.md:19`), dar structura efectiva a fost verificata pe schema live in
`docs/cercetare/rec_cale_vanzari_detalii.md:157-169` (interogare `all_tab_columns`, 08.08.2026):
35 de coloane, PK `ID_VANZARE_DET` (generat prin trigger `TRG_VANZARI_DET_BEFOINS` din
`SEQ_VANZARI_DETALII`), FK logic `ID_VANZARE`. Lista coloanelor relevante citata acolo: `ID_ARTICOL`,

View File

@@ -1,53 +0,0 @@
# Mockup #13 — v6 -> v7 (runda 8), ce s-a schimbat
Fisier atins: `D:\ROA\ROAFACTURARE\docs\mockup_13_formular_unificat.html`. Niciun alt fisier.
## Sectiuni atinse
- **Eyebrow / marcaj versiune** (linia ~199): `versiunea 6` -> `versiunea 7 (runda 8)`.
- **Sectiunea 8** ("Ce trebuie verificat inainte"): item-ul "cont de venit fara politica" a fost
rescris — decizia 24 (politica implicita) marcata retrasa, inlocuita cu decizia 27/27-bis, cu
trimitere la sectiunea 10 noua. S-au adaugat trei intrari noi, toate `raspuns`: nepotrivirea de
afisare ROAAUTO (decizia 28), stergerea liniei din comanda (decizia 29), coordonarea cu #6
(decizia 30). Cele 7 intrari `de verificat` originale nu s-au atins.
- **Sectiunea 9** (ROAAUTO): ultimul paragraf ("Ce ramane e o nepotrivire de afisare", pill
`de acceptat`) a fost rescris ca decizie inchisa (pill `decis`), cu conditia explicita — MANOPERA
si MATERIALE conform devizului — si precizarea "nu se cere cod nou in ROAAUTO".
- **Sectiune noua 10** ("Contul de venit pentru articole adaugate din nomenclator"), adaugata la
finalul documentului: nu exista o sectiune dedicata in v6, doar bulletul cramponat din sectiunea 8
cu raspunsul vechi (politica implicita) — s-a creat sectiune noua, nu s-a renumerotat nimic
existent. Contine: decizia 24 barata (`<s>`) cu motivul retragerii; tabel cu decizia 27 (cele doua
ramuri — gestionabil prin `CORESP_CONT_VENCHELT.CONT_VENIT`, negestionabil prin `NOM_ARTICOLE.CONT`
sau `704`); decizia 27-bis ca listă ordonata de 4 pasi (calculeaza contul -> cauta politica cu
acel cont -> `pack_preturi.adauga_politica_pret_art` -> trimite `id_pol`); intrebarea lui Marius
("de ce nu si in ROAACNPRO / pe contract") cu raspunsul exact din plan (ROAACNPRO nu cheama
`contabilizeaza_articol`; pe contract articolele au `id_pol` din cursor; `FACT-024` ramane
blocantul); lista "Ce nu e gratuit" cu cele 4 costuri din J-quater.
## CSS
S-a extins selectorul `ul.tight` la `ul.tight, ol.tight` (si `li`-urile lor), ca sa poata fi folosita
o lista numerotata (reteta VFP in 4 pasi) cu exact aceeasi tipografie ca listele `<ul class="tight">`
deja existente. Nicio alta regula CSS schimbata, nicio paleta/biblioteca noua.
## Ce NU s-a atins
- Relatia cu #6 nu avea nicio mentiune in v6; s-a adaugat doar in bulletul nou de la decizia 30 din
sectiunea 8 (unde e cel mai la locul lui) — nu s-a creat sectiune separata pentru asta, planul nu
o cerea explicit.
- "Riscuri" (primele doua puncte din plan) nu au sectiune proprie in mockup si nu li s-a creat una —
continutul lor (perimetrul cu #6 inchis, riscul mutat pe vizibilitatea politicii tehnice) e deja
reflectat implicit in sectiunea 10 ("Ce nu e gratuit") si in bulletul decizia 30.
- Sectiunile 1-7 (formular, buton antet, meniu de adaugare, valuta, discount, puncte de intrare,
ce se scrie la Termina) nu au fost modificate — deciziile rundei 8 nu le afecteaza continutul.
## Contradictii / alegeri facute
- Sarcina mentioneaza "sectiunea despre contul de venit ... (daca exista; altfel o adaugi ca
sectiune noua)". In v6 exista doar un bullet in sectiunea 8, nu o sectiune propriu-zisa — am
tratat asta ca "nu exista" si am creat sectiunea 10, pastrand si bulletul din sectiunea 8 (actualizat,
mai scurt, cu trimitere catre sectiunea 10 pentru detalii).
- Pentru pill-ul de pe decizia inchisa am folosit eticheta `decis` (sectiunea 9) si am reutilizat
`raspuns` (sectiunea 8, clasa CSS `pill have`) — nu exista in CSS o eticheta dedicata "decis", dar
clasa `pill have` (verde, „raspuns/rezolvat") e deja folosita cu text variabil in restul
documentului (`exista deja`, `rezolvat`, `da`), asa ca am urmat conventia in loc sa inventez o clasa.

View File

@@ -1,99 +0,0 @@
# Mockup #13 — v7 -> v8 (rundele 9-11, deciziile 31-42), ce s-a schimbat
Fisier atins: `D:\ROA\ROAFACTURARE\docs\mockup_13_formular_unificat.html`. Niciun alt fisier.
Citire unica a HTML-ului (decizia 33); editarile de mai jos s-au aplicat intr-o singura serie, fara
recitire intermediara.
## Sectiuni atinse
- **Eyebrow / marcaj versiune** (linia ~199): `versiunea 7 (runda 8)` -> `versiunea 8 (runda 11)`.
- **Sectiunea 1** (disclosure-ul din panoul Document): decizia 41 — comutatorul unic „Alte date —
analitice, delegat si transport, incasare, adresa de facturare, text aditional” s-a despartit in
**doua** `.disclosure`: unul nou, doar „Incasare” (fara callout numerotat, ca sa nu se renumeroteze
legenda), cu hint „alocare/dezalocare — comutator propriu”; al doilea pastreaza callout-ul 2 si restul
campurilor (fara incasare). Legenda callout-ului 2 a fost rescrisa: titlu „Restul, pliat — doua
comutatoare”, text care explica motivul izolarii (efecte laterale reale doar pe incasare, blocata pe
document emis prin decizia 25, garda de non-alocare scrisa/testata intr-un singur loc).
- **Sectiunea 3** (meniul de adaugare): paragraf nou dupa observatia despre „adauga tot” — decizia 39:
`crsarticole` ramane registrul cantitatii ramase de facturat (folosit la inchiderea automata a
comenzii/avizului), decuplat de gridul incarcat; cautarea pe server ramane cum era in v7, doar
bookkeeping-ul se muta intr-un registru propriu.
- **Sectiunea 4** (Valuta si data cursului): paragraf nou la final — decizia 42: validarea cursurilor
(`verifica_cursuri_valute`) se restrange la valuta articolului cautat, nu mai ruleaza global la
deschidere; diferenta de comportament asumata explicit.
- **Sectiunea 7** (Ce se scrie la Termina): paragraf nou dupa tabel — decizia 35: un singur cod de
scriere contabila, `scrie_factura2` → `contabilizeaza_articol`, si la emitere si la editare (etapa
II); canalul `oscrie_in_fisiere` (folosit azi de #6) nu intra in #13.
- **Sectiunea 8** (Ce trebuie verificat inainte): bulletul „Coordonarea cu #6” (decizia 30) extins cu
decizia 38 — fluxul de editare al lui #6 nu se retrage, coexista cu regenerarea din #13, decizia
despre unificare se ia mai tarziu. Bullet nou, mic, pentru decizia 40 — bug-ul de dezalocare POS se
repara in trecere in S3b, testarea trebuie sa acopere si dezalocarea pe calea veche.
- **Sectiunea 10** (Contul de venit) — **rescrisa integral**, cum a fost cerut:
- decizia 24 ramane barata (`<s>`), neschimbata din v7;
- decizia 27 (tabelul cu cele doua ramuri, gestionabil/negestionabil) neschimbata;
- **decizia 27-bis (reteta VFP in 4 pasi) e acum barata** (`<s>`), cu explicatia abandonarii
(decizia 32 → decizia 34) — tiparul vizual e identic cu cel folosit pentru decizia 24 respinsa,
cerut explicit de mandat;
- **sectiune noua „Decizia 34”**: coloana noua `VANZARI_DETALII_TEMP.CONT_VENIT`, parametrul nou
`V_CONT_VENIT` la coada lui `adauga_articol_factura`, cei trei apelanti interni neatinsi
(BULK COLLECT pe `%ROWTYPE`), ramura noua infasoara `FACT-024`, `descarca_gestiune` o data prin
constructie, plus bulletul „de retinut la implementare” cu cele doua clase VFP separate
(`frm_facturare_articole` / `frm_facturare_articole2`), lista de coloane a `scrie_in_vanzari`, si
excluderea structurala a articolului compus;
- **sectiune noua „Decizia 36”**: tabel cu sursa lui `SCD` (optiune de firma, implicit `4111`, tiparul
din `scrie_incasare2`) si `CU_TVA` (derivat din `proc_tvav > 0`, cu riscul gasit la verificarea
adversariala explicat);
- **sectiune noua „Decizia 37”**: cheia `RF_CONT_ART_FARA_POL`, fara validare de cont, garda de
lungime (`ORA-12899`);
- paragraful „Intrebarea lui Marius, verificata” pastrat (raspunsul nu s-a schimbat fata de v7);
- **„Ce nu e gratuit” rescris** — cele 4 costuri vechi (specifice retetei in 4 pasi, azi abandonate)
inlocuite cu 4 costuri noi: regresia pe toata suita, cele doua clase VFP cablate separat, lista de
coloane a `scrie_in_vanzari`, si absenta validarii pe un cont fara precedent.
- **Sectiune noua 12** *(vezi corectie mai jos — de fapt 11)*: „Puncte marunte ramase”, tabelul a-k din
plan, cu nota „se merge pe recomandare daca Marius nu spune altfel”.
*Corectie fata de un draft intermediar al acestui raport: sectiunea noua e numerotata corect
**11** (urmatorul numar liber dupa 10, cum cere regula „nu renumerota sectiunile existente”), nu 12.*
## CSS
Nicio regula noua, nicio paleta noua. S-au refolosit `pill have` / `pill check`, `<s>`, `table.doc`,
`.tbl`, `ul.tight` — exact ca in v7. Ordonata list (`ol.tight`) a disparut din document odata cu
eliminarea retetei in 4 pasi (nu mai exista niciun `<ol>` in fisier), dar selectorul CSS extins la
`ul.tight, ol.tight` din v7 a fost pastrat neschimbat, pentru refolosire viitoare.
## Ce NU s-a atins
- Deciziile 31 si 33 nu apar in mockup (reguli de lucru interne, nu decizii de produs), cum a cerut
mandatul.
- Decizia 32 nu are sectiune proprie — e reflectata implicit prin explicatia abandonarii retetei in 4
pasi (barata) din sectiunea 10.
- Ramura `ntip = 4` / avize / `SCD` pe aviz — **exclusa deliberat**, nu apare nicaieri in mockup (in
verificare adversariala, conform mandatului).
- Sectiunile 2, 5, 6, 9 nu au fost modificate — deciziile 31-42 nu le ating continutul.
## Verificare
- Ambele fisiere exista pe cale absoluta (`docs\mockup_13_formular_unificat.html`,
`docs\cercetare\mockup_v8_modificari.md`).
- Tag-uri numarate cu regex pe fisierul final: `div` 148/148, `section` 6/6, `table` 11/11,
`tbody`/`thead` 11/11, `tr` 56/56, `ul` 2/2, `ol` 0/0 (eliminat odata cu reteta), `p` 58/58,
`h2` 11/11, `h3` 5/5 — toate echilibrate.
## Contradictii / alegeri facute
- **Numarul callout-ului pe noul disclosure „Incasare” (decizia 41):** am ales sa NU-i dau un numar de
callout propriu, ca sa nu renumerotez legenda existenta (1-4) sau sa creez un al 5-lea item de legenda
pentru un detaliu minor. In schimb am pus un `.hint` inline, dupa tiparul deja folosit in alte locuri
ale mockup-ului (ex. nota „3 linii · comanda CMD 3312 acoperita 100%”) pentru text explicativ fara
callout numerotat.
- **Plasarea deciziei 35:** am ales sectiunea 7 (Ce se scrie la Termina) in loc de o sectiune noua,
pentru ca tabelul de acolo descrie deja exact ce cod scrie fiecare tip de modificare — decizia 35 e o
precizare directa pe acel tabel, nu un subiect separat.
- **Plasarea deciziilor 39/42:** ambele au fost puse ca paragrafe `.meta` la finalul sectiunilor deja
existente (3, respectiv 4) despre subiectul lor, nu ca sectiuni noi — mandatul preciza ca „se vad in
formular”, dar niciuna nu schimba un desen existent (spre deosebire de 41), deci text a fost suficient.
- **Sectiunea 10, „Intrebarea lui Marius, verificata”:** am pastrat-o neschimbata din v7 pentru ca
raspunsul (ROAACNPRO nu cheama `contabilizeaza_articol`, contractul are `id_pol` din cursor) nu s-a
schimbat prin nicio decizie a rundelor 9-11 — doar mecanismul prin care se evita `FACT-024` s-a
schimbat, nu raspunsul la intrebarea de ce nu se aplica si acolo.

View File

@@ -1,193 +0,0 @@
# Cercetare: bifa de deblocare campuri in formularul actual de modificare antet
Sursa: cache text `.vc2` (deja la zi in acest working copy) din `COMUN\clase\`. Investigatie
read-only, fara editare de cod.
## 1. Localizarea clasei `frm_modifica_factura`
**Concluzie**: Clasa e definita in `COMUN\clase\ofacturare_comun.vc2:5262-5774`
(`DEFINE CLASS frm_modifica_factura AS frm_termin_renunt OF "_frm_child.vcx"`), formular modal
mic (Width=613, Height=412), deschis din `frm_facturi.do_modifica`
(`ofacturare_comun.vc2:4538-4637`, `Createobject("frm_modifica_factura", ...)` la linia 4588).
Ancestor chain: `frm_modifica_factura -> frm_termin_renunt -> _frm_child.vcx`.
**Dovezi** — lista completa a controalelor proprii (nume / clasa-baza / caption sau control source):
| Control | Clasa | Caption / rol | Linie |
|---|---|---|---|
| `Ct_clb_ruta` | `ct_clb_cautare` (caut_ora.vcx) | "Ruta" | 5510 |
| `Ct_clb_agent` | `ct_clb_cautare` | "Agent" | 5455 |
| `Ct_clb_delegat` | `ct_clb_cautare` | "Delegat" | 5473 |
| `Ct_clb_masina` | `ct_clb_cautare` | "Masina" | 5491 |
| `clb_adresa_facturare` | `ct_clb_cautare` | "Adresa facturare" | 5418 |
| `Clb_dataora_exp` | `clb_tx_simplu` (lb_tx.vcx) | "Data si ora expedierii", `poRec.dataora_exp` | 5437 |
| `shpTipFactura` / `lblTipFactura` / `cboTipFactura` | shape / label / `_combobox` | "Tip factura", `poRec.tip_saft` (vizibil doar daca `gl406`) | 5335, 5553, 5562 |
| `chkDetaliat` | `_checkbox` | "Listare detaliata", `poRec.listare_detaliata` | 5379 |
| `Ed_tx_simplu1` | `ed_tx_simplu` (lb_tx.vcx) | "Text aditional...", `poRec.text_aditional` | 5528 |
| `chkSerieAct` | `_checkbox` | "Serie factura", `Enabled=.F.` implicit | 5405 |
| `chkNrAct` | `_checkbox` | "Numar factura", `Enabled=.F.` implicit | 5392 |
| `chkDataAct` | `_checkbox` | "Data factura", `Enabled=.F.` implicit | 5353 |
| `chkDataScad` | `_checkbox` | "Data scadenta", `Enabled=.F.` implicit | 5366 |
| `txtSerieAct` | `_textbox` | `poRec.serie_act`, `Enabled=.F.` implicit | 5605 |
| `txtNrAct` | `_textbox` | `poRec.numar_act`, `Enabled=.F.` implicit | 5594 |
| `txtDataAct` | `_textbox` | `poRec.data_act`, `Enabled=.F.` implicit | 5572 |
| `txtDataScad` | `_textbox` | `poRec.data_scad`, `Enabled=.F.` implicit | 5583 |
| `BUT_TERMIN1` / `But_renunt1` | din `frm_termin_renunt` | Terminat / Renunta | 5322, 5328 |
| `Lb_titlu_alb_b121` | label titlu | "Modifica date factura" | 5318 |
## 2. Bifa de deblocare a campurilor
**Concluzie: NU exista o singura bifa care sa activeze/dezactiveze tot antetul.** Ceea ce exista
e altceva: **4 checkbox-uri separate**, cate unul pentru fiecare camp "act" (serie/numar/data
factura + data scadenta), fiecare deblocand DOAR campul lui propriu, si toate 4 pornesc ele
insele dezactivate (`Enabled=.F.`) daca factura nu are deja un "act" atasat. Toate celelalte
campuri (ruta, delegat, agent, masina, adresa, data/ora expeditie, tip factura, listare
detaliata, text aditional) **nu sunt blocate deloc** — sunt mereu editabile, fara nicio bifa.
**Dovezi**:
`Init` (`ofacturare_comun.vc2:5736-5750`):
```
this.chkSerieAct.Enabled = !EMPTY(NVL(poRec.numar_act,0))
this.chkNrAct.Enabled = !EMPTY(NVL(poRec.numar_act,0))
this.chkDataAct.Enabled = !EMPTY(NVL(poRec.numar_act,0))
this.chkDataScad.Enabled = !EMPTY(NVL(poRec.numar_act,0))
```
adica cele 4 checkbox-uri sunt ele insele clickabile doar daca factura are deja `numar_act`
completat (act existent); altfel raman gri, nefolosibile.
Handlerele lor (`:5758-5772`), fiecare cuplat 1-la-1 cu textbox-ul corespunzator:
```
PROCEDURE chkDataAct.Valid
thisform.txtDataAct.Enabled = this.Value
ENDPROC
PROCEDURE chkDataScad.Click
thisform.txtDataScad.Enabled = this.Value
ENDPROC
PROCEDURE chkNrAct.Valid
thisform.txtNrAct.Enabled = this.Value
ENDPROC
PROCEDURE chkSerieAct.Valid
thisform.txtSerieAct.Enabled = this.Value
ENDPROC
```
Nu apeleaza `.activeaza()`/`.dezactiveaza()` pe niciun container — seteaza direct
`Enabled = this.Value` pe textbox-ul propriu. Nu exista alt mecanism de blocare (nu se apeleaza
`dezactiveaza()` in `Init` pe vreun container din formular — vezi punctul 5).
## 3. Campuri sub bifa vs. campuri libere
**Concluzie**: singurele campuri gatate sunt cele 4 legate de documentul "act" (justificativ):
serie act, numar act, data act, data scadenta. Serie/numar **ale facturii insesi** nu sunt pe
acest formular deloc (se aloca ireversibil la emitere, prin `poGeneratorNumere`, in afara acestui
flux). Delegat/agent/masina/ruta/adresa sunt tratate identic intre ele — toate prin containere
`ct_clb_cautare` fara nicio gata de `Enabled`/`ReadOnly` proprie in acest formular.
**Dovezi**: vezi tabelul de la punctul 1 — coloana "Caption / rol" arata `Enabled=.F.` explicit
doar pe cele 4 perechi checkbox+textbox de "act"; niciun `Enabled=.F.` sau apel de dezactivare pe
`Ct_clb_ruta`/`Ct_clb_agent`/`Ct_clb_delegat`/`Ct_clb_masina`/`clb_adresa_facturare`/
`Clb_dataora_exp`/`chkDetaliat`/`Ed_tx_simplu1`/`cboTipFactura`.
## 4. Calea de salvare
**Concluzie**: la `Terminat` (`gnButon=1`), se apeleaza **`pack_facturare.modifica_date_factura`**
o data pentru fiecare factura selectata, cu 14 parametri — toti metadate de antet/logistica, deci
salvarea antetului e **complet independenta de articole/note contabile**: nu exista in
`do_modifica` niciun apel spre `oscrie_in_fisiere`, `pack_contafin`, sau vreun cursor de articole.
**Dovezi** (`ofacturare_comun.vc2:4587-4630`, `do_modifica` pe `frm_facturi`):
```
If poRec.sters = 0 AND NVL(m.pnEFactura,0) = 0
ofrmmodificare = Createobject("frm_modifica_factura", ...)
ofrmmodificare.Show(1)
...
If gnButon = 1
...
Scan For &lcFiltru
TEXT TO lcSql NOSHOW TEXTMERGE
begin pack_facturare.modifica_date_factura(<<...id_vanzare...>>,
<<...id_ruta...>>, <<...id_delegat...>>, <<...id_agent...>>, <<...id_masina...>>,
to_date('<<TTOC(poRec.dataora_exp,1)>>','YYYYMMDDHH24:MI:SS'),
<<...id_facturare...>>, <<...listare_detaliata...>>,
?poRec.text_aditional, ?poRec.tip_saft, ?poRec.efactura,
?poRec.data_act, ?poRec.data_scad, ?poRec.numar_act, ?poRec.serie_act);
end;
ENDTEXT
lnSucces = goExecutor.oExecute(lcSql)
ENDSCAN
Endif
Else
amessagebox("Nu puteti face modificari pe inregistrarile sterse sau facturile trimise in eFactura!", 48, "Atentie")
Endif
```
Garda de intrare (poate edita doar daca nu e stearsa si nu e in eFactura) e la linia 4587,
verificarea `anaf_efactura` la 4583-4585. Se poate confirma direct din semnatura RPC-ului
(`id_vanzare, id_ruta, id_delegat, id_agent, id_masina, dataora_exp, id_facturare,
listare_detaliata, text_aditional, tip_saft, efactura, data_act, data_scad, numar_act,
serie_act`) ca nu exista niciun parametru de articol/nota — deci da, **antetul se salveaza singur,
fara sa atinga restul documentului**.
## 5. Conventia de containere blocabile in suita (`clb_*`/`ct_clb_*`)
**Concluzie**: conventia exista, dar **e inconsistenta intre clase si niciuna din variantele cu
adevarat blocante nu e folosita in `frm_modifica_factura`**. Trei situatii diferite gasite:
1. **`ct_clb_cautare`** (`caut_ora.vc2:710`, folosit de `Ct_clb_ruta/agent/delegat/masina/
clb_adresa_facturare`) — are `do_activeaza()`/`do_dezactiveaza()` (property `lactiv`,
`caut_ora.vc2:780-806`), dar acestea **nu blocheaza textbox-ul** (care e oricum
`ReadOnly=.T.` prin design — editarea se face doar prin popup de cautare, nu prin tastare
directa), ci doar ascund iconita de cautare si tooltip-ul:
```
PROCEDURE do_dezactiveaza
This.lactiv = .F.
This.img_cautare.Visible = .F.
...
ENDPROC
```
Popup-ul se declanseaza doar daca `This.Parent.lactiv` e adevarat (`DblClick`/`KeyPress`/
`img_cautare.Click`, :819-844). **Confirmat prin grep: `do_activeaza`/`do_dezactiveaza` NU sunt
apelate nicaieri in `ofacturare_comun.vc2`** — deci in `frm_modifica_factura` raman mereu
`lactiv=.T.` (valoarea implicita), adica mereu deblocate.
2. **`clb_tx_data`** (`lb_tx.vc2:461-548`, container de camp-data cu buton calendar — NU e folosit
in `frm_modifica_factura`, dar e "sora" a `clb_tx_simplu` in aceeasi biblioteca) — are metodele
care fac chiar ce cere Marius: `dezactiveaza()`/`reactiveaza()` (`lb_tx.vc2:521-538`):
```
PROCEDURE dezactiveaza
This.text_simplu1.ReadOnly = .T.
This.text_simplu1.TabStop =.F.
This.cmd_buton1.Enabled = .F.
ENDPROC
PROCEDURE reactiveaza
This.text_simplu1.ReadOnly = .F.
This.text_simplu1.TabStop =.T.
This.cmd_buton1.Enabled = .T.
ENDPROC
```
3. **`clb_tx_simplu`** (`lb_tx.vc2:551-585`, chiar clasa folosita pentru `Clb_dataora_exp` in
`frm_modifica_factura`) — **nu are nicio metoda `activeaza`/`dezactiveaza`/`reactiveaza`**
(verificat prin grep pe intreg intervalul clasei).
4. **`clb_serie_act`** (`serii_numere.vc2:7`, containerul dedicat seriei-numarului de document) —
**nu are nicio metoda `activeaza`/`dezactiveaza`** (grep negativ pe tot fisierul).
Deci: mecanismul "blocheaza antetul, deblocheaza-l la bifa" **NU exista gata-facut la nivel de
container** pentru containerele efectiv folosite in `frm_modifica_factura`. Ce exista deja, gata
de reutilizat ca tipar (nu ca apel direct), e reteta din `clb_tx_data.dezactiveaza()/reactiveaza()`
(punctul 2 de mai sus, ReadOnly+TabStop+buton) — si tiparul checkbox-pe-camp deja folosit chiar in
`frm_modifica_factura` pentru cele 4 campuri "act" (`Enabled = this.Value` pe `Valid`/`Click`,
punctul 2 de mai sus).
## Necunoscute ramase
- Nu am gasit in `ROAFACTURARE` niciun formular existent care sa foloseasca o **singura** bifa
pentru a debloca simultan tot un grup de campuri de antet (nu doar `frm_modifica_factura`) —
posibil exista un asemenea tipar in alt produs ROA (ROAGEST/ROACONT) sau in alta clasa
ne-cautata aici; nu am extins cautarea in afara `ROAFACTURARE\COMUN`.
- Comportamentul exact al `ReadOnly=.T.` pe `ct_clb_cautare.clb_tx_cautare.text_simplu1`
(adica daca userul poate edita manual textul cand `lactiv=.F.`, sau doar iconita dispare) nu a
fost testat vizual/headless, doar dedus din cod.
- Nu am verificat daca exista vreo diferenta de comportament la nivel de `_frm_child.vcx` /
`frm_termin_renunt` (clasele parinte) care ar putea injecta alt mecanism de blocare — am citit
doar metodele proprii ale `frm_modifica_factura`, nu ascendenta completa.

View File

@@ -1,199 +0,0 @@
# Cercetare — proforma, copiere document, puncte de intrare comanda/contract
Investigatie read-only, 09.08.2026. Nicio modificare de cod. Vezi si `docs\plan_13_unificare_formular_facturare.md`
si `docs\handoff_13_formular_unificat.md` (sesiune paralela, activa la data cercetarii — nu s-a atins
`COMUN\clase\ofacturare_comun.vc2` si nici `COMUN\programe\ofacturare_editare.prg`, marcate acolo ca "in lucru").
## 1. Proforma
**Concluzie.** Proforma nu e un tip de document separat (`poDate.tip` ramane 1-52, ca la orice
factura), ci un **atribut de numerotare/serie** (`poDate.nIdTipDoc = 23`, fata de `5` = FACTURA).
Se seteaza dintr-un combo "Tip document" (FACTURA/PROFORMA/BON FISCAL) aflat direct pe formularul
de antet unificat `frm_date_factura` — **acelasi formular** folosit si pentru facturi normale, fara
formular separat. Combo-ul e vizibil doar cand `frm_date_factura` e instantiat, adica doar pentru
tipuri de "factura" (nu si pentru avize, care merg pe `frm_date_aviz`, fara acest combo).
Nu exista un buton/meniu dedicat "Proforma noua": utilizatorul apeleaza fluxul normal de facturare
(`factureaza(tnTip)`) si comuta manual pe PROFORMA in antet.
**Dovezi:**
- `COMUN\programe\ofacturare_comun.prg:593-599` — setter-ul care leaga `nIdTipDoc` de `eProforma`:
`This.eProforma = IIF(m.tnIdTipDoc = This.nIdTipDocProforma, 1, 0)` (`nIdTipDocProforma = 23`,
`COMUN\programe\ofacturare_comun.prg:104`).
- `COMUN\clase\ofacturare.vc2:9396-9403` — `frm_date_factura.do_schimba_tipdoc`:
`lcTipDoc = UPPER(this.ct_clb_fdoc._combobox1.Value)` → mapare FACTURA/PROFORMA/BON FISCAL/AVIZ
la `nIdTipDoc`.
- `COMUN\clase\ofacturare.vc2:8745-8754` — combo-ul: `RowSource = "FACTURA,PROFORMA,BON FISCAL"`,
`Value = FACTURA` (implicit). Owner confirmat cu `vfp_symbols.ps1 -Where`:
`frm_date_factura [class] ofacturare.vc2:8482-9869`.
- `COMUN\clase\ofacturare.vc2:9415,9427-9428` — la schimbarea tipului: `initializeaza_setari_document(-102)`
pentru proforma, `poGeneratorNumere.dezaloca_numar(...)` + `creeaza_cursor_serii(poDate.nIdTipDoc)` —
**serie/numar propriu**, realocat la comutare.
- `COMUN\programe\ofacturare.prg:81-196` — `factureaza(tnTip, toFactura)`: la creare, `poDate.nIdTipDoc`
se seteaza explicit la `5` (FACTURA) sau `6` (AVIZ) dupa `tnTip` (`:187-196`); PROFORMA (23) nu
apare niciodata aici — se ajunge la ea **doar** din interactiunea cu combo-ul din antet.
- **Fara note contabile pe proforma**: `COMUN\programe\ofacturare.prg:1960,1996,2052,2063,2103` —
blocurile de scriere/actualizare nota contabila si atasamente sunt garzduite cu
`poDate.eProforma = 0`.
- **Continut specific de raport**: `COMUN\programe\ofacturare.prg:1119` (`Case poDate.eProforma = 1`)
ramifica pe un SQL de antet propriu (parteneri/adresa facturare) pentru listare; `:1638-1643`
(`Case ... And poDate.eProforma = 1` → `lcRaport = [PROFORMA]`) alege formularul `.fr2` dedicat
(`COMUN\Rapoarte\proforma.fr2`, `proforma_orig.fr2`, `proforma_val.fr2`).
- **Transformare in factura = copiere**: tooltip explicit,
`COMUN\clase\ofacturare_comun.vc2:1409`: *"Copiere (CTRL+K) * Se foloseste si pentru generarea
unei facturi din proforma prin copiere"*. Mecanismul: la copiere (`completeaza_setari_document`,
vezi §2) linia care ar propaga `nIdTipDoc` de la documentul sursa e **comentata**
(`COMUN\programe\ofacturare_comun.prg:370`: `*.nIdTipDoc = toDateAnterior.nIdTipDoc`), deci noul
document porneste implicit la `nIdTipDoc=5` (FACTURA) indiferent ca sursa era proforma — functioneaza,
dar prin omisiune, nu printr-o ramura dedicata "proforma → factura".
- **Relistare proforma**: cale separata de `factureaza`, in gridul de facturi:
`COMUN\clase\ofacturare_comun.vc2:7230-7264` (`PROCEDURE do_listare`, alt context decat
`frm_facturi.do_listare`) — filtreaza `crsFacturi` dupa `id_proforma=`, forteaza
`poDate.eProforma = 1` si `poDate.nRelistare = 1` (`:7258-7260`).
- Referinta tipuri: `COMUN\docs\tipuri_documente_facturare.md` — confirma ca `TIP` (1-52) e ortogonal
fata de proforma; niciun rand din tabel nu e "proforma" ca atare.
**Ce e specific proformei, confirmat cu dovada:**
1. Serie/numar propriu (`nIdTipDoc=23`, realocare la comutare din combo).
2. Fara scriere de nota contabila / atasamente (gate `eProforma=0` in `ofacturare.prg`).
3. Raport de listare propriu (`.fr2` dedicate).
4. "Transformare in factura" = copiere obisnuita, care scapa tipul de document proforma pentru ca
linia de propagare e comentata (efect secundar, nu design explicit).
**Nu am putut confirma cu dovada** (vezi "Necunoscute ramase"): daca descarcarea de gestiune e
efectiv sarita pentru proforma la nivel de Oracle (`PACK_FACTURARE`, sursa nu e in cache text local).
## 2. Copierea documentului
**Concluzie.** Traseul e `frm_facturi.But_copiaza1.Click` → `do_copiaza` (degradeaza tipul) →
`copiere_factura` → `factureaza(tip_degradat, toFactura)` → `frm_date_factura` cu antetul
pre-completat din `completeaza_setari_document(toFactura, .T.)`. Se aloca **intotdeauna** numar nou
(alocarea de serie ruleaza neconditionat in `factureaza`, indiferent de `llCopiere`). Campurile de
antet raman editabile (nimic din traseu seteaza `Enabled=.F.` pe controale de antet la copiere);
singurul efect vizibil e relabelarea campului "Altele" in "Nr. factura" cand tipul degradat e
1/5/10/48/49 sau 48/49 sub `gnScadereStoc=0`.
**Dovezi:**
- `COMUN\clase\ofacturare_comun.vc2:3628-3713` — `do_copiaza`: degradeaza tipul (tabelul deja
cunoscut, ex. `T2/T3/T4/T8/... → T1`, `:3696-3710`), apoi `DO copiere_factura WITH loFactura IN
oproceduri_facturare.prg` (`:3710`).
**Bug observat, nu cerut de investigat**: ramura `CASE INLIST(loFactura.tip,T21,T24,T26,T30,...)`
(`:3702-3703`) scrie `lnTip = T22` in loc de `loFactura.tip = T22` — variabila gresita, degradarea
nu se aplica efectiv pe aceasta ramura (avize catre clienti din comanda/contract/retur etc.).
- `COMUN\programe\oproceduri_facturare.prg:150-153` — `copiere_factura`: `factureaza(toFactura.Tip,
toFactura)`.
- `COMUN\programe\ofacturare.prg:111` — `llCopiere = (Type('toFactura') = 'O')`;
`:203-206` — `If m.llCopiere: poDate.completeaza_setari_document(m.toFactura, .T.)`.
- `COMUN\programe\ofacturare_comun.prg:362-412` — `completeaza_setari_document(toDateAnterior,
tlFactura)`: ramura `tlFactura=.T.` (copiere) seteaza `.lCopiere=.T.` si precompleteaza
lucrare/sectie/agent/delegat/masina/`listaid = toDateAnterior.id_vanzare`/`descriere`
(serie+numar sursa)/client (`:368-390`); **nu** propaga `nIdTipDoc`, `id_responsabil`,
`id_venchelt` (comentate, `:370,373,377`).
- **Numar nou, mereu**: `COMUN\programe\ofacturare.prg:208,211` — `poGeneratorNumere.ResetNumere()`
+ `poDate.rezultat_serii = poGeneratorNumere.creeaza_cursor_serii(poDate.nIdTipDoc)` ruleaza in
bucla principala a lui `factureaza`, inainte de a deschide formularul, **neconditionat de
`llCopiere`**. Functia: `COMUN\programe\oserii_numere.prg:128-177` (`Function
creeaza_cursor_serii`).
- **Relabel antet la copiere**: `COMUN\clase\ofacturare.vc2:9622-9628,9652-9658` —
`IF m.llCopiere: .ct_clb_altele.do_schimba_explicatia([Nr. factura])` (altfel campul e eliminat
din formular pentru acele tipuri).
- **Reutilizabil vs specific degradarii**: reutilizabil = `copiere_factura`/`factureaza(tip,
toFactura)`/`completeaza_setari_document` (mecanismul general de copiere, indiferent de tip);
strict legat de degradare = tabelul `#DEFINE T.../DO CASE` din `do_copiaza` (`:3629-3708`) — acolo
se decide explicit "ce tip devine ce tip la copiere", nimic din asta nu se refoloseste in afara
acestei metode.
## 3. Punctele de intrare "factura din comanda" / "factura din contract"
**Concluzie.** Ambele exista deja, **cu precompletare reala**, dar pe cai diferite:
- **Contract**: azi precompletarea vine **din ROACONTRACTE** (produs separat), nu din ROAFACTURARE.
Butonul "Factura" de pe gridul de contracte populeaza globalul `goContract` din randul selectat si
cheama acelasi `factureaza(2/6/52)` din COMUN.
- **Comanda**: exista deja un buton de facturare **direct in ROAFACTURARE**, pe tab-ul Comenzi
(`Page5.Ct_comenzi1`), care populeaza `goComanda` din randul de grid selectat inainte de a chema
`factureaza(3)` — deci raspunsul la "exista deja un buton?" e **da**, nu ipotetic.
- Exista si o cale **generica, nepre-completata**, in meniul principal al ROAFACTURARE
(`Clase\ofundal_facturare.vc2`, tab Page2): pentru contract nu atinge `goContract`; pentru comanda
**reseteaza explicit** `goComanda = ''` inainte de apel — utilizatorul alege manual din formular.
**Semnatura `factureaza`:**
```
COMUN\programe\ofacturare.prg:81-82
Procedure factureaza
Lparameters tnTip, toFactura
```
`tnTip` = tipul de business (1-52, tabelul din `tipuri_documente_facturare.md`); `toFactura` = obiect
opational, folosit azi **doar** pentru copiere factura/aviz (nu pentru contract/comanda). Nu exista
parametru dedicat pentru "contract precompletat" sau "comanda precompletata" — canalul e globalul
`goContract`/`goComanda`, citit in `oDateFactura.Init`.
**Dovezi — mecanismul comun (globale citite la creare `poDate`):**
- `COMUN\programe\ofacturare_comun.prg:261-297` — `Init`, ramura
`If INLIST(m.tnTip, 2, 6, 52) And Type('goContract') <> 'U'` → `.id_client = goContract.id_part`,
`.listaid = goContract.id_ctr`, `.descriere = goContract.contract`, plus interogare
`fact_vcontracte` pentru scadenta (`:274-296`).
- `COMUN\programe\ofacturare_comun.prg:301-328` — ramura
`If tnTip = 3 And Type('goComanda') = 'O'` → `.id_client = goComanda.id_part`,
`.listaid = goComanda.id_comanda`, `.descriere = goComanda.nr_comanda`, plus interogare sectie
(`:312-323`).
**Dovezi — contract, din ROACONTRACTE:**
- `D:\ROA\ROACONTRACTE\Clase\ferestre_contracte.vc2:1605` — `grid_contracte.AfterRowColChange`:
`SCATTER NAME goContract MEMO` la fiecare schimbare de rand selectat.
- `D:\ROA\ROACONTRACTE\Clase\ferestre_contracte.vc2:1538-1549` — `but_factura.Click`: meniu
"Factura lei;Invoice;Factura fiscala in valuta" → `DO facturare_contracte WITH 'FACTURA LEI'/...
IN oproceduri_facturare.prg` (copia locala din `ROACONTRACTE\COMUN`, acelasi cod ca in
ROAFACTURARE).
- `COMUN\programe\oproceduri_facturare.prg:118-136` — `facturare_contracte(tcTip)` →
`factureaza(2)` / `factureaza(6)` / `factureaza(52)`.
- **Cale generica, fara precompletare**, in ROAFACTURARE insusi:
`Clase\ofundal_facturare.vc2:886-897` (`Page2.Cw2.do_actiune`) — acelasi meniu, aceeasi
`facturare_contracte`, dar **nu** atinge `goContract` inainte — daca globalul nu a fost populat
in sesiune (`Type('goContract') = 'U'`), ramura de precompletare din `Init` nu se activeaza si
userul alege contractul manual din `frm_date_factura.do_cauta_contract`
(`COMUN\clase\ofacturare.vc2:9067-9115`, deja cunoscut din context).
**Dovezi — comanda, buton deja existent in ROAFACTURARE:**
- `COMUN\clase\ocomenzi.vc2:1580-1596` — `ct_comenzi.do_factura`:
`SELECT crsComenzi` → `SCATTER NAME goComanda MEMO` → `DO facturare_comenzi IN
oproceduri_facturare.prg` → `this.do_cauta()`.
- `COMUN\clase\ocomenzi.vc2:932-937` — butonul: `ADD OBJECT 'But_factura1' AS but_factura`, clasa
de baza `COMUN\clase\cmd_butoane.vc2:96-107` (`DEFINE CLASS but_factura ... caction = do_factura`,
`ToolTipText = "Factura"`, `Picture = factura1.bmp`).
Vizibilitate conditionata de starea comenzii: `COMUN\clase\ocomenzi.vc2:2199-2203`
(`grid_comenzi...`) — `this.Parent.but_factura1.Visible = (goComanda.facturat = 0)` (ascuns daca
deja facturata).
- **Montare in ROAFACTURARE**: `Clase\ofundal_facturare.vc2:604` — `ADD OBJECT 'Page5.Ct_comenzi1'
AS ct_comenzi`; `Ferestre\fundal.sc2:206` — `Page5.Ct_comenzi1.But_factura1.Name = "But_factura1"`
confirma montarea concreta pe formular (nu doar in clasa sursa).
- `COMUN\programe\oproceduri_facturare.prg:138-141` — `facturare_comenzi` → `factureaza(3)`.
- **Cale generica, fara precompletare**: `Clase\ofundal_facturare.vc2:899-902`
(`Page2.Cw3.do_actiune`): `goComanda = ''` apoi `DO facturare_comenzi ...` — reseteaza explicit
globalul inainte de apel, deci userul alege comanda manual in formular.
**Concluzie combinata pentru "gazda naturala"**: pentru comanda, gazda exista deja
(`COMUN\clase\ocomenzi.vc2`, buton `But_factura1`, montat in `Clase\ofundal_facturare.vc2` Page5).
Pentru contract, gazda echivalenta **nu exista in ROAFACTURARE** — traieste azi doar in
`ROACONTRACTE\Clase\ferestre_contracte.vc2`; daca s-ar dori acelasi tipar in ROAFACTURARE, ar trebui
fie o pagina de contracte proprie (subiectul planului `docs\plan_10_integrare_contracte.md`, azi
"propunere, neinceput", cu decizie go/no-go in asteptare), fie un buton similar montat direct pe o
lista de contracte inexistenta azi in acest produs.
## Necunoscute ramase
1. **Descarcare de gestiune pe proforma**: n-am putut confirma/infirma daca `PACK_FACTURARE`
(server-side Oracle) sare efectiv descarcarea de stoc pentru documente cu `nIdTipDoc=23`. Sursa
pachetului nu e in cache text local (`COMUN\docs\PACK_FACTURARE.pck` nu exista; doar
`PACK_CONTAFIN.pck`, `PACK_UPDATE.pck` etc.). Comentariul din `ofacturare.prg:52` ("daca este
proforma, pun toate articolele negestionabile, ca sa nu mai arate stocul") sugereaza ca partea
VFP trateaza stocul doar vizual, nu ca dovada asupra scrierii server-side.
2. **Campuri de antet blocate la copiere**: am confirmat ca traseul de copiere nu seteaza explicit
`Enabled=.F.` pe controale de antet (nimic gasit in `frm_date_factura` pentru `llCopiere`), dar
nu am verificat exhaustiv fiecare control individual — doar relabelarea campului "Altele".
Tratati ca "probabil toate editabile", nu ca fapt verificat camp-cu-camp.
3. **Bug-ul din `do_copiaza` (`:3702-3703`, `lnTip` in loc de `loFactura.tip`)** e raportat ca
dovada gasita in timpul cercetarii, nu ca urmare a unei cereri explicite de audit — nu a fost
verificat efectul lui in productie (date de test).
4. **ROACONTRACTE nu are cod la fel de detaliat verificat ca ROAFACTURARE**: desi are cache text
(203 fisiere `.vc2/.sc2`, contrar notei mai vechi din `plan_10_integrare_contracte.md` care spunea
ca nu exista), nu am facut o trecere completa a formularului de contracte — doar traseul minim
pentru `but_factura.Click`.

View File

@@ -1,19 +0,0 @@
set linesize 32767
set pagesize 200
set trimspool on
set feedback on
set heading on
prompt ==MEMBRI_POLITICA_7==
select count(*) from crm_politici_pret_art where id_pol=7;
select id_pol_art, id_articol from crm_politici_pret_art where id_pol=7;
prompt ==CATE_LINII_COMENZI_ELEMENTE_ID_POL_7_TOTAL==
select count(*), sum(case when cantitate<0 then 1 else 0 end) as negative, sum(case when cantitate>0 then 1 else 0 end) as pozitive
from comenzi_elemente where id_pol=7 and sters=0;
prompt ==DISTINCT_ARTICOLE_PE_POLITICA_7_IN_COMENZI==
select id_articol, count(*), sum(cantitate) from comenzi_elemente where id_pol=7 and sters=0 group by id_articol;
prompt ==DONE==
exit

View File

@@ -1,6 +1,6 @@
# Cine sunt "cele 41 de facturi" de la decizia 9, si daca `cod=1138989` e printre ele
Intrebare deschisa 4 din `docs\handoff_sesiune_08082026.md`. **Se raspunde din date, nu are nevoie
Intrebare deschisa 4 din handoff intermediar (sters). **Se raspunde din date, nu are nevoie
de Marius.** Sursa: `MARIUSM_AUTO@ROA_CENTRAL`, 08.08.2026.
## Definitia care da exact 41

View File

@@ -1,220 +0,0 @@
# Inventar consumatori `VANZARI.AVIZE`/`CURS`/`ID_VALUTA`/`MULTIPLICATOR` in suita ROA
Cercetare STRICT de citire (fara modificari de cod, fara DDL, fara conexiuni DB, fara rulare de
conversii noi `vcx2txt.ps1`/`git_sync.ps1`) — masoara riscul de comportament schimbat dupa
corectiile S4 (AVIZE, WHERE lipsa) si S8/curs (garda `nin_valuta`) aplicate in `PACK_FACTURARE`
(vezi `rec_s4_aplicare.md`). Executata cu 3 subagenti in paralel: (a) ROAFACTURARE+COMUN, (b) cele
8 produse cu cache text deja generat, (c) restul suitei (~56 directoare).
## RISC REAL
**1. Referinta la aviz dispare de pe factura retiparita (tip=4).**
`COMUN\programe\oproceduri_facturare.prg` (`listeaza_formular`, ~:1125/:1189/:1265) si dublura ei
`COMUN\clase\ofacturare_comun.vc2` (`frm_facturi.do_listeaza_formular`, ~:4103/:4204) — cod
partajat, prezent in tot ecosistemul ROA*. Construiesc `crsFacturaListare` din `FACT_VFACTURI2`
(coloana `altele` = alias pentru `vanzari.avize` cand `tip in (4,24,8,9)`), apoi
`poDate.descriere = Alltrim(altele)` specific pentru `tip=4` ("factura din aviz"). `poDate.descriere`
ajunge pe formularul tiparit ca referinta "nr. aviz" (layout exact in `.frx`, neconvertit — vezi
gap mai jos). **Ce se schimba**: la retiparirea/relistarea unei facturi `tip=4` mai vechi, unde
`vanzari.avize` era populat gresit inainte (smearat de UPDATE-ul fara WHERE) si acum e gol pentru
majoritatea facturilor, referinta la aviz dispare vizibil de pe document. E in calea de reprint,
nu de emitere — deci afecteaza utilizatorul la orice reeditare/retiparire ulterioara corectiei.
**2. Nota "Curs: X RON/valuta" pe factura electronica/PDF, generata fara verificare `in_valuta`.**
`xmlefactura.prg` (COMUN partajat, cod identic — verificat prin hash — in ROAEFACTURA, ROASITFIN,
ROACONIMPORT, ROAPRINT, ROAPRODUCTIE, ROACONT/OUTPUT, si prezent si in ROAFACTURARE/COMUN):
```
IF !EMPTY(NVL(loDate.curs,0)) AND ATC('curs', m.lcTextAditional) = 0
lcTextAditional = ... + "Curs: " + ALLTRIM(STR(loDate.curs,10,4)) + " RON/" + ... loDate.cValuta ...
ENDIF
```
Conditia verifica doar `curs` nenul, nu si `loDate.in_valuta` (spre deosebire de blocul de cateva
linii mai jos, `DocumentCurrencyCode`, care testeaza corect `in_valuta=1`). Inainte, facturile in
LEI aveau deja `curs` populat gresit (bug), deci nota aparea eronat, dar cu o valoare "plauzibila".
**Ce se schimba**: dupa corectie, `curs=1` pe facturile in lei — `!EMPTY(1)` tot trece, deci nota
tot apare, dar acum arata constant `"Curs: 1.0000 RON/"` cu sufix de valuta gol (`id_valuta=0`).
Vizibil pe fiecare factura/aviz in lei exportata ca e-factura sau tiparita, in toate produsele de
mai sus.
## RISC POSIBIL
3. **`ofacturare_comun.vc2:4156-4157`** (si dublura `oproceduri_facturare.prg:1225-1226`): dupa
blocul `If poDate.in_valuta = 1 ... Else ... Endif`, `poDate.Curs`/`poDate.multiplicator` sunt
suprascrise necondiționat din valorile citite din view. Calculul de discount e corect protejat
de `in_valuta=1`, dar nu s-a putut confirma daca FRX-ul (neconvertit) afiseaza aceste campuri
necondiționat de `in_valuta`. De verificat in layout-ul tiparit.
4. **`vizualizare_facturi2` (`oproceduri_facturare.prg:431-479`)**: grid-ul de cautare/listare
facturi expune coloanele `altele`, `curs`, `multiplicator`, `valuta`, `id_valuta`, `nume_val`
direct din `FACT_VFACTURI2`. Nu s-a putut confirma legarea la `ControlSource` in `.scx`
(neconvertit) — daca vreuna e legata vizibil intr-un grid, utilizatorii ar vedea coloane
goale/"1" unde inainte vedeau valori (gresite).
5. **ROAACNPRO** `Programe\proceduri_acnpro.prg:1180-1229`, `calcul_penalitati` (calea activa):
`Select v.Curs, v.id_Valuta ... left join vnom_valute vl on v.id_valuta = vl.id_valuta From
vanzari v`, afisat probabil intr-un grid de review inainte de generarea facturilor de
penalizare. Calculul numeric al penalitatii NU foloseste `curs` (confirmat), deci fara risc de
calcul; ramane risc de **afisare**: `id_valuta=0` ar putea sa nu se potriveasca in
`left join vnom_valute` (tabela de valute proprie ACNPRO, distincta de `NOM_VALUTE`), lasand
coloana `valuta` goala. Nu s-a putut confirma daca `vnom_valute` are un rand pentru
`id_valuta=0` (spre deosebire de `NOM_VALUTE`, unde existenta randului `id_valuta=0` a fost deja
confirmata in `rec_s4_aplicare.md`, punctul 3 din sectiunea S8/curs — deci pentru view-urile
`FACT_VFACTURI*` din COMUN acest risc e deja exclus, ramane specific tabelei proprii ACNPRO).
6. **ROAAUTO** `Programe\oproceduri_devize.prg:1486-1532`, `relisteaza_factura_deviz`: citeste
`curs`/`multiplicator`/`altele` din `fact_vfacturi` la reafisarea unei facturi, dar cursorul se
inchide imediat fara ca valorile sa fie propagate mai departe — risc redus, de reverificat doar
daca un apelant viitor se bazeaza pe acelasi cursor.
7. **`CONTAFIN2ORA\VFP2ORA\Programe\acn.prg:~1247-1319`** (unealta de migrare, nu produs curent de
vanzare): scrie direct `curs`/`id_valuta`/`multiplicator` in `INSERT INTO VANZARI` +
`MERGE INTO VANZARI_CURSURI`, cu propria regula de zero-ing independenta de `PACK_FACTURARE` —
probabil neafectata functional, dar merita o verificare separata daca unealta mai e folosita
activ.
## FARA RISC (rezumat, nu enumerate)
- **ROAFACTURARE+COMUN**: restul celor ~930 potriviri brute pentru `AVIZE`/`CURS`/`ID_VALUTA`/
`MULTIPLICATOR`/`ALTELE` — module NIR/import, balante/parteneri/compensari, salarii, curs
valutar BNR, sau citiri deja corect protejate de `in_valuta`/`tip_valuta`
(`ofacturare.prg::listeaza_ofacturare` la emitere, `ofacturare_stoc.prg`, `anaf_efactura.prg` cu
`decode(in_valuta,1,curs,1)`, `makexmlfacturaelectronica.prg` cu garda `mmoneda<>"RON"`). Niciun
hit `.avize` (acces direct de camp) in afara celor doua raportate mai sus.
- **ROACONT**: `Programe\saft_d406.prg` (declaratia fiscala D406, `oSalesInvoices`) — foloseste
`DECODE(v.in_valuta, 0, 0, ...)` explicit, output SAF-T neschimbat de corectie. Restul hit-urilor
pe tabele proprii (`ireg_parteneri`, `act`, `rul`) sau text necorelat.
- **ROAACNPRO** (restul), **ROACONTRACTE**, **ROAGEST**, **ROAIMOB**, **ROAREGISTRATURA**,
**ROASTART**: zero hit relevant legat de `VANZARI` in afara COMUN (verificat, nu doar negasit).
- **~40 de produse din restul suitei** (ROAEFACTURA si variante, ROASITFIN, ROAPRINT,
ROACONIMPORT, ROAPRODUCTIE, ROAHOTEL si variante, ROASAL, ROAMANAGER, ROADECL, ROAPRETURI,
ROABAZA, ROAAPROV, ROADEVIZE, etc.): hit-uri pe "AVIZE" = conceptul de business "aviz de
expeditie" (tip document), nu coloana; hit-uri "CURS"/"ID_VALUTA" pe alte tabele proprii sau in
`oDateFactura` (populate de apelant, protejate de `in_valuta`). `COMUNROA` (depozitul central)
contine doar scripturi de deployment, fara logica de facturare.
## Rezumat acoperire
- **ROAFACTURARE + COMUN local**: acoperire completa `.prg` + `.vc2`/`.sc2` via `vfp_symbols.ps1
-CodeOnly` (index deja construit). **Gap**: 207 `.frx` si 30 `.mnx` fara `.fr2`/`.mn2` in cache —
layout-ul efectiv tiparit (unde `poDate.descriere`/`Curs`/`cValuta` chiar apar pe hartie) nu e
verificabil fara conversie (interzisa in acest task). Riscurile REAL #1/#2 si POSIBIL #3/#4
depind partial de acest layout.
- **8 produse cu cache text existent** (ROAACNPRO, ROAAUTO, ROACONT, ROACONTRACTE, ROAGEST,
ROAIMOB, ROAREGISTRATURA, ROASTART): acoperire completa `.prg` + `.vc2`/`.sc2` via
`vfp_symbols.ps1 -CodeOnly`. **Gap**: proprietati/metadata (`ControlSource` de grid legat direct
de o coloana, fara linie de cod explicita) nu apar in `-CodeOnly` — dar un asemenea caz s-ar
clasifica oricum FARA RISC (simpla afisare).
- **Restul suitei** (~56 directoare, inclusiv `COMUNROA`): acoperire **doar** pe fisierele `.prg`
(text simplu, nu necesita conversie); zero cache text pentru `.vcx`/`.scx` — **niciun cod din
clase/formulare compilate al acestor produse nu a fost verificat**, conform interdictiei de a
genera cache nou. ~35 produse identificate ca in afara domeniului (unelte/infrastructura: SSH,
server, telefonie, criptare, declaratii D1xx/D3xx/D406 etc.) fara nicio potrivire pe termenii
cautati.
- Nicio conexiune la baza de date folosita; cifrele despre distributia datelor (ex. randul
`id_valuta=0` din `NOM_VALUTE`) sunt preluate din `rec_s4_aplicare.md`, deja documentate.
## Concluzie
Doua locuri cu **risc real** confirmat, ambele in codul COMUN partajat (deci efect cross-project):
disparitia referintei la aviz de pe facturile `tip=4` retiparite, si textul "Curs: 1.0000 RON/"
afisat gresit pe nota facturii electronice/PDF pentru facturile in lei. Restul e risc posibil,
dependent de layout-uri `.frx`/`.scx` neconvertite (gap de acoperire cunoscut, nu absenta de risc).
Nu s-a gasit niciun consumator cu risc real de **calcul** (sume/discounturi) — toate caile de
calcul verificate sunt deja protejate corect de `in_valuta`.
---
## Corectie aplicata — riscul REAL #2 (nota "Curs:" din `xmlefactura.prg`)
Modificare de cod, ceruta explicit de team-lead dupa livrarea inventarului de mai sus. Domeniu:
**doar** `D:\ROA\ROAFACTURARE\COMUN\programe\xmlefactura.prg`. Nicio alta copie din suita nu a
fost atinsa.
### Ce s-a schimbat
Linia 374 (acum singura diferenta fata de fisierul dinainte de editare):
```diff
- IF !EMPTY(NVL(loDate.curs,0)) AND ATC('curs', m.lcTextAditional) = 0
+ IF loDate.in_valuta = 1 AND !EMPTY(NVL(loDate.curs,0)) AND ATC('curs', m.lcTextAditional) = 0
lcTextAditional = m.lcTextAditional + Iif(!Empty(m.lcTextAditional), ' # ', '') + "Curs: " + ...
ENDIF
```
Garda adaugata (`loDate.in_valuta = 1 AND`) e preluata **identic** din modelul deja corect din
acelasi fisier, la 9 linii mai jos (acum `:385`, era `:384`): `If loDate.in_valuta = 1` /
`oinvoice.lastchild.Text = m.mmoneda`, folosit pentru `DocumentCurrencyCode`. Nicio forma noua
inventata. Fara comentarii adaugate (regula 2, rezolvari de erori). Diff complet:
`D:\ROA\ROAFACTURARE\docs\diff_xmlefactura_garda_valuta.patch`.
### Verificare pe cazuri (dupa modificare)
1. **Factura in lei (`in_valuta=0`), `curs=1`** (comportamentul nou, generalizat, al facturilor in
lei dupa corectia `PACK_FACTURARE`): inainte, `!EMPTY(NVL(1,0))=.T.` -> nota aparea cu
`"Curs: 1.0000 RON/"` (valuta goala). Acum, `loDate.in_valuta = 1` e `.F.` -> intreg `AND`-ul e
fals -> nota NU se mai adauga. **Singurul caz care isi schimba comportamentul** (cel vizat).
2. **Factura in valuta reala (`in_valuta=1`)**, curs populat normal: `loDate.in_valuta = 1` e
`.T.`, restul conditiei neschimbat -> nota apare identic ca inainte. Neschimbat.
3. **Factura veche cu `curs` NULL** (orice `in_valuta`): `NVL(NULL,0)=0` -> `!EMPTY(0)=.F.` ->
conditia era deja falsa inainte de garda si ramane falsa (garda adaugata doar restrange in plus
cazul `in_valuta=0`, nu schimba nimic pe ramura `curs` NULL). Neschimbat.
Confirmat: doar cazul 1 (facturi in lei cu `curs` efectiv nenul) isi schimba comportamentul, exact
riscul identificat.
### Verificare encoding (byte-level)
Fisierul contine octeti cp1252 `>=0x80` (`0xEE` = "î", la liniile 1203 si 1330 — "puteti încarca
prin SPV"), deci risc de corupere la scriere cu tool care nu pastreaza octetii nativ. Editare
facuta cu `perl` in mod raw (`s/.../.../ `), nu cu Edit/Write:
- Backup pre-editare: `xmlefactura.prg.pre_runda.bak` (md5 `e800c71bd08e6c472b6fe912437f37f8`,
62093 octeti).
- Dupa editare: md5 `c9c9f4774346b2e62bfe9c12ea02dfb3`, 62118 octeti (+25 = exact lungimea
textului `loDate.in_valuta = 1 AND ` inserat).
- Comparatie linie-cu-linie (raw bytes) intre backup si fisierul editat: **1364 linii in ambele,
o singura linie diferita (374)** — restul fisierului byte-identic.
- Octetii `0xEE` de la liniile 1203/1330 confirmati neschimbati dupa editare.
- Scanare pentru markeri de corupere (`EF BF BD` = U+FFFD reincodat): zero potriviri.
Encoding intact, nicio corupere.
### Copii identice/asemanatoare in suita — corectie fata de raportul initial
Raportul initial (sectiunea RISC REAL #2) afirma ca fisierul e "identic prin hash" in ROAEFACTURA,
ROASITFIN, ROACONIMPORT, ROAPRINT, ROAPRODUCTIE si ROACONT/OUTPUT — verificare hash directa acum
(md5 pe tot arborele `D:\ROA`, exclus `DATABASE`) arata ca afirmatia era **partial gresita**: doar
`ROACONIMPORT` si `ROAPRINT` sunt byte-identice intre ele; restul au fiecare continut propriu,
divergent de `ROAFACTURARE`. Ce e adevarat si ramane valabil: **toate contin acelasi tipar de cod
vulnerabil** (linia cu conditia fara garda pe `in_valuta`), verificat cu grep, o singura aparitie
in fiecare fisier.
**Grup A — fisier byte-identic cu `ROAFACTURARE/COMUN` INAINTE de editarea de azi**
(md5 `e800c71bd08e6c472b6fe912437f37f8`, deci acelasi patch de o linie de la `:374` se aplica
identic, byte cu byte, in toate):
`ROAACNPRO`, `ROAAUTO`, `ROACONT`, `ROACONTRACTE`, `ROADEF`, `ROAGEST`, `ROAIMOB`,
`ROAREGISTRATURA`, `ROARES`, `ROASTART` — cale `D:\ROA\<PRODUS>\COMUN\programe\xmlefactura.prg`.
(In plus, acelasi hash apare si in foldere de backup istoric fara relevanta:
`_backup_comun_conflicts\*`, `_backup_roaimob_comun_conflict\*` — nu sunt copii vii.)
**Grup B — fisier divergent (alt continut/alte linii in rest), dar cu ACELASI tipar vulnerabil**
(conditie identica textual, gasita o singura data per fisier, doar la alt numar de linie):
| Produs | Cale | md5 | Linia conditiei |
|---|---|---|---|
| OUTPUT/ROACONT | `D:\ROA\OUTPUT\ROACONT\COMUN\programe\xmlefactura.prg` | `504dc24e771f6d66e4f028d1347671a8` | 350 |
| ROACONIMPORT | `D:\ROA\ROACONIMPORT\COMUN\programe\xmlefactura.prg` | `fa1e389839109ae46da1ef815e102259` | 356 |
| ROAEFACTURA | `D:\ROA\ROAEFACTURA\COMUN\programe\xmlefactura.prg` | `200442ad86e180c2484c96367ac9514a` | 356 |
| ROAPRINT | `D:\ROA\ROAPRINT\COMUN\programe\xmlefactura.prg` | `fa1e389839109ae46da1ef815e102259` | 356 |
| ROAPRODUCTIE | `D:\ROA\ROAPRODUCTIE\COMUN\programe\xmlefactura.prg` | `b71c1d9284d8ee78d02429b04c968a35` | 326 |
| ROASITFIN | `D:\ROA\ROASITFIN\COMUN\programe\xmlefactura.prg` | `47bb2e49770713b396e855e8af0ae2ea` | 356 |
**Grup C — NU are acest bloc de cod deloc** (verificat, nu doar negasit — nu construiesc nota de
curs valutar in e-factura): `ROADECL`, `ROAMANAGER`, `ROAPRETURI`, `ROASAL`. Fara risc, fara
propagare necesara.
**Fisierul modificat azi**: doar `D:\ROA\ROAFACTURARE\COMUN\programe\xmlefactura.prg` (md5 nou
`c9c9f4774346b2e62bfe9c12ea02dfb3`). Toate celelalte 16 cai listate mai sus (Grup A + Grup B)
raman NEATINSE, cu bug-ul inca prezent — propagarea e decizie de proces a lui Marius, nu s-a facut
aici.
### Livrabile
- Modificare: `D:\ROA\ROAFACTURARE\COMUN\programe\xmlefactura.prg` (linia 374, +garda `in_valuta`).
- Patch de review: `D:\ROA\ROAFACTURARE\docs\diff_xmlefactura_garda_valuta.patch`.
- Backup pre-editare (ramas pe disc, netracked): `xmlefactura.prg.pre_runda.bak` in acelasi folder.
- Aceasta sectiune.
Fara commit git/svn — asteapta aprobarea patch-ului.

View File

@@ -39,7 +39,7 @@ conform interdictiei primite.
> 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 `docs\diff_d42_efactura_readonly.patch`.
> Diff-ul consolidat (COMUN + ROAGEST) e regenerat in diff aplicat (sters).
## Ce s-a schimbat, si unde
@@ -233,7 +233,7 @@ e demonstrat pe flag, nu pe o coincidenta a documentului ales. Captura:
- Zero scrieri in Oracle in toata sesiunea — toate interogarile (`EsteInEFactura`,
`IncarcaCursoareModificareNota`, `IncarcaVanzareNota`, `IncarcaArticoleFactura`) sunt `SELECT`.
- Zero commit (git/svn).
- Diff consolidat: `docs\diff_d42_efactura_readonly.patch` (ambele fisiere).
- 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\`).

View File

@@ -175,7 +175,7 @@ Altele:
| `COMUN\utile\Teste\editare_factura\descopera_caz_test.prg` | **nou** |
| `COMUN\utile\Teste\editare_factura\test_page3_articole.prg` | modificat |
| `COMUN\utile\Teste\editare_factura\test_incarca_vanzare_din_nota.prg` | modificat |
| `docs\diff_datoria6_suite_regresie.patch` | diff-ul celor trei |
| diff aplicat (sters) | diff-ul celor trei |
Comenzile de rulare:

View File

@@ -200,7 +200,7 @@ dupa modelul `test_ui_sterge_linie.prg`:
**`test_d42_efactura_readonly.prg`** — cazul pozitiv, cu date mock (nu exista document real din
luna curenta trimis in eFactura, cf. §1):
1. Incarca `tact`/`tvd` pentru un document real din luna curenta cu `lAreArticoleVanzari = .T.`
(ex. acelasi `id_vanzare = 1049` mentionat in `handoff_punct6_dupa_s5.md`, daca inca in luna
(ex. acelasi `id_vanzare = 1049` mentionat in handoff intermediar (sters), daca inca in luna
curenta la momentul rularii).
2. Dupa `IncarcaVanzareDinNota`, forteaza `tvanz.id_fact` (sau `tact.id_fact`, dupa care varianta se
alege in §8) la o valoare stiuta ca exista in `ANAF_EFACTURA` (mock: `INSERT` intr-un cursor
@@ -230,7 +230,7 @@ ca nu s-a facut nicio interogare Oracle suplimentara, sau direct daca se mock-ui
contor de apeluri).
Toate cele trei suite: fara scriere in Oracle, `QUIT` la final, log langa `.prg` cu acelasi nume +
`_log.txt`, conform conventiei din `handoff_punct6_dupa_s5.md`.
`_log.txt`, conform conventiei din handoff intermediar (sters).
## 8. Schita de diff — corectia necesara peste diff-ul in lucru

View File

@@ -30,7 +30,7 @@ fara coloane*" - identica, doar declansata din `Show()` in loc de `Init()`. `Rec
text) ramane `"tvd"`, dar `Columns` colapseaza la 0 - de aici simptomul "pagina apare, grid gol".
## Arhitectura FINALA (dupa o coliziune de editare intre agenti concurenti pe `Show()`,
## descrisa in `docs\handoff_fix_grid_tvd_blank.md` - rezolvata, verificata mai jos)
## descrisa in handoff intermediar (sters) - rezolvata, verificata mai jos)
Varianta livrata difera de iteratia descrisa initial mai sus (`ZAP`+`APPEND FROM` in
`IncarcaArticoleFactura` + `Refresh()` in `Show()`). Arhitectura finala muta incarcarea
@@ -116,7 +116,7 @@ impactul in ROACONT pe `comun.vc2:2436` (registrul jurnal) ramane de verificat s
## Stare livrare
Fara commit. Diff regenerat din starea curenta (git diff vs HEAD, in `COMUN`):
`docs\diff_fix_grid_tvd_blank.patch`. Write-back facut in `COMUN\clase\omodificari.vcx`/`.vct` si
diff aplicat (sters). Write-back facut in `COMUN\clase\omodificari.vcx`/`.vct` si
`COMUN\clase\ofacturare_comun.vcx`/`.vct` (mtime text/binar sincrone, verificat 08.08.2026 23:49).
`ofacturare_editare.prg` e ASCII pur, editat direct, fara risc de encoding.

View File

@@ -92,7 +92,7 @@ principal.
sintetice (1 id_set / 2 id_set +5 / 2 id_set fara relatia +5 / 3 id_set) - toate 4 + cele 2
cazuri de regresie (`cod=1140888`, `cod=1140885`) au dat rezultatul asteptat la rulare headless
(`vfp9.exe -A -T`).
- Patch: `docs\diff_runda3_garda_idset.patch` (netrimis la commit, asteapta review).
- Patch: diff aplicat (sters) (netrimis la commit, asteapta review).
- Baseline: `COMUN\clase\ofacturare_comun.vc2.pre_runda3.bak`.
## Netestat

View File

@@ -1,358 +0,0 @@
# Cercetare: integrare CONTRACTE, politici de preturi, nomenclator ca lista de preturi
Metoda: `vfp_symbols.ps1` (cache text ROAFACTURARE deja la zi) + Grep pe `.prg`/`.vc2`/`.mn2`.
Fapte cu `fisier:linie`; ipoteze marcate `IPOTEZA:`.
## SUBIECT A - Integrare pagina CONTRACTE (todo #10)
### 1. Unde exista azi contractele
Produs separat, working copy completa: `D:\ROA\ROACONTRACTE` (`.git` + `.svn`, `roaContracte.pjx`,
`roacontracte.exe`). Structura: `Clase\` (`ofundal.vcx`, `onom_clienti.vcx`, `oOptiuni.vcx`,
`roaclienti.vcx`, `ferestre_contracte.vcx` - probabil formularele CRUD de contracte),
`Ferestre\`, `Programe\`, `Rapoarte\`, `Meniuri\`, `COMUN\` (propria copie a librariei partajate),
`Teste\`, `docs\`.
**Important**: ROAFACTURARE NU e izolat de contracte azi - are deja o integrare de facturare
partiala "pe baza de contract" (vezi punctul 4), care citeste direct din schema Oracle a
ROACONTRACTE prin view-uri (`vcontracte`, `fact_vcontracte`, `tipuri_contracte`), fara pagina de
editare. `ferestre_contracte.vcx` din ROACONTRACTE contine probabil formularele CRUD care ar
trebui aduse in ROAFACTURARE (nu au fost deschise/citite - binar, necesita conversie separata daca
se trece la implementare).
Exista deja urme ale unei integrari partiale de UI in ROAFACTURARE:
- `Meniuri\contracte.mnx`/`.mn2` (`D:\ROA\ROAFACTURARE\Meniuri\contracte.mn2:1`) - NU e un meniu de
administrare contracte, ci un shortcut-popup cu 3 optiuni de facturare ("Factura fiscala lei /
Invoice / Factura fiscala valuta") - cf. continut citit integral.
- `Grafice\icon_contracte1.png`, `icon_contracte2.png`, `Grafice\Originale\contracte.png` -
iconite deja pregatite in ROAFACTURARE.
### 2. Cum e integrata azi COMENZI in ROAFACTURARE (sablonul de urmat)
COMENZI **nu** e produs separat legat prin exe, ci cod montat direct in ROAFACTURARE din
`COMUN\` (librarie partajata `gitea.romfast.ro:romfast/comun.git`, cf. CLAUDE.md). Exista si un
produs stand-alone `D:\ROA\ROACOMENZI` (cu `.pjx` propriu), dar in ROAFACTURARE comenzile sunt
o **pagina/panou montat direct in formularul principal (fundal)**, nu un exe separat lansat.
Reteta pas cu pas (comenzi ca model pentru contracte):
1. **Clasa container** `ct_comenzi` din `COMUN\clase\ocomenzi.vcx` (`.vc2` cache:
`COMUN\clase\ocomenzi.vc2`) - contine formulare/containere CRUD comenzi
(`frm_optiuni_comenzi`, cursoare `vcomenzi_elemente` etc.).
2. **Montare in formularul principal**: containerul e plasat ca obiect copil in
`Clase\ofundal_facturare.vc2` (form fundal), cu comentariul `< END OBJECT:
ClassLib="..\comun\clase\ocomenzi.vcx" BaseClass="container" />` in jurul liniei
`Clase\ofundal_facturare.vc2:831`; obiectul se numeste `lb_comenzi`
(`Clase\ofundal_facturare.vc2:824`).
3. **Butoane de actiune** ("Cw" = clase de tip buton-cu-drept, vezi punctul 3) legate la proceduri
business, ex. `Page2.Cw3.do_actiune` -> `DO facturare_comenzi IN oproceduri_facturare.prg`
(`Clase\ofundal_facturare.vc2:899-902`).
4. **Inregistrare in `Programe\roafacturare.prg`** (entry point):
- `SET CLASSLIB TO ocomenzi ADDITIVE` sub comentariul `*** COMENZI`
(`Programe\roafacturare.prg:180-181`);
- `SET PROCEDURE TO orap_comenzi.prg / onom_comenzi.prg / update_comenzi.prg ADDITIVE`
(`Programe\roafacturare.prg:239-242`), tot sub `*** COMENZI`;
- variabile module: `PRIVATE pocomenzi,pocomenzielemente,polucrari,pocomenzi2,polucrarielemente`
(`Programe\roafacturare.prg:246-247`).
- Toate cele 3 `.prg` (`orap_comenzi.prg`, `onom_comenzi.prg`, `update_comenzi.prg`) si clasa
`ocomenzi.vcx`/`.vct` locuiesc fizic in `COMUN\programe\` / `COMUN\clase\`, dar sunt
inregistrate ca membri ai proiectului `roafacturare.pjx` (confirmat prin Grep pe `.pjx`:
`COMUN\clase\ocomenzi.vcx`, `COMUN\programe\orap_comenzi.prg` etc. apar in el).
5. **Business logic de facturare din comenzi**: `Procedure facturare_comenzi` in
`COMUN\programe\oproceduri_facturare.prg:139-141` - un simplu `factureaza(3)` (tip document 3
= "din comanda", motorul central `factureaza()` face restul).
6. **Meniu**: nu exista `Meniuri\comenzi.mnx` separat in ROAFACTURARE - comenzile nu au intrare de
meniu proprie, ci doar butonul `Cw3` de pe pagina fundal (Page2 = "Facturare"). Contractele au
deja `Meniuri\contracte.mnx` dar cu alt continut (shortcut factura), deci pentru pagina noua de
contracte ar trebui fie extins acest fisier, fie creat altul.
Concluzie sablon: pentru CONTRACTE ar insemna (a) o clasa container tip `ct_contracte` (posibil
adaptata din `ferestre_contracte.vcx` al ROACONTRACTE, mutata/duplicata in `COMUN\clase\`), (b)
montarea ei ca obiect in `ofundal_facturare.vc2` langa `lb_comenzi`, (c) inregistrare `SET
CLASSLIB`/`SET PROCEDURE` in `roafacturare.prg` sub un bloc nou `*** CONTRACTE`, (d) adaugare in
`roafacturare.pjx`.
### 3. Mecanismul de DREPTURI pe obiecte
Sursa: `COMUN\programe\acces_meniu.prg` (fisier citit integral).
- **Sursa de date**: view Oracle `contafin_oracle.vdef_util_obiecte`, interogat cu
`select cheie,id_firma from contafin_oracle.vdef_util_obiecte where id_util=?gnIdUtil and
id_program=?gnIdProgram and id_firma=?gnIdFirma` (`acces_meniu.prg:29-31`), rezultat in cursorul
`crsdrepturi` (o singura coloana cheie relevanta: `cheie`, string).
- **Codificarea cheii**: concatenare de "caractere de nivel" - `Chr(lnKey)` pentru fiecare nivel de
pageframe/pagina (`dezactiveaza_obiecte_pageframe`, `acces_meniu.prg:103-165`, recursiv pe
subpageframe-uri), plus un cod de 2 cifre pentru fiecare buton `Cw*`:
`lcCheie = lcKey + Padl(Alltrim(Str(.Objects(l).nid_cw)), 2, '0')` (`acces_meniu.prg:138`).
Fiecare obiect `Cw*` are proprietatea `nid_cw` (numarul lui in cadrul paginii) si la runtime i se
seteaza `ccheie` (`acces_meniu.prg:140`) si `coptiuni_active` (lista de operatii CRUD permise,
citita din caracterele urmatoare cheii - `acces_meniu.prg:141-149`). Butonul apeleaza
`.Objects(l).activeaza()` / `.dezactiveaza()` in functie de gasire (`acces_meniu.prg:150-152`).
- **Pentru imagini/iconite** (nivel diferit, folosit pe alte forme): proprietate `ccod` pe obiect
(`acces_meniu.prg:48`), aceeasi logica de cautare in `crsdrepturi`.
- **Cod de meniu (pad-uri)**: `GetAccesByCod(tcCod, tcAccesDefault)` (`acces_meniu.prg:236-276`)
cauta o cheie explicita (cod optiune meniu, ex. "ZA01") in `crsdrepturi` si intoarce lista de
operatii permise (ex. "1;2;3;4").
- **Punct de intrare**: `verifica_drepturi(tcObiectFundal, tcPageFrame)`
(`acces_meniu.prg:9-15`) apelat din formularul fundal (`Ferestre\fundal.sc2:699`:
`verifica_drepturi('gofundal','_pgfrmbase1')`), care incarca `crsdrepturi` o singura data per
firma (cache in memorie, `citeste_drepturi`, `acces_meniu.prg:17-37`) si dezactiveaza in cascada
paginile/butoanele/meniurile fara drept.
- **Administrare drepturi** (unde se declara catalogul de obiecte si se atribuie pe grupuri):
`COMUN\clase\drept_grupuri.vc2` - `frm_grupuri`, apel catre pachetul Oracle
`PACK_DREPTURI.grupdreptmodproc` (`COMUN\clase\drept_grupuri.vc2:39`) si `citeste_drepturi
(loRec.id_grup)` (`COMUN\clase\drept_grupuri.vc2:205`).
IPOTEZA: catalogul efectiv de "obiecte disponibile pentru ROAFACTURARE" (denumirile/codurile
`nid_cw`/`ccod`/coduri de meniu, ex. cele pentru COMENZI) e definit **partial in designerul VFP**
(proprietatea `nid_cw` seteaza pe fiecare buton la design-time in `.scx`/`.vcx`) si **partial
server-side** in schema Oracle `contafin_oracle` (tabelul din spatele view-ului
`vdef_util_obiecte`, populat probabil printr-un script de instalare/migrare, nu vazut in sursa
VFP). Pentru "comasarea" drepturilor ROACONTRACTE + ROAFACTURARE mentionata in cerere, ar trebui
inspectat acest tabel server-side (in afara sursei VFP disponibile aici) plus alocarea de noi
`nid_cw` pentru butoanele noi de contracte, fara sa coincida cu cele deja folosite de COMENZI/
lista de preturi/avize pe aceeasi pagina.
Exemplu concret COMENZI: butonul `Page2.Cw3` (facturare din comenzi) foloseste automat cheia
`<cheie_pagina>+'03'` (Cw3 => `nid_cw=3`); pentru un buton nou de contracte pe aceeasi pagina ar
trebui un `nid_cw` neutilizat (ex. 11+, dat fiind ca Page2 are deja Cw1..Cw9 conform
`Clase\ofundal_facturare.vc2:882-926`).
### 4. Facturarea pe baza de comanda / pe baza de contract
**Comanda -> factura**: `Procedure facturare_comenzi` (`COMUN\programe\oproceduri_facturare.prg:
139-141`) => `factureaza(3)`. Cautarea comenzii disponibile pentru facturare:
`Function caut_comanda_gestiune` (`COMUN\programe\oproceduri_facturare.prg:1961-1983`), citeste
din view-ul `vcomenzi` (`... FROM ] + gcS + [.vcomenzi`), filtru
`facturat = 0 and interna = 3 ... ` (linia 1977).
**"Pe baza de contract" EXISTA DEJA**, mai complet decat comenzile pe alocuri:
- `Procedure facturare_contracte(tcTip)` (`COMUN\programe\oproceduri_facturare.prg:119-136`) -
primeste tipul de document ("FACTURA LEI"/"INVOICE"/"FACTURA VALUTA") si apeleaza
`factureaza(2)`/`factureaza(6)`/`factureaza(52)`.
- Buton pe pagina fundal: `Page2.Cw2.do_actiune` (`Clase\ofundal_facturare.vc2:886-897`) - meniu
`xmenu` cu cele 3 optiuni, cheama `facturare_contracte`.
- **Cautare contract**: `Function caut_contract_facturare(tnIdPart, tcSirTipFacturare)`
(`COMUN\programe\oproceduri_facturare.prg:1986-2021`) - citeste din view-ul `fact_vcontracte`
(`select id_ctr, contract, numar, data, denumire, scadenta_incasare, opt_facturare,
text_standard, afisare_scadenta FROM fact_vcontracte`, linia 2001), filtrat pe
`opt_facturare in (...)` si `id_part`.
- **Alegerea contractului la factura**: `frm_date_factura.do_cauta_contract`
(`COMUN\clase\ofacturare.vc2:9067-9115`) si `frm_date_aviz.do_cauta_contract`
(`COMUN\clase\ofacturare.vc2:7049-7051`) apeleaza `caut_contract_facturare`.
- **Editorul de articole pe factura** are un tab/grid dedicat contractelor:
`frm_facturare_articole` cu controale `grd_contracte`, `cb_contracte` (combobox cu ratele /
contractele), populate din cursorul `crscontracte` (`COMUN\clase\ofacturare.vc2:15069-15107` si
in jur). Optiunea `opt_facturare` din `fact_vcontracte`/`crsfactura` marcheaza randurile "din
contract" (`COMUN\programe\oproceduri_facturare.prg:176-177`, `Inlist(opt_facturare,1,2)` in alt
context legat de seturi).
- **Aviz pe baza de contract**: exista si un tip de aviz "26 - catre clienti din contract"
(`COMUN\programe\oproceduri_facturare.prg:207`, enumerat si in `caut_avize`,
`COMUN\programe\oproceduri_facturare.prg:2045`), apelat din `emitere_aviz_clienti(tnTip=3)`.
Concluzie: **motorul de facturare din contract e deja complet functional** in ROAFACTURARE (citire
din schema ROACONTRACTE prin view-uri Oracle `vcontracte`/`fact_vcontracte`/`tipuri_contracte`).
Ce lipseste conform cererii e (a) o **pagina de editare CRUD a contractelor** in ROAFACTURARE
(azi doar in exe-ul separat ROACONTRACTE) si (b) **rapoarte de contracte** in ROAFACTURARE, plus
(c) unificarea drepturilor. Nu a fost gasit niciun raport de contracte in
`ROAFACTURARE\Rapoarte\` (glob `*contract*` nu a dat `.frx` in Rapoarte, doar meniu/iconite).
---
## SUBIECT B - Politici de preturi (todo #11)
### 5. Unde sunt azi definite/editate
Produs separat, mic, dedicat: `D:\ROA\ROAPRETURI` (`.pjx` propriu, `roapreturi.exe`). Structura:
`Programe\onom_preturi.prg`, `Programe\update_preturi.prg`, `Programe\update_nomenclator.prg`,
`Clase\opreturi.vcx`, `Clase\onom_preturi.vcx`, `Clase\ofundal_preturi.vcx`,
`Clase\ofundal_roapreturi.vcx`, `Ferestre\fundal.scx`. (Continutul acestor clase nu a fost convertit
in text - ROAPRETURI nu are un cache text propriu generat in aceasta sesiune; doar structura de
fisiere a fost inspectata.)
Interfata de editare pare sa fie un produs desktop de sine statator, distinct de ROAFACTURARE si de
ROACONT, focalizat strict pe politici/liste de preturi si pe actualizarea nomenclatorului
(`update_nomenclator.prg` sugereaza ca ROAPRETURI scrie si in nomenclatorul comun de articole).
### 6. Tabele/view-uri implicate (identificate din ROAFACTURARE)
Din codul ROAFACTURARE care CITESTE politici de preturi (nu editeaza), gasite:
- `vcrm_politici_preturi` - view folosit in cautare dupa drepturi utilizator
(`COMUN\clase\baza.vc2:10087`, `:10157`, `:10502-10512`). Interogare efectiva:
`select nume_lista_preturi, id_pol from crm_vpolpretcurutil` (`COMUN\clase\baza.vc2:10504`) -
deci exista si view-ul `crm_vpolpretcurutil` ("politica de pret curenta pentru utilizator"),
cheie `id_pol`.
- `vvanzari_detalii` - contine coloana `nume_lista_preturi` folosita in rapoarte de marfa
(`COMUN\clase\configurare.vc2:3915-3972`, `frm_raport_marfa`).
- Meniu dedicat facturarii pe lista de preturi: `Meniuri\politica.mnx`/`.mn2`/`.MPR` in
ROAFACTURARE; procedura `facturare_lista_de_preturi` = `Do politica.mpr`
(`COMUN\programe\oproceduri_facturare.prg:113-116`), buton `Page2.Cw1.do_actiune`
(`Clase\ofundal_facturare.vc2:882-884`).
- Prefixul `crm_`/`CRM` in numele tabelelor/view-urilor (`vcrm_politici_preturi`,
`crm_vpolpretcurutil`) sugereaza schema/modul Oracle numit "CRM", separat de schema principala
de facturare (`gcS`). IPOTEZA: politicile de pret sunt un modul Oracle transversal (folosit si
de ROAGEST, ROAPRETURI, ROACONTRACTE), nu proprietatea exclusiva a unui singur produs VFP.
- Comenzile (ROACOMENZI/`ocomenzi.vcx`) au propriul mecanism de asociere pret-din-comanda:
globale `gnIdPoliticaPret`, `gnId_lista_preturi_PV` (`Programe\roafacturare.prg:467,469`),
folosite si in `frm_optiuni_comenzi` (`COMUN\clase\ocomenzi.vc2:6488-6686`, variabila
`gnID_LISTA_PRETURI_PV` = politica de pret "de productie" folosita la generarea automata a
comenzilor). Cursorul de articole al comenzii are coloanele `id_pol`, `nume_lista_preturi`,
`pret`, `pret_cu_tva`, `ptva` direct in el (`COMUN\clase\ocomenzi.vc2:1227-1229`, cursor creat
din view-ul `vcomenzi_elemente`).
Nu a fost gasita nicio schema DBF/DDL explicita pentru "politici de preturi" / "liste de preturi"
in sursa VFP (tabelele reale sunt Oracle, definite server-side; VFP le vede doar prin view-uri
enumerate mai sus). N-a fost identificat un tabel separat de "note contabile asociate politicii de
pret" in codul cercetat - contul contabil de vanzare pare sa vina din nomenclatorul de articole
(`nom_articole.cont`, vezi punctul 10), nu dintr-o tabela separata legata de politica.
### 7. Ce foloseste ROAFACTURARE azi din aceste date
- **Facturare pe lista de preturi** (`Do politica.mpr`) - flux complet de vanzare pe baza unei
politici de pret selectate (analog cu vanzarea din stoc/comenzi/contract), tip document
distinct in motorul central `factureaza()`.
- **Cautare/afisare politica dupa drepturi utilizator** (`COMUN\clase\baza.vc2:10502-10512`) -
ROAFACTURARE citeste `crm_vpolpretcurutil` pentru a limita politicile vizibile la cele pe care
utilizatorul are drept (alt strat de drepturi, distinct de `acces_meniu.prg` - specific pe
politici de pret, posibil gestionat tot server-side prin pachetul `PACK_DREPTURI`).
- **Rapoarte de vanzari pe lista de preturi** (`frm_raport_marfa`,
`COMUN\clase\configurare.vc2:3915-3972`) - grupare/însumare pe `nume_lista_preturi`.
- Nu editeaza politici/liste - doar le CITESTE si le foloseste ca sursa de pret la facturare/
raportare. Editarea (adaugare politica, adaugare articole in politica, preturi) ramane in
ROAPRETURI.
Concluzie pentru migrare: ce ar trebui **mutat efectiv in ROAFACTURARE** (conform cererii - "se
folosesc numai in programul ROAFACTURARE") e interfata de editare (`opreturi.vcx`/
`onom_preturi.vcx` din ROAPRETURI), nu structura de date (Oracle, deja partajata/citita corect).
Rapoartele si drepturile pe liste de preturi trebuie de asemenea aduse ca pagina/panou in
ROAFACTURARE, dupa acelasi sablon COMENZI descris la punctul 2.
---
## SUBIECT C - Nomenclatorul de articole ca lista de preturi virtuala (todo #12)
### 8. Structura tabelei de nomenclator
Tabela Oracle **`catalog_articole`**, expusa prin view-ul **`vnom_articole`** (si `vnom_articole2`
pentru un al doilea tip - vezi `nom_articole2_nou`, `COMUN\programe\onomenclatoare.prg:1376-1396`,
tabela `catalog_articole2`).
Coloane identificate din interogari/scatter (nu e o lista exhaustiva - vin din SELECT-uri
punctuale, nu din DDL):
`id_articol, denumire, codmat, codmatf (cod furnizor), codbare, um, grupa, subgrupa, id_grupa,
id_subgrupa, dnf, cont (cont contabil, 3-4 caractere), acont, inactiv, sters, in_stoc, in_crm,
tip (ex. 1 = manopera pt. ROAACNPRO), id_part/partener (pt. articole legate de furnizor/client)`.
Surse: `COMUN\clase\ocriterii.vc2:1531` (`select denumire, codmat, um, grupa, subgrupa, id_grupa,
id_subgrupa, dnf, cont, acont, inactiv, id_articol from vnom_articole`),
`COMUN\programe\onomenclatoare.prg:1345-1353` (`in_crm`, `in_stoc`, `tip`),
`COMUN\clase\ointroduceri.vc2:9631` (`in_stoc, cont`).
**Nicio coloana de pret** nu a fost gasita direct pe `nom_articole`/`catalog_articole` (grep
`pret_v|pretv|pret_lista` in `onomenclatoare.prg` = fara rezultate; scatter-ul din
`nom_articole_nou` nu populeaza niciun camp de pret). Confirma punctul 11 mai jos.
**Formular de editare**: `frm_catalog_articole` (grid/cautare) si `frm_catalog_articole_nou`
(fisa), ambele in `COMUN\clase\onom_articole.vc2` (`:531-599`, `:1655-1733`), salvare prin
`cus_odata_catalog_articole.salvare` si `Adauga_Modifica_Inregistrare('catalog_articole', ...)`
(`COMUN\programe\onomenclatoare.prg:1367,1443`). Deschidere din meniu:
`Procedure viz_catalog_articole` (`COMUN\programe\oproceduri_articole.prg:62-122`).
**Important pentru subiectul B/C**: `nom_articole_nou` (`COMUN\programe\onomenclatoare.prg:
1343-1353`) marcheaza acelasi articol cu `in_crm = 1` cand programul curent e ROAPRETURI sau
ROACONTRACTE, respectiv `in_stoc = 1` in rest (inclusiv ROAFACTURARE) - **nomenclatorul de
articole e deja UNIC/PARTAJAT** intre ROAFACTURARE, ROAPRETURI, ROACONTRACTE si ROAACNPRO (aceeasi
tabela `catalog_articole`), flagurile `in_stoc`/`in_crm`/`tip` fiind doar clasificari de
utilizare, nu tabele separate. Asta simplifica mult todo #12: nomenclatorul nu trebuie replicat,
doar completat cu campuri de pret/tva/cont-vanzare si folosit direct ca sursa de pret la
facturare.
### 9. Mecanismul actual de "lista de articole din stoc ca lista de preturi virtuala"
Confirmat: e mecanismul de **"vanzare din stoc/gestiune"**, un tip de facturare paralel cu
"lista de preturi"/"contract"/"comanda", identificat prin variabila globala `gnTipGest`:
- `Procedure vanzare_materii_prime` -> `gnTipGest = 2`, `Do vanzare1.mpr`
- `Procedure vanzare_produse` -> `gnTipGest = 4`, `Do vanzare2.mpr`
- `Procedure vanzare_marfa_pret_achi` -> `gnTipGest = 5`, `Do vanzare3.mpr` (marfa la pret de
achizitie)
- `Procedure vanzare_marfa_pret_vanz` -> `gnTipGest = 6`, `Do vanzare4.mpr` (marfa la pret de
**vanzare**)
- `Procedure vanzare_marfa_pret_achi_vanz` -> `gnTipGest = 7`, `Do vanzare5.mpr`
(toate in `COMUN\programe\oproceduri_facturare.prg:1505-1534`; butoane `Page2.Cw5..Cw9` in
`Clase\ofundal_facturare.vc2:908-926`).
Gestiunile disponibile per tip se filtreaza prin `Procedure selecteaza_gestiuni`
(`COMUN\programe\oproceduri_facturare.prg:1536-1565`), pe view-ul `vnom_GESTIUNI` filtrat
`nr_pag = ?gnTipGest`, plus un al doilea nivel de drept pe gestiuni (view-urile
`vgest_coresp_grupe_gestiuni` / `vgest_coresp_util_grupe`, linia 1552-1555) - deci "lista de
preturi virtuala" = stocul unei gestiuni, cu control de acces pe gestiune (nu pe politica de
pret).
Motorul de scriere: `Function oscrie_vanzare_din_stoc` in `COMUN\programe\ofacturare_stoc.prg:
104-...`, apelat din `initializeaza_vanzare_din_stoc` (`ofacturare_stoc.prg:31-99`). Comentariu
explicit in cod: *"in vanzari_detalii scriu pretul cu tva daca am marfa la pret de vanzare, daca
nu scriu pretul de vanzare fara tva"* (`ofacturare_stoc.prg:107`), cu
`lnPretCuTva = Iif(INLIST(gnTipGest,6,7), 1, 0)` (linia 111) - deci flagul "pret cu TVA" e
determinat de TIPUL de vanzare din stoc ales (6/7 = la pret de vanzare), nu citit dintr-o coloana
a nomenclatorului.
Cursorul-cheie `crsvanztemp` (`ofacturare_stoc.prg:137-139`) are coloanele:
`id_articol, Pret, proc_tvav, id_jtva_coloana, cantitate, discount_unitar, id_gestiune, Cont
(c4), pret_cu_tva, serie, id_valuta, codmat, Curs, multiplicator, pret_achizitie, pretd,
id_valuta_d, id_rul_aux, taxcode, lot`.
### 10. Lantul de cod: pret, valuta, %TVA, pret_cu_tva, cont vanzare - la facturare "din stoc"
Din structura `crsvanztemp` (punctul 9) rezulta explicit lantul folosit azi cand se factureaza
"virtual" din stoc (echivalentul cerut pentru nomenclator-ca-lista-de-preturi):
- **Pret**: coloana `Pret` in `crsvanztemp`, luata din inregistrarea de gestiune/stoc (miscarea de
intrare), nu din nomenclator - `pret_achizitie` separat pentru pretul de achizitie.
- **Valuta**: `id_valuta`, `Curs`, plus varianta in alta valuta `pretd`/`id_valuta_d` (pret dublu,
pentru afisare in a doua valuta).
- **%TVA**: `proc_tvav` + `id_jtva_coloana` (coloana de defalcare TVA in jurnal) + `taxcode` (cod
fiscal pt. integrari, ex. eFactura).
- **Flag pret_cu_tva**: `pret_cu_tva` in cursor, calculat din `gnTipGest` (`ofacturare_stoc.prg:
111`), NU citit dintr-o coloana persistenta a articolului.
- **Cont vanzare (echivalent 4111=7xx)**: coloana `Cont c(4)` in `crsvanztemp` - cont contabil pe
4 caractere (ex. "707x"/"701x"), scris explicit in cursor la nivel de linie de vanzare. Sursa lui
cea mai probabila (nu confirmata cu linie exacta de SELECT in aceasta cercetare, cursorul e
populat mai jos in fisier, dincolo de zona citita) e coloana `nom_articole.cont` (confirmata ca
existenta la punctul 8) sau contul gestiunii (`nom_gestiuni`) - **IPOTEZA**: trebuie verificat
punctual restul lui `oscrie_vanzare_din_stoc` (fisierul continua dupa linia 140, necitit
integral in aceasta trecere) pentru sursa exacta linie-cu-linie a lui `Cont`.
Pentru comparatie, la facturarea pe **lista de preturi/politica** (nu pe stoc), pretul/valuta/TVA
vin din politica de pret (view `crm_vpolpretcurutil`/`vcrm_politici_preturi`, punctul 6), deci
lantul e diferit dupa tipul de facturare ales (`gnTipGest` vs. `id_pol`).
### 11. Coloane de pret existente/partial folosite in nomenclator
**Nu exista azi nicio coloana de pret pe `nom_articole`/`catalog_articole`** (cautare explicita
fara rezultate). Exista insa deja doua campuri reutilizabile direct pentru scenariul din cerere:
- `cont` (cont contabil de vanzare/achizitie, deja pe articol - vezi punctul 8) - poate fi folosit
ca "nota contabila" fara tabel separat.
- Flagurile `in_stoc` / `in_crm` - clasifica deja fiecare articol dupa modul de utilizare (stoc
vs. politica de pret / CRM), un precedent direct pentru un viitor flag suplimentar de tipul
"articol cu pret propriu in nomenclator" daca se implementeaza todo #12.
Nu au fost gasite coloane de tipul `pret`, `pret_vanzare`, `valuta_pret`, `ptva` direct pe
nomenclator - toate preturile de vanzare vin azi fie din politici de pret (Oracle, schema CRM),
fie din miscarile de gestiune/stoc (nu din articolul insusi). Implementarea todo #12
("nomenclatorul direct ca lista de preturi, fara politica + nota contabila asociate") ar necesita
adaugarea a cel putin: pret (+valuta), procent TVA, flag pret_cu_tva pe `catalog_articole`/
`nom_articole` - camp nou, nu o coloana ascunsa deja existenta.
---
## Rezumat surse cheie (fisier:linie)
- Sablon COMENZI: `Programe\roafacturare.prg:180-181,239-247`; `Clase\ofundal_facturare.vc2:
760-926`; `COMUN\clase\ocomenzi.vc2`.
- Drepturi: `COMUN\programe\acces_meniu.prg` (tot fisierul, 306 linii).
- Facturare contract: `COMUN\programe\oproceduri_facturare.prg:119-136,1986-2021`;
`COMUN\clase\ofacturare.vc2:9067-9115,15069-15107`.
- Politici de pret: `COMUN\clase\baza.vc2:10087,10157,10453-10512`;
`COMUN\programe\oproceduri_facturare.prg:113-116`.
- Vanzare din stoc (lista virtuala): `COMUN\programe\oproceduri_facturare.prg:1505-1534`;
`COMUN\programe\ofacturare_stoc.prg:31-140`.
- Nomenclator articole: `COMUN\programe\onomenclatoare.prg:1302-1373`;
`COMUN\clase\onom_articole.vc2:531-599,1655-1733`.

View File

@@ -1,177 +0,0 @@
# Cercetare frm_modific2024 — editare directa act/rul in ROAFACTURARE
## 1. Localizare frm_modific2024
Clasa `frm_modific2024` e definita in `D:\ROA\ROAFACTURARE\COMUN\clase\omodificari.vc2`
(clasa incepe la `omodificari.vc2:6375`; metodele proprii ale lui `frm_modific2024` sunt la
liniile `12200`-`15319`). Text `.vc2` (492 942 octeti, 02.08.2026 12:28) e mai nou decat
binarul `.vcx` (64 144 octeti, 02.08.2026 12:24) — cu ~4 minute, deci sincronizat, nimic
neconvertit ramas in urma.
Important: `omodificari.vc2` NU e specific unui singur produs — exista un fisier aproape
identic si in `D:\ROA\ROAGEST\COMUN\clase\omodificari.vc2` (aceleasi metode, linii aproape
identice, cf. `_symbols.tsv` per-produs). `COMUN/` e propriul working copy git per produs
(cf. CLAUDE.md), deci **frm_modific2024 exista deja, azi, in checkout-ul COMUN al
ROAFACTURARE** — nu trebuie adus/portat de nicaieri, doar instantiat.
E o **clasa .vcx instantiabila** (`Createobject([frm_modific2024], lnIdSet, ...)`), nu un
`.scx` monolitic. Ascendenta: `frm_modific2024 -> _frmbase (_frm_base.vc2:7) -> _form
(_baza.vc2:157) -> form`.
## 2. Ce face efectiv
Editeaza **cursoare locale in memorie** `tact` / `trul` / `trul_obinv` (READWRITE), NU
tabelele Oracle `ACT`/`RUL` direct:
- `Init` (`omodificari.vc2:13510-13616`) primeste `tnIdSet, tlNotaNoua, toBackupXML, toSet,
tlVizualizare` — nu incarca date, doar configureaza UI (readonly pe coloane cand
`id_set` e "specializat", vizibilitate butoane).
- `do_modifica` (`12906-13027`), `do_sterge` (`13111-13185`), `do_adauga` (`12615-12663`)
editeaza direct pe `SELECT tact` / `SELECT trul` — grid-uri legate de aceste cursoare.
- `inainte_de_do_termin` (`13316-13508`) ruleaza validari (`verificare_note_contabile`,
echilibru conturi 4426-4428, `VerificaAvertizareExigibilizareTVA`) inainte de a permite
inchiderea formularului cu `gnButon=1`.
- `do_termin` in sine e mostenit din `_frmbase` (`_frm_base.vc2:363-376`): doar seteaza
`gnButon=pnButon=Buton=pnIesire=1` si inchide formularul — **nu scrie nimic in baza de
date**. Scrierea e responsabilitatea apelantului, dupa `.Show()`.
**Salvarea reala** (in codul apelant, vezi pct. 5) trece prin `ACT_TEMP`/`RUL_TEMP` +
`oscrie_in_fisiere.prg` + pachetul Oracle `PACK_CONTAFIN`, intr-o tranzactie manuala
(`SQLSetProp(gnhandle,'Transactions',2)` ... `COMMIT`/`ROLLBACK`).
Protectii: `glLunaInchisa` (luna inchisa → return), verificare sucursala curenta pe stergere
(`do_sterge:13129-13136`), verificare referinte incasari/plati inainte de stergere
(`ReferinteDocument`, `do_sterge:13152`), validare structura nota (`verificare_note_contabile`
in `inainte_de_do_termin`).
## 3. Reutilizabilitate din ROAFACTURARE
**Direct reutilizabila, fara portare** — clasa e deja in `ROAFACTURARE\COMUN\clase\omodificari.vc2`,
iar `COMUN\clase` e deja inregistrat in `SET CLASSLIB`/`SET PROCEDURE` din
`Programe\roafacturare.prg` (verificat ca `omodificari.vc2` foloseste variabile globale
standard ROA: `gnAn`, `gnLuna`, `goExecutor`, `gcs`, `gnIdUtil`, `glLunaInchisa` — toate deja
setate de bootstrap-ul ROAFACTURARE). Nu am gasit dependinte de clase/proceduri absente din
ROAFACTURARE — `verificare_note_contabile`, `update_saft_taxtable`, `backupxml` etc sunt tot
in `COMUN`, deci deja disponibile.
Ce lipseste NU e clasa in sine, ci **codul apelant** (echivalentul `afisjurcom.do_modifica`)
care: (a) incarca `vact_tot`/`vrul_tot`/`vrul_obinv_tot` filtrate pe `cod` in `tact`/`trul`/
`trul_obinv`, (b) deschide tranzactia, (c) apeleaza `oscrie_in_fisiere` de doua ori (sterge +
scrie), (d) apeleaza `pack_contafin.finalizeaza_modificare_nota`, (e) inchide tranzactia. Acest
cod nu exista inca in ROAFACTURARE si trebuie scris nou, dupa modelul de la pct. 5-6 (dar e
~40 linii, nu o clasa noua).
## 4. Punctul de agatare in ROAFACTURARE: frm_facturi
`frm_facturi` e in `COMUN\clase\ofacturare_comun.vc2:1168`, ascendenta `frm_facturi ->
_frmbase -> _form -> form` (aceeasi baza ca `frm_modific2024`).
- `do_modifica` (`ofacturare_comun.vc2:4382-4482`): deschide un formular **diferit**,
`frm_modifica_factura` (editeaza doar metadate: ruta/delegat/agent/masina/text
aditional/data act/serie act — NU sume), apoi cheama `pack_facturare.modifica_date_factura(...)`.
La linia 4432 exista deja garda exacta ceruta de utilizator:
`If poRec.sters = 0 AND NVL(m.pnEFactura,0) = 0` — verifica `anaf_efactura` (linia 4428) si
blocheaza cu mesajul *"Nu puteti face modificari pe inregistrarile sterse sau facturile
trimise in eFactura!"* daca factura a plecat deja. **Acesta e modelul de garda de reutilizat**
pentru o actiune noua "editare directa".
- `do_sterge` (`4503-4719`) e modelul arhitectural cel mai apropiat de ce se cere: incarca
`vact_tot`/`vrul_tot`/`vrul_obinv_tot` filtrate pe `cod` in `actactan`/`rul_temp`/
`rul_temp_obinv` (4573-4615), arata un formular de verificare (`Createobject('verificare')`,
4620), deschide tranzactie manuala (4625), apeleaza `OSCRIE_IN_FISIERE(2,.F.,llRul)` (4632),
apoi `pack_contafin.finalizeaza_stergere_nota(...)` (4652-4653), commit/rollback (4662-4673).
Cazul special "eProforma" foloseste in schimb un singur apel PL/SQL,
`pack_facturare.sterge_proforma` (4549-4560); cazul fara randuri in `act` foloseste
`pack_facturare.sterge_factura` direct (4689).
- **Corectie fata de ipoteza initiala**: nu exista `nid_cw` in `ofacturare_comun.vc2`.
Vizibilitatea/activarea butoanelor `do_modifica`/`do_sterge` e controlata prin flag-urile
`This.lactiv3`/`This.lactiv4` (definite in `_frm_base.vc2`, default `.F.`) si prin variabila
globala `gcAcces` (sir de tokeni gen `"4;"` pentru dreptul de stergere — vezi
`ofacturare_comun.vc2:4773-4776`, unde `glLunaInchisa` scoate tokenul `4;` din `gcAcces` si
ascunde `Thisform.but_sterge1`). `nid_cw` exista doar in `ofundal.vc2` si
`drept_grupuri.vc2` (proprietate pe clasa de fundal/toolbar, nefolosita in
`ofacturare_comun.vc2`) — deci reteta de "adaugare actiune noua" e: (1) adauga metoda
`do_<actiune>` pe `frm_facturi` dupa modelul `do_sterge`, (2) adauga un buton nou pe
toolbar-ul formularului (langa `but_sterge1`) cu `Click` care cheama `Thisform.do_<actiune>()`,
(3) controleaza vizibilitatea prin acelasi mecanism `gcAcces`/`lactivN` daca se doreste
control pe drepturi, altfel doar prin garda `sters=0 AND eFactura=0` din pct. eFactura de mai
sus.
## 5. Fezabilitate scriere (cel mai important)
**NU exista niciun `UPDATE`/`DELETE` direct pe `ACT`/`RUL` in cod VFP** (cautat
`update act `, `update rul `, `delete from act`, `delete from rul` in tot
`ROAFACTURARE` si `ROAGEST\COMUN` — zero rezultate). Singura cale de scriere e prin
tabelele staging Oracle `ACT_TEMP`/`RUL_TEMP`:
1. VFP populeaza cursoare `actactan`/`rul_temp`/`rul_temp_obinv` (READWRITE, incarcate din
view-urile `vact_tot`/`vrul_tot`/`vrul_obinv_tot`).
2. `COMUN\programe\oscrie_in_fisiere.prg` (10 461 octeti, 25.03.2026): parametrul
`tnScrie_Sterge` (0=scriere, 2=stergere) — apeleaza `pack_contafin.init_scriere_act_rul_local`
(linia 121), apoi `sql_temp_insert('actactan','ACT_TEMP')` / `sql_temp_insert('rul_temp',
'RUL_TEMP')` care fac `INSERT INTO ACT_TEMP`/`RUL_TEMP` rand cu rand (liniile 127-136, 272-274
— singurele DML explicite din acest fisier, si sunt pe tabelele `_TEMP`, nu pe `ACT`/`RUL`),
apoi `pack_contafin.final_scriere_act_rul_local` (linia 141-143) care, in Oracle, ruleaza
`SCRIE_IN_ACT`/`STERGE_DIN_ACT` din `PACK_CONTAFIN.pck` — **acolo** se face efectiv
`UPDATE ACT SET STERS=1 ...` (stergere) sau `INSERT`/`UPDATE ACT_TEMP -> ACT` (scriere) prin
PL/SQL, in Oracle, nu in VFP.
3. Editarea NU suprascrie randul vechi: la modificare, randurile vechi din `ACT`/`RUL`/`RUL_OBINV`
raman cu `STERS=1`, iar un document nou (`cod` nou, acelasi `id_fact`/`id_factd`) e scris in
locul lor — comportament confirmat explicit ca "nu e bug" in
`D:\ROA\ROAGEST\COMUN\docs\flux-modificare-stergere-nota-jurnal.md`.
4. `pack_contafin.finalizeaza_modificare_nota` (`PACK_CONTAFIN.pck:8601-8651`) — apelata dupa
`oscrie_in_fisiere` — **deja contine sincronizarea cu `vanzari`**:
```
SELECT COUNT(*) INTO lnEInVanzari FROM vanzari WHERE cod = tnCod;
IF lnEInVanzari > 0 THEN pack_facturare.actualizeaza_vanzari(tnCod, lnCodNou); END IF;
UPDATE atasamente_vanzari SET cod = lnCodNou WHERE cod = tnCod;
```
si simetric, `finalizeaza_stergere_nota` (`8653-8709`) apeleaza
`pack_facturare.sterge_din_vanzari(tnCod, tnAn, tnLuna, tnIdUtil)`.
**Acesta e precedentul concret ca "editarea act/rul actualizeaza automat vanzari"** — dar
sursa pachetului `PACK_FACTURARE` (unde traiesc `actualizeaza_vanzari`/`sterge_din_vanzari`/
`modifica_date_factura`/`sterge_factura`/`sterge_proforma`) **nu e exportata** in
`COMUN\docs\*.pck` din acest working copy (doar `PACK_CONTAFIN`, `PACK_DIAG_SPATIU`,
`PACK_MIGRARE`, `PACK_UPDATE`) — deci **nu se poate stabili din working copy** daca
`actualizeaza_vanzari` recalculeaza si sumele/liniile din `vanzari_detalii` sau doar
realiniaza `vanzari.cod` la `cod`-ul nou generat de `pack_contafin.get_cod()`. Asta e
intrebarea-cheie de lamurit inainte de a proiecta planul (posibil necesar acces la codul
Oracle sau la un DBA/export suplimentar al `PACK_FACTURARE`).
Concluzie arhitecturala: planul de "editare directa" trebuie sa respecte acelasi flux
(cursoare temp -> `ACT_TEMP`/`RUL_TEMP` -> `PACK_CONTAFIN`), nu un `UPDATE`/`DELETE` VFP
direct pe `ACT`/`RUL` — asta nu exista nicaieri ca precedent si ar ocoli toata logica de
alocare `cod` nou, marcare `sters`, si sincronizare `vanzari`/`atasamente_vanzari` care traieste
in Oracle.
## 6. Precedent de editare de nota contabila (afara de frm_modific2024)
**Nu exista un formular separat** pentru "MODIFICARE REGISTRU JURNAL" — e acelasi
`frm_modific2024`, folosit din `afisjurcom.do_modifica`
(`D:\ROA\ROAFACTURARE\COMUN\clase\comun.vc2:2222-2563`, identic si in
`ROAGEST\COMUN\clase\comun.vc2`). `afisjurcom` = clasa formularului "Registru jurnal" (afisare
jurnal contabil). Acesta e **precedentul complet, deja documentat**:
`D:\ROA\ROAGEST\COMUN\docs\flux-modificare-stergere-nota-jurnal.md` descrie exact acest flux
(scris de un agent/dezvoltator anterior, cross-verificat de mine cu codul — coincide integral
cu ce am gasit independent la pct. 2 si 5). N-am gasit un literal "MODIFICARE REGISTRU JURNAL"
in `ROAGEST\todo.txt` (cautat, zero potriviri) — probabil e o formulare verbala a
utilizatorului, nu un text din cod; funcțional se refera la exact acest `afisjurcom.do_modifica`.
`afisjurcom.do_modifica` (rezumat, pentru referinta directa la implementare):
- 2253-2264: citeste `an`/`luna`/`cod`/`id_set`/`id_fact`/`id_factd` din randul curent din grid.
- 2265-2268: blocheaza daca nu e luna curenta.
- 2313-2331: elibereaza cursoarele vechi (`actactan`, `tact`, `rul_temp`, `trul`, ...).
- 2352-2427: incarca `vact_tot`/`vrul_tot`/`vrul_obinv_tot` filtrate pe `cod` in
`actactan`→`tact`, `rul_temp`→`trul`, `rul_temp_obinv`→`trul_obinv` (READWRITE).
- 2436: `Omodif = Createobject([frm_modific2024],lnIdSet)` ; 2442: `Omodif.Show()` (modal).
- 2444-2541: daca userul a apasat Terminat (`buton=1`), deschide tranzactie
(`Thisform.do_deschide_tranzactie()`), `oscrie_in_fisiere(2,.T.,llRul)` (sterge vechi),
reincarca `tact`→`actactan`/`trul`→`RUL_TEMP`/`trul_obinv`→`RUL_TEMP_OBINV` cu
`id_util`/`sters=0`, `oscrie_in_fisiere(0,.T.,llRul)` (scrie nou),
`pack_contafin.finalizeaza_modificare_nota(...)`, apoi
`Thisform.do_inchide_tranzactie(...)` (commit/rollback) si `Thisform.do_cauta` (refresh grid).
- Cod mort comentat la 2496-2503 arata ca la un moment dat exista aici EXPLICIT un apel
`pack_facturare.actualizeaza_vanzari(lnCod, pack_contafin.get_cod())` **direct din VFP** pentru
"nota din ROAFACTURARE" — mutat ulterior in Oracle, in
`pack_contafin.finalizeaza_modificare_nota` (pct. 5). Confirma ca legatura
notă-contabila-din-jurnal <-> `vanzari` a fost tratata explicit de dezvoltatori anterior,
exact pentru cazul ROAFACTURARE.

View File

@@ -1,243 +0,0 @@
# Cercetare: lant pret (#12) + editare politici pret (#11/#10) + lazy loading
## REZUMAT (max 30 linii, focus A2 + C2)
**A2 — NU exista niciun fallback la nomenclator azi.** Confirmat din chiar view-ul care alimenteaza
majoritatea ramurilor lui `cursor_preturi` (`fact_vpreturi_utilizator`, definit in
`D:\ROA\DATABASE\SCRIPTURI\2009\4\ff_2009_04_21_03_FACTURARE.sql:11-50`): clauza
`and d.id_pol is not null` (linia 49) e o conditie **obligatorie** pe `crm_politici_pret_art d` —
un articol nu apare deloc in lista de vanzare daca nu are un rand in `CRM_POLITICI_PRET_ART` pentru
politica activa a utilizatorului. `NOM_ARTICOLE` e joinat doar pentru `um/denumire/codmat/codbare/
in_stoc` (descriptive), niciodata pentru `pret/valuta/proc_tvav`. In `PACK_FACTURARE.cursor_preturi`
insusi (`ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql:2121-2627`) acelasi tipar se repeta in toate
ramurile (2, 45, 1/2, 5/6/10/52, 7, else/aviz): driver-ul e mereu `CRM_POLITICI_PRET_ART`/politica,
niciun `NVL`/`COALESCE` catre `catalog_articole`/`nom_articole` pentru pret. Nu exista deloc referinte
la `catalog_articole` in tot pachetul `PACK_FACTURARE` (grep pe fisierul de 16948 linii: 0 hit-uri).
**Concluzie: fallback-ul de #12 chiar trebuie construit de la zero.** Locul ieftin de inserat: in
`fact_vpreturi_utilizator` si/sau direct in `cursor_preturi`, un `UNION ALL`/`LEFT JOIN` suplimentar
care aduce articolele din `catalog_articole` **fara** rand in `CRM_POLITICI_PRET_ART` pentru
politica curenta, cu pret/valuta/tva **NULL sau valori implicite din optiuni firma** — deoarece
`catalog_articole` nu are nicio coloana de pret/valuta/tva (confirmat de echipa, si verificat: n-am
gasit `PRET`/`ID_VALUTA`/`PROC_TVAV` pe `NOM_ARTICOLE`/`CATALOG_ARTICOLE` in DDL). Fallback-ul e deci
"articolul apare, dar utilizatorul trebuie sa completeze pretul manual" — nu un pret implicit real.
**C2 — Exista deja un sablon de lazy loading, complet si reutilizabil**, in
`COMUN\clase\_ct_base.vc2:278-281` (`do_activeaza_container` → `This.actualizeaza_cursoare()`), legat
la `PageX.Activate` (`Clase\ofundal_facturare.vc2:1006-1008` pentru comenzi). Implementarea reala e
in `COMUN\clase\ocomenzi.vc2:1088-1104`: cursorul se creeaza o singura data (guard
`!Used('crscomenzi') Or gcS!=This.cSchema Or ...schimbare sectie`), cu un `WHERE` imposibil
(`id_comanda = -9999999`) — deci structura se creeaza dar nu se aduc date. Datele reale vin abia la
`do_cauta()` (`ocomenzi.vc2:1484-1510`), care trimite un `WHERE` filtrat prin `gencursor`/
`ca_baza1.afisare()` — deci cautarea e deja server-side (Oracle), nu filtrare locala. **Acesta e
sablonul de refolosit pentru #11/#10, exact cum indica deja `plan_10_integrare_contracte.md` S3.**
Atentie: baza `_ct_base.actualizeaza_cursoare` (linia 231-232) e un stub gol — clasa container noua
(`ct_preturi`/`ct_contracte`) trebuie sa suprascrie explicit `actualizeaza_cursoare`, dupa modelul
`ocomenzi`, nu doar sa mosteneasca `_ct_base`. `ct_contracte` din ROACONTRACTE **nu** face asta azi
(vezi C4) — deci nu e lazy, desi mosteneste acelasi `_ct_base`.
---
## A. Lantul de determinare a pretului
### A1. `cursor_preturi` — surse pe ramura (spec `:335-343`, body `:2121-2627`,
`ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql`)
Toate ramurile pornesc din `pack_facturare.initializeaza_facturare` + `completare_politica_stoc` +
`verifica_cursuri_valute` (:2132-2136), apoi `CASE V_TIP`:
- **V_TIP=45 (restaurant)**, `:2143-2247`: subselect A = politica activa a utilizatorului
(`utilizatori_rol_intern` → `politici_grupuri` → `crm_politici_preturi` → `crm_note_vanzari` →
`note_contabile`, filtrat pe `datai/datas` fata de luna curenta si `id_sucursala`), apoi
`LEFT JOIN CRM_POLITICI_PRET_ART B ON A.ID_POL=B.ID_POL`, `LEFT JOIN NOM_ARTICOLE C`. **Pret**:
`B.PRET`/`B.DISCOUNT_UNITAR` convertite prin curs (`F.CURS`) daca valuta politicii ≠ valuta
nationala. **Valuta**: `B.ID_VALUTA` → `NOM_VALUTE G`. **TVA%**: `B.PROC_TVAV` (direct din
`CRM_POLITICI_PRET_ART`, nicio referinta la `ID_JTVA_COLOANA` in acest cursor). **Flag
pret_cu_tva**: `A.PRETURI_CU_TVA` (de pe `crm_politici_preturi`, nu per-articol). **Cont**:
`'371' AS CONT` — **hardcodat**, nu vine din nicio tabela.
- **V_TIP IN (1,2) (factura lei)**, `:2248-2372`: acelasi tipar (A/B/C), plus `LEFT JOIN` pe `STOC`
pentru cantitate gestionabila (E) si pe `CURS`/`NOM_VALUTE` (F/G). Nicio coloana `CONT` in select.
- **V_TIP IN (5,6,10,52) (valuta)** si **V_TIP=7 (credit note)**, `:2374-2524`: sursa e view-ul
`FACT_VPRETURI_UTILIZATOR A` (nu mai construieste politica inline), plus `STOC` (C) si `CURS`/
`NOM_VALUTE` (D/E). Filtru `A.ID_VALUTA=V_ID_VALUTA AND A.IN_VALUTA=1` (sau `A.ID_POL=
pack_facturare.nid_politica_stoc` la tip 5/6/10/52). Nicio coloana `CONT`.
- **ELSE (aviz)**, `:2526-2624`: tot din `FACT_VPRETURI_UTILIZATOR A`, fara filtru pe valuta. Nicio
coloana `CONT`.
**Definitia `FACT_VPRETURI_UTILIZATOR`** (cea mai recenta gasita, `D:\ROA\DATABASE\SCRIPTURI\2009\4\
ff_2009_04_21_03_FACTURARE.sql:11-50`; nu a mai fost modificata in `SCRIPTURI_CLAR`, deci pare
stabila de atunci):
```
utilizatori_rol_intern a
left join politici_grupuri b on a.id_grup=b.id_grup
left join crm_politici_preturi c on b.id_politica=c.id_pol
left join crm_politici_pret_art d on b.id_politica=d.id_pol
left join nom_articole e on d.id_articol=e.id_articol -- doar um/denumire/codmat/codbare/in_stoc
left join crm_note_vanzari f on c.id_nota=f.id_nota
left join note_contabile g on f.id_set=g.id_set
where ... and d.id_pol is not null -- <- gate-ul, vezi A2
```
Coloane expuse: `id_pol, preturi_cu_tva, nume_lista_preturi, id_articol, pret, discount_unitar,
proc_tvav, um, denumire, codmat, codbare, gestionabil, id_valuta, in_valuta, nota_discount`. **Nicio
coloana `cont`.**
**`ID_JTVA_COLOANA`**: nu apare deloc in `cursor_preturi`. Grep pe tot pachetul arata ca se
foloseste doar mai tarziu, la scriere/postare (`scrie_in_vanzari`, `descarca_gestiune`,
`contabilizeaza_tva`, in jur de liniile 3700-4130, 4660-5400, 12250-13700 din pachet) — deci cota de
TVA "oficiala" (coloana `JTVA_COLOANE`) se rezolva separat de `PROC_TVAV`-ul afisat la selectarea
pretului, probabil prin cautare dupa procent in `citeste_id_jtva_coloana`-tip logica (nu am urmarit
in detaliu — in afara bugetului A, marcat ca zona neexplorata).
**Cont de vanzare, de fapt**: parametrul `V_CONT` din `PACK_FACTURARE.adauga_articol_factura`
(`:4972-4998`) e trimis de VFP la adaugarea liniei (valoare `'XXXX'` = "fara override" -> `V_CONT2`
ramane NULL). Nu am gasit el sa fie citit din `CRM_POLITICI_PRET_ART`/`NOM_ARTICOLE` in acest flux;
in schimb exista deja `initializeaza_date_gestiune(V_ID_GESTIUNE, V_ID_TIPGEST, V_CONT, V_ACONT)`
(spec `:311-314`) care leaga contul de **gestiune**, nu de articol/politica. Separat, pachetul
`PACK_PRETURI` (editorul din ROAPRETURI) scrie `NOM_ARTICOLE.CONT` direct la
`adauga_articol`/`modifica_articol` (`D:\ROA\DATABASE\SCRIPTURI\2008\7\ff_2008_07_31_01_PRETURI.sql
:107-130, 300-330, 386-424`) — deci **contul de vanzare al articolului exista deja pe
`NOM_ARTICOLE.CONT`** (= `catalog_articole.cont` din nomenclatura curenta), independent de orice
lista de preturi. Asta inseamna ca, pentru #12, contul NU are nevoie de fallback nou — poate fi citit
direct din nomenclator, exact ce cere planul (ramane de confirmat unde/cum VFP populeaza azi `V_CONT`
la trimiterea catre `adauga_articol_factura`, cautare separata, in afara bugetului acestei runde).
### A2. Fallback existent — **NU exista**. Detaliat mai sus (rezumat) si in A1
(`d.id_pol is not null`, zero hit-uri `catalog_articole` in `PACK_FACTURARE`). Singurul loc unde
`NOM_ARTICOLE`/nomenclatorul intra in calculul de pret e ca sursa a campurilor descriptive
(um/denumire/codmat/codbare/in_stoc), niciodata pentru pret/valuta/tva/cont.
### A3. `citeste_setari_pol_pret` (`:2025-2065`)
Nu seteaza `pret_cu_tva`/TVA. Citeste doar **care politica e implicita** pentru un `V_ID_UTIL`, in
functie de `V_TIP`: `OPTIUNI.VARNAME` = `'ID_POL_PRET_TR'` (tip 23/30/41), `'ID_POL_PRET_STOC'`
(tip 1), `'IDPOLPRETFACTK'` (tip 48/49), fiecare cu `LEFT JOIN CRM_VPOLPRETCURUTIL B ON ... AND
B.ID_UTIL=V_ID_UTIL`. Deci `pret_cu_tva`/TVA vin exclusiv din randurile `crm_politici_preturi`/
`crm_politici_pret_art` selectate ulterior de `cursor_preturi`, nu din aceasta procedura.
### A4. Tabelele politicii de pret (coloane confirmate din uz + din
`ff_2008_07_31_01_PRETURI.sql:10-95`, ADD/FK, si `create or replace view vcrm_politici_preturi`):
- **`CRM_POLITICI_PRETURI`**: `ID_POL, NUME_LISTA_PRETURI, DATAI, DATAS, ID_VALUTA, ID_UTIL,
DATAORA, NOTA_ONLINE, ID_NOTA, PRETURI_CU_TVA, ID_SUCURSALA, STERS`. FK: `ID_VALUTA->NOM_VALUTE`,
`ID_NOTA->CRM_NOTE_VANZARI`, `ID_SUCURSALA->CONTAFIN_ORACLE.NOM_FIRME`.
- **`CRM_POLITICI_PRET_ART`**: `ID_POL, ID_ARTICOL, ID_VALUTA, PRET, PRETFTVA, PRETCTVA, PROC_TVAV,
DISCOUNT_UNITAR, STERS` (din `modificare_politica_stoc`, `:2105-2119`, si din selectii). **Nicio
coloana CONT.**
- Nu am gasit `CREATE TABLE` originar pentru aceste doua tabele in `SCRIPTURI_CLAR` (probabil
create inainte de 2006, in afara arhivei "clare"); coloanele de mai sus sunt derivate din uz activ
in cod, nu dintr-un DDL complet — de tratat ca aproape sigure, nu 100% exhaustive (pot exista
coloane suplimentare needitate de codul cercetat).
- View-uri asociate: `VCRM_POLITICI_PRETURI` (`ff_2008_07_31_01_PRETURI.sql:42-65`),
`VPOLITICI_GRUPURI` (`:67-95`), `CRM_VPOLPRETCURUTIL` (folosit pretutindeni, definitia lui nu a
fost cautata — in afara bugetului).
---
## B. Cine mai foloseste listele de preturi
- **ROAFACTURARE**: doar citeste. `crm_vpolpretcurutil` la `COMUN\clase\baza.vc2:10087,10157,
10502-10512` (filtrare politici dupa dreptul utilizatorului); `facturare_lista_de_preturi` =
`Do politica.mpr` (`COMUN\programe\oproceduri_facturare.prg:113-116`); rapoarte grupate pe
`nume_lista_preturi` din `vvanzari_detalii` (`COMUN\clase\configurare.vc2:3915-3972`).
(Sursa: `docs\plan_11_integrare_politici_preturi.md:15-22`, deja in `D:\ROA\ROAFACTURARE\docs\`.)
- **ROAPRETURI** (`D:\ROA\ROAPRETURI`, exe separat `roapreturi.exe`): **editeaza** politicile —
`Clase\opreturi.vcx`, `Clase\onom_preturi.vcx`, `Clase\ofundal_preturi.vcx`,
`Programe\update_preturi.prg`, `Programe\update_nomenclator.prg`. Pachet Oracle `PACK_PRETURI`
(`adauga_articol`/`modifica_articol`/`verifica_articol` — scriu si pe `NOM_ARTICOLE`, nu doar pe
politica). **Nu are cache text (.vc2/.sc2) generat** — nu s-a putut inspecta clasa in detaliu (vezi
C4); confirmat prin `Glob D:\ROA\ROAPRETURI\**\*.vc2` = 0 fisiere, doar `.vcx` binare.
- **ROACONTRACTE** (`D:\ROA\ROACONTRACTE\Clase\ferestre_contracte.vc2`): citeste direct
`vcrm_politici_preturi` / `vcrm_politici_pret_art` prin SQL Pass Through (`goExecutor.oExecute`),
la cautarea/atasarea unui articol pe linie de contract
(`Programe\oproceduri_roacontracte.prg:213-239`: `select id_pol,... from vcrm_politici_preturi`,
apoi `select id_articol, id_pol_art, ... from ]+gcS+[.vcrm_politici_pret_art where id_pol=...`).
Nu editeaza politica insasi, doar o consuma pentru a atasa articole+pret pe contract.
- **ROAGEST**: 0 hit-uri directe pe `CRM_POLITICI_PRET*`/`cursor_preturi`/`PACK_PRETURI` in cod VFP
(`.vc2`/`.prg`) — foloseste probabil acelasi `PACK_FACTURARE` server-side prin
`Programe\ofactureaza.prg` (fisier gasit la cautarea `id_pol`, dar doar in comentarii vechi de
schema cursor, nu apel activ identificat in bugetul alocat).
- **ROAACNPRO**: la fel, 0 hit-uri directe; `id_pol` apare doar intr-un `Text To lcSchema`/
`lcSelect` ascuns (`Omitted long matching line` — continut necunoscut, de investigat separat daca
devine relevant).
- **ROAIMOB**: 0 hit-uri (`.vc2`).
- **COMUNROA**: 0 hit-uri (`.vc2`) — surprinzator pentru un modul "CRM transversal"; posibil ca
accesul se face exclusiv server-side (proceduri Oracle), nu prin VFP direct in produsele
verificate, sau ROAGEST/ROAACNPRO folosesc cod VFP montat din `COMUN` (acelasi `ocomenzi.vcx` etc.)
fara sa atinga politica de pret local.
- **Nomenclatorul comun** (`update_nomenclator.prg` in ROAPRETURI) scrie in tabela de articole
folosita de toate produsele — punct de atentie deja notat in `plan_11...md:82-84` (S2, perimetru).
**Concluzie B**: politica de pret (structura de date) e deja un modul transversal minim
(ROAFACTURARE citeste, ROAPRETURI editeaza, ROACONTRACTE citeste), consistent cu ce spune deja
`plan_11...md`. Nu s-a gasit inca un al patrulea consumator activ in cod VFP (ROAGEST/ROAACNPRO
probabil trec prin acelasi `PACK_FACTURARE` server-side, fara sa atinga tabelele direct din VFP).
---
## C. Incarcare lazy si cautare
### C1. Cum incarca azi paginile mari
- **`ct_comenzi`** (`COMUN\clase\ocomenzi.vc2`): montat ca `Page5.Ct_comenzi1`
(`Clase\ofundal_facturare.vc2:604-606`). `PROCEDURE Page5.Activate` (`:1006-1008`) apeleaza
`this.ct_comenzi1.do_activeaza_container()`. Aceasta e mostenita din `_ct_base.vc2:278-281`
(`do_activeaza_container` → `bind keypress` + `This.actualizeaza_cursoare()`).
`ocomenzi.actualizeaza_cursoare` (`:1088-1104`) **nu incarca date** — creeaza doar structura
cursorului prin `creeaza_cursoare()` (`:1191-1245`), cu `lcFiltru = [id_comanda = -9999999]`
(`:1216`) — deci 0 randuri reale la deschidere/activare de pagina.
- **`onom_articole.vc2`**: editorul de articol individual (`PROCEDURE Init`, `:1704-1772`) e per-
inregistrare (`toRec`), nu o grila; incarca doar cursoarele mici de grupe/subgrupe pentru combo-uri
(`crs_grupe_art`, `crs_subgrupe_art`, `:1717-1729`). Nu s-a gasit/verificat in bugetul alocat cum
se incarca lista/grila principala de articole a nomenclatorului (formularul-parinte, nu editorul) —
**neacoperit**, marcat ca zona pentru o runda ulterioara daca devine relevanta pentru #12/#11.
### C2. Sablon de lazy loading existent — **DA**, detaliat in rezumat.
Cheia: `_ct_base.do_activeaza_container` (hook legat de `Page.Activate`) → `actualizeaza_cursoare()`
**suprascrisa** in clasa concreta cu un guard `!Used(cursor) Or <context s-a schimbat>` →
`creeaza_cursoare()` cu `WHERE` fals → date reale doar la `do_cauta()`. `_ct_base` insusi ofera doar
stub-uri goale (`:231-232` pentru `actualizeaza_cursoare`, la fel `do_adauga/do_cauta/...` la
`:283-322`) — **fiecare container concret trebuie sa implementeze explicit lazy-load-ul**, nu vine
gratis din mostenire.
### C3. Cautare server-side vs. filtrare locala
- **Server-side (tiparul de urmat)**: `ocomenzi.do_cauta` (`:1484-1510`) construieste `lcFiltru`
(`id_sectie = ...` + `filtru_pretty`) si il trimite prin `actualizeaza_grid1(lcFiltru)` →
`pocomenzi.ca_baza1.cfiltru=lcFiltru` → `pocomenzi.ca_baza1.afisare()` (`:1109-1123`) — clasa
`ca_baza1` (generata de `gencursor`) trimite `WHERE`-ul catre Oracle prin `goExecutor`, nu
filtreaza un cursor deja incarcat integral.
- **Local (contra-exemplu)**: `actualizeaza_grid1` in continuare (`:1119-1124`) face si operatii pur
locale pe cursor deja adus (`SELECT * FROM crscomenzi WITH (Buffering=.T.) WHERE selectat=1 INTO
CURSOR crstempcomenzi`) — dar asta e pentru pastrarea selectiei intre reincarcari, nu pentru
cautare/filtrare initiala.
### C4. ROAPRETURI / ROACONTRACTE — incarca tot la deschidere?
- **ROAPRETURI**: **nu se poate stabili** — lipseste cache-ul text (`.vc2`/`.sc2`), doar `.vcx`
binare (`Clase\opreturi.vcx`, `Clase\ofundal_preturi.vcx`); conform regulilor primite, nu am
convertit nimic. Precondiitia e deja documentata ca blocanta in `plan_11...md:66-70` (S1: inrolare
in fluxul text, procedura `COMUN\docs\inrolare-proiect-git-text.md`).
- **ROACONTRACTE**: `ferestre_contracte.vc2` are cache text si e vizibil. Descoperire importanta:
clasa container `ct_contracte` (`:9`, `DEFINE CLASS ct_contracte AS _ctfrmbase OF
"..\comun\clase\_ct_base.vcx"`) **mosteneste acelasi `_ct_base`** ca `ct_comenzi`, si are propriul
`filtru_pretty`/`but_start_criterii1` (vazut in `But_reset_criterii1.Click`, `:1551-1567`) — deci
infrastructura de cautare exista. **Dar nu suprascrie `actualizeaza_cursoare`/`creeaza_cursoare`**
(0 hit-uri in fisier) — inseamna ca foloseste stub-ul gol din `_ct_base` pentru acel hook, iar
cursorul principal (`cContracte`, vazut deja populat la `PROCEDURE Init` a ferestrei,
`:1518-1527`, `Select cContracte / If Reccount()>0`) se incarca **altundeva, probabil eager, la
deschiderea formularului** — nu s-a gasit punctul exact de populare in bugetul alocat (cautare
separata necesara: `cContracte` INTO CURSOR / gencursor pentru contracte). **Concluzie: ROACONTRACTE
NU e azi lazy**, desi are "schela" pentru a deveni (acelasi `_ct_base`). Pentru #10/#11, sablonul
de copiat e strict cel din `ocomenzi.vc2`, nu cel din `ferestre_contracte.vc2`.
---
## Neacoperit / de reluat intr-o runda viitoare
- `CRM_VPOLPRETCURUTIL` — definitia view-ului (coloane exacte, drepturi).
- `ID_JTVA_COLOANA` — cum se leaga procentul afisat in `cursor_preturi` (`PROC_TVAV`) de coloana TVA
oficiala folosita la postare.
- Unde/cum populeaza azi VFP parametrul `V_CONT` la `adauga_articol_factura` (ipoteza: din gestiune,
nu din articol) — relevant pentru a confirma daca planul #12 poate refolosi direct
`NOM_ARTICOLE.CONT` fara alta lucrare.
- Incarcarea listei/grilei principale de articole din `onom_articole.vc2` (formularul-parinte, nu
editorul per-inregistrare).
- Unde exact se populeaza `cContracte` in `ferestre_contracte.vc2` (cautare punctuala, nu facuta).
- ROAGEST/ROAACNPRO: confirmarea ca folosesc `PACK_FACTURARE` exclusiv server-side pentru preturi
(ipoteza, nu verificata prin citirea completa a `ofactureaza.prg`/`proceduri_acnpro.prg`).

View File

@@ -1,6 +1,6 @@
# Review S4 runda 1 (PAGE3 "Articole factura") - ancorare coloane + calitate cod
Review de cod, fara nicio modificare aplicata. Obiect: `docs\diff_s4_runda1_page3.patch`
Review de cod, fara nicio modificare aplicata. Obiect: diff aplicat (sters)
(`COMUN\clase\omodificari.vc2` clasa `frm_modific2024`, `COMUN\programe\ofacturare_editare.prg`).
Context citit: `docs\cercetare\rec_s4_runda1.md`, `docs\progres.md` (sectiunea "#6, S4 runda 1" si
decizia/nota despre pozitionarea in `actactan`), `COMUN\docs\reguli_lucru.md`,

View File

@@ -1,110 +0,0 @@
# S10 + S12 — versiune_db.txt, curatare VERSIUNE, propunere changelog 2.11.13
## S10 — `versiune_db.txt`
Regula exacta, confirmata in `COMUN\docs\scripturi-migrare-db.md` ("Numerotare si versiune_db.txt"):
in `versiune_db.txt` se trece **doar versiunea ultimului script `ff_`** (nu `co_`/`sys_`/`rf_`/`ris_`),
pentru ca programele se conecteaza pe schema firmei, nu pe `CONTAFIN_ORACLE`.
Verificat pe disc, `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\`: cinci scripturi `ff_2026_08_06_*`
aplicate azi pe `MARIUSM_AUTO` — `_02` (`PACK_FACTURARE`, S4), `_03` (`PACK_FACTURARE`, S7), `_04`
(`VANZARI_COMANDA_CONTRACT`, S6), `_05` (`FACT_VFACTURI`, S8), `_06` (`VANZARI_BACKFILL`, S5).
Confirmat si prin interogare pe `VERSIUNE` (`order by data_script desc, seq_script desc`): ultimul
`ff_` aplicat e `ff_2026_08_06_06_COMUN_VANZARI_BACKFILL.sql`.
**Scris in `versiune_db.txt`: `2026_08_06_06`** (fara newline la final, pastrand conventia
fisierului existent — verificat byte-level, 13 octeti, identic ca lungime cu vechea valoare
`2026_08_02_01`).
## S10 — starea tabelei `VERSIUNE`
Interogata direct pe `MARIUSM_AUTO` (`docs\cercetare\s10_curata_versiune.sql`, pasul 1). Numar de
inregistrari per script, azi:
| Script | Inregistrari |
|---|---|
| `ff_2026_08_06_02_COMUN_PACK_FACTURARE.sql` (S4) | 2 |
| `ff_2026_08_06_03_COMUN_PACK_FACTURARE.sql` (S7) | 1 |
| `ff_2026_08_06_04_COMUN_VANZARI_COMANDA_CONTRACT.sql` (S6) | 2 |
| `ff_2026_08_06_05_COMUN_FACT_VFACTURI.sql` (S8) | 4 |
| `ff_2026_08_06_06_COMUN_VANZARI_BACKFILL.sql` (S5) | 5 |
14 randuri in total pentru cele 5 scripturi de azi, 9 in plus fata de cate 1 per script. Confirma
tiparul semnalat: `_02`, `_05`, `_06` (si, in plus fata de ce era asteptat, `_04`) au fost aplicate
de mai multe ori pe masura extinderii lor in cursul zilei; `_03` are deja un singur rand, nimic de
curatat acolo.
**Propunere, nerulata**: `docs\cercetare\s10_curata_versiune.sql`. Pastreaza per script randul cu
`ID_VERSIUNE` maxim (ultima aplicare = starea finala reala a scriptului), sterge restul — scoped
strict pe cele 5 nume de script din lista de mai sus, cu `select` de verificare inainte si dupa,
`delete` la mijloc, `commit` comentat (de dat manual). Fara impact functional indiferent daca se
ruleaza sau nu: nici `versiune_db.txt`, nici aplicarea DDL nu depind de numarul de randuri din
`VERSIUNE`. **Nu s-a rulat** — stergerea de istoric ramane decizie de om.
## S12 — propunere changelog
Livrat: `docs\propunere_changelog_2.11.13.txt` (neaplicat in `changelog_roafacturare.txt`).
```
<!--
06/08/2026
ROAFACTURARE - 2.11.13
:eroare:
Referinta catre aviz de pe facturi era gresita - toate facturile aratau acelasi aviz, indiferent de cel real. Acum se afiseaza avizul corect acolo unde exista, iar unde nu exista referinta, campul ramane necompletat.
Unele facturi mai vechi ramasesera fara total salvat la emitere si aparea fara valoare la listare sau retiparire. Totalurile lipsa au fost completate.
Cursul valutar afisat pe facturile emise in lei era uneori inregistrat gresit. Facturile in lei nu mai afiseaza curs valutar strain.
La facturile de retur-transfer numele clientului afisat in lista de facturi era uneori gresit. Acum se afiseaza clientul corect.
:modificare:
S-a uniformizat textul explicativ (comanda/contract) afisat pe facturi.
-->
```
### Motivare inclusiune/excludere
- **Aviz, totaluri, curs valutar** (`:eroare:`) — toate trei sunt defecte confirmate ca fiind
efectiv pe date de productie (`VENDING`), vizibile pe facturi reale (lista principala si
retiparire), acum corectate. Se incadreaza clar la `:eroare:`.
- **`CLIENT` pe retur-transfer** (`:eroare:`) — `fact_vfacturi`, folosit de gridul principal de
listare, calcula gresit numele clientului pe cele 23 de facturi `tip=41`/`tip=-6`; view-ul
corect (`fact_vfacturi2`) confirma sursa deliberata din cod. E o valoare gresita afisata in
productie, nu doar o diferenta cosmetica intre doua liste — de aceea l-am pus la `:eroare:` si
nu la `:modificare:`, desi in mesajul initial parea doar "etichete neuniforme".
- **`EXPLICATIE`** (`:modificare:`) — diferenta e strict de formatare a textului
("COMERCIAL - FACTURARE" vs "COMERCIAL-FACTURARE" etc.), nu o valoare gresita; l-am tinut separat
si mai jos in prioritate, la `:modificare:`.
- **Denormalizarea comanda/contract (S6) — EXCLUSA din changelog.** Harnessul de regresie da
aceleasi cifre inainte si dupa aplicarea scriptului; nu exista nimic vizibil pentru utilizator.
O intrare de changelog ar fi inselatoare (ar sugera o schimbare functionala inexistenta).
- **Incasarea lipsa pe facturile din devize auto — EXCLUSA din `changelog_roafacturare.txt`.**
Corectia e integral in cod VFP din **ROAAUTO** (`Programe\oproceduri_devize.prg`,
`factureaza_deviz`) plus un parametru nou cu `DEFAULT` in `PACK_FACTURARE.scrie_incasari`
(pachet Oracle comun, dar ramura noua e apelata **doar** din ROAAUTO). Recompilarea
`roafacturare.exe` singura, fara recompilarea ROAAUTO, nu produce niciun efect vizibil pentru
utilizatorul ROAFACTURARE — deci intrarea nu apartine acestui changelog, chiar daca facturile
respective ar putea fi vazute si din listele ROAFACTURARE dupa ce ROAAUTO e recompilat si el.
**Propunere de text pentru `changelog_roaauto.txt` (needitat, doar propus aici)**:
```
<!--
06/08/2026
ROAAUTO - 2.5.5
:eroare:
La facturile emise din deviz auto nu se inregistra incasarea (chitanta/bon), desi factura era platita. S-a corectat.
-->
```
## Fisiere livrate
- `versiune_db.txt` — actualizat la `2026_08_06_06` (editat direct, marcaj de proiect).
- `docs\cercetare\s10_curata_versiune.sql` — propunere de curatare, **nerulata**.
- `docs\propunere_changelog_2.11.13.txt` — propunere, **neaplicata** in `changelog_roafacturare.txt`.
- Acest raport.
**Fara commit** (git/SVN). Nu s-au atins scripturile de migrare, nu s-a rulat DDL, nu s-a scris in
`VERSIUNE`.

View File

@@ -1,446 +0,0 @@
# Cercetare S1-S3 (plan_06_editare_factura.md) - stare cod la 08.08.2026
Refera ancorele planului dupa commit-urile #7/#8. Toate liniile de mai jos sunt din textul
`.vc2` regenerat de `git_sync.ps1` in aceasta sesiune (deci la zi cu binarul).
## A. Ancore re-verificate
### A1. frm_facturi.do_sterge - COMUN\clase\ofacturare_comun.vc2:4501-4717
Clasa `frm_facturi` incepe la `ofacturare_comun.vc2:1168` (mosteneste `_frmbase`). Metoda
`do_sterge` e imediat dupa `do_modifica_explicatie` (4482-4499) si inainte de `do_verifica`
(4719-4766). Structura pe pasi:
1. `4502-4508`: citeste `gnLuna`/`gnAn` in variabile, iese daca `crsfacturi` e gol.
2. `4516-4518`: garda **luna inchisa** (`glLunaInchisa`) - `Return` fara mesaj.
3. `4520-4527`: pozitioneaza pe randul curent din `crsfacturi`, citeste `id_vanzare`, `cod`,
an/luna din `data_act`, `sters`, `eproforma`.
4. `4529-4536`: daca deja sters -> mesaj si `Return`; confirmare cu `amessagebox(...,4+32,...)`.
5. `4541-4544`: garda **luna curenta** - `(pnAn*12)+pnLuna <> (gnAn*12)+gnLuna` -> mesaj si
`Return`.
6. `4546-4559`: ramura separata **STERGERE PROFORMA** (`eproforma=1`) - apeleaza direct
`pack_facturare.sterge_proforma(pnIdVanzare,gnIdUtil)` si iese cu `RETURN`, **inainte** de
garda de referinte de mai jos. Facturile/avizele nu intra pe aceasta ramura.
7. `4562-4567`: garda **referinte incasari/plati** -
`ReferinteDocumenteNota(pnAn, pnLuna, lnCod)` (definita in
`COMUN\programe\odocumente.prg:8`) -> daca `.T.`, mesaj si `Return`.
8. `4569-4614`: incarca cursoare pe `cod` din `vact_tot`/`vrul_tot`/`vrul_obinv_tot` (schema
`gcs`), filtrate `sters=0 and an=gnAn and luna=gnLuna and cod=lnCod`, in `actactan`/
`rul_temp`/`rul_temp_obinv`.
9. `4617-4620`: daca sunt randuri in `actactan`, deschide formularul modal `verificare`
(confirmare vizuala inainte de stergere efectiva).
10. `4622-4685`: daca `buton=1` din `verificare`, trece manual pe tranzactie
(`SQLSetprop(gnhandle,"Transactions",2)`), apeleaza `OSCRIE_IN_FISIERE(2,.F.,llRul)`, apoi
`pack_contafin.finalizeaza_stergere_nota(pnLuna,pnAn,Null,lnIdSet,lnCod,lnIdFact,lnIdFactD,
gnIdUtil)`, COMMIT/ROLLBACK dupa rezultat, revine pe tranzactie automata.
11. `4686-4701`: ramura alternativa (fara randuri in `actactan`, adica document fara nota) -
apel direct `pack_facturare.sterge_factura(pnIdVanzare,gnLuna,gnAn,gnIdUtil)`.
12. `4707-4716`: inchide cursoarele temporare.
**Nu exista nicio verificare eFactura in do_sterge** - vezi A3, e o corectie fata de plan.
### A2. Cele 3 garzi lipsa din do_modifica - confirmate, linii curente
Toate trei sunt in `do_sterge` (A1) si lipsesc din `do_modifica` (`ofacturare_comun.vc2:4381-4480`,
care nu verifica deloc luna sau referinte, doar `sters`+eFactura, vezi A3):
- **Luna inchisa**, `ofacturare_comun.vc2:4516-4518`:
```
If glLunaInchisa
Return
Endif
```
- **Luna curenta**, `ofacturare_comun.vc2:4541-4544`:
```
If (pnAn * 12) + pnLuna <> (gnAn * 12) + gnLuna
amessagebox('Nu puteti sterge decat inregistrari din luna curenta!',0,'Atentie!')
Return
Endif
```
Text hardcodat pe "stergere" - la reutilizare pentru editare trebuie schimbat mesajul.
- **Referinte incasari/plati**, `ofacturare_comun.vc2:4562-4567`:
```
*** verificare restrictie stergere documente cu referinte (incasari/plati)
llReferinteDocumente = ReferinteDocumenteNota(pnAn, pnLuna, lnCod) && && odocumente.prg
If llReferinteDocumente
amessagebox("Documentul are referinte (incasari/plati). Nu poate fi sters.", 0+48,"Stergere")
Return
Endif
```
Idem, mesajul e specific stergerii.
### A3. Garda eFactura - CORECTIE fata de plan: e in do_modifica, NU in do_sterge
Cautare exhaustiva `anaf_efactura` in `ofacturare_comun.vc2`: **o singura aparitie**, la linia
4426, in interiorul lui `do_modifica` (4381-4480). `do_sterge` nu contine deloc `anaf_efactura`.
Cod exact, `ofacturare_comun.vc2:4426-4430`:
```
lcSql = [select count(*) as lneFactura from anaf_efactura where id_fact = ] + ALLTRIM(STR(poRec.id_fact))
pneFactura = 0
llSucces = goExecutor.oSelecteaza2Value(m.lcSql, @pneFactura)
If poRec.sters = 0 AND NVL(m.pnEFactura,0) = 0
```
(`pneFactura`/`pnEFactura` e aceeasi variabila, VFP e case-insensitive.)
Garda e refolosibila ca atare (interogare + conditie), dar trebuie extrasa dintr-un `If` care
astazi conditioneaza doar deschiderea dialogului `frm_modifica_factura` - pentru actiunea noua
S1 trebuie sa devina un `Return` explicit cu mesaj, dupa modelul celorlalte garzi din
`do_sterge`, nu o simpla conditie de `If`.
### A4. Mecanismul de drepturi pe frm_facturi
Nu exista o proprietate `lactiv3`/`lactiv4` setata explicit in `ofacturare_comun.vc2` - ele sunt
proprietati generice mostenite din `_frmbase` (`_frm_base.vc2:7`), populate dinamic din
`gcAcces` de metoda comuna `actualizeaza_drepturi`, `_frm_base.vc2:195-228`:
- Format `gcAcces = "opt1;opt2;...;optN;"` (string cu numere separate prin `;`).
- Pentru fiecare token `N` prezent, seteaza `thisform.lactivN = .T.` (linia 203-205:
`lcProp='thisform.lactiv'+Alltrim(lcAcces)` + `&lcProp=.T.`).
- Daca exista si o proprietate `thisform.cbutonN` (lista de nume de butoane separate prin `;`),
seteaza `.Visible = .T.` pe fiecare buton din lista (206-221).
Uzul din `inainte_de_do_modifica`/`inainte_de_do_sterge` (`_frm_base.vc2:476-481, 493-498`):
`If This.lactiv3 Then This.do_modifica()` / `If This.lactiv4 Then This.do_sterge()`. Deci
`lactivN` gateaza EXECUTIA actiunii, `cbutonN` gateaza VIZIBILITATEA butoanelor asociate.
**Tokenii folositi azi de frm_facturi** (proprietati proprii clasei, `ofacturare_comun.vc2:1352-1353`):
- `cbuton2 = but_listare1;but_listare2;But_listare3` (token "2" = listare)
- `cbuton3 = but_modifica1;but_modifica2` (token "3" = modificare - **ambele** butoane de
modificare, cel de antet si cel de explicatie articol, vezi A5)
- Tokenul "4" (stergere) nu are `cbuton4` definit pe `frm_facturi` - vizibilitatea lui
`but_sterge1` e gestionata separat, direct in `Init` (`4770-4773`): daca `glLunaInchisa`,
scoate manual `"4;"` din `gcAcces` si ascunde butonul. `lactiv4` insa tot se seteaza normal
din `gcAcces` (prin mecanismul generic), si `but_sterge1.Click` foloseste implicit
`caction = inainte_de_do_sterge` (default din clasa de baza `but_modifica`/`but_sterge`,
`cmd_butoane.vc2:358`), care verifica `This.lactiv4`.
- Tokenul "1" nu e folosit de `frm_facturi` (fara `cbuton1`) - liber pentru o semnificatie noua
daca s-ar dori, dar mai curat e un token nou (ex. "5").
**Sursa lui `gcAcces`**: variabila globala PUBLIC (comentariul `*:Global gcAcces`,
`ofacturare_comun.vc2:4770`), NU e setata in codul lui `frm_facturi` sau in procedura care il
deschide (`COMUN\programe\oproceduri_facturare.prg:416, 505` - `Createobject("frm_facturi")`
fara nicio atribuire de `gcAcces` inainte). E populata inainte, la click pe iconita de pe
ecranul-fundal (`ofundal.vc2:69,186,311,391` - `gcAcces = This.coptiuni_active`), unde
`coptiuni_active` per iconita vine din `dezactiveaza_imagini` (`COMUN\programe\acces_meniu.prg:39-80`),
care citeste central din view-ul Oracle `contafin_oracle.vdef_util_obiecte` (interogat in
`citeste_drepturi`, `acces_meniu.prg:17-37`, filtrat pe `id_util`/`id_program`/`id_firma`) si
mapeaza pe cheia iconitei (`cheie`) ultima cifra la un token numeric. Editarea drepturilor per
grup se face prin `PACK_DREPTURI.grupdreptmodproc` (`COMUN\clase\drept_grupuri.vc2:39`, apelat
din `frm_grupuri`).
**Nu am gasit** un catalog central editabil in VFP care sa enumere sensul fiecarui token numeric
per program (ex. un tabel `optiuni_program` cu eticheta "3 = modificare"). Sensul e o conventie
fixata in cod (proprietatile `cbutonN` din fiecare clasa de formular) - vezi intrebarea D2.
### A5. frm_facturi.do_modifica - CORECTIE fata de descrierea din task/plan
**Contrar formularii din plan_06 ("butonul existent din frm_facturi deschide
frm_modifica_articol_factura, care editeaza doar explicatie si taxcode")**, in codul de azi
exista DOUA actiuni distincte de "modificare" pe `frm_facturi`, ambele gateate de acelasi token
"3" (`cbuton3`), dar cu efecte diferite:
1. **`do_modifica`** (`ofacturare_comun.vc2:4381-4480`), legata de `but_modifica1` (butonul din
bara de sus, `Left=609`, fara `caction` explicit -> foloseste default-ul din clasa de baza
`but_modifica` = `caction = inainte_de_do_modifica` -> `This.lactiv3` -> `do_modifica()`).
Deschide **`frm_modifica_factura`** (antet document) si, la `gnButon=1`, ruleaza
`pack_facturare.modifica_date_factura(...)` pe UNA sau MAI MULTE facturi (dupa selectie
multipla `ales=1`) cu campurile: `id_ruta`, `id_delegat`, `id_agent`, `id_masina`,
`dataora_exp`, `id_facturare`, `listare_detaliata`, `text_aditional`, `tip_saft`,
`efactura`(flag intentie trimitere), `data_act`, `data_scad`, `numar_act`, `serie_act`.
**Niciun camp de suma/cantitate/pret.** Contine garda eFactura (A3).
2. **`do_modifica_explicatie`** (`ofacturare_comun.vc2:4482-4499`), legata de `But_modifica2`
(langa grid-ul de detalii, `caction = do_modifica_explicatie` explicit,
`ofacturare_comun.vc2:1433-1441`, tooltip "Modificare explicatie articol"). Deschide
**`frm_modifica_articol_factura`** (`ofacturare_comun.vc2:4959`, caption "Modifica explicatie
articol"), care editeaza DOAR `explicatie` (memo) si `taxcode` (combo SAFT) pe linia curenta
din `crsDetalii`. Garda: doar `poRec.sters = 0` - **fara verificare eFactura**.
Deci descrierea corecta pentru plan: actiunea care deschide `frm_modifica_articol_factura` e
`do_modifica_explicatie` (nu `do_modifica`), iar niciuna din cele doua actiuni existente nu
atinge sume/cantitati - confirma nevoia unei actiuni noi (S1), dar sablonul de clonat pentru
garzi ramane `do_sterge`, nu vreuna din cele doua `do_modifica*`.
### A6. afisjurcom.do_modifica - COMUN\clase\comun.vc2:2222-2563
Clasa `afisjurcom` (extinde `_frmbase`). Pasi:
1. `2230-2232`: `If !Thisform.lactiv3 Then Return` (acelasi mecanism de drept ca A4).
2. `2238-2240`: garda luna inchisa (`glLunaInchisa`).
3. `2242-2258`: determina daca se arata si randurile sterse (`lleSters`, dupa filtrul curent),
citeste `cod`/`an`/`luna`/`id_set`/`sters`/`id_fact`/`id_factd` din `actjur`.
4. `2265-2268`: garda luna curenta - **acelasi tipar** ca in `do_sterge`:
`(pnAn*12)+pnLuna <> (gnAn*12)+gnLuna` -> mesaj -> `Return`.
5. `2278-2281`: garda suplimentara - `id_set` intre 30000-30009 (note din ROAPRODUCTIE) ->
blocate necontional.
6. `2313-2332`: inchide cursoarele reziduale `actactan`/`tact`/`rul_temp`/`trul`/
`rul_temp_obinv`/`trul_obinv` daca sunt deschise.
7. `2352-2368`: incarca `vact_tot` in `actactan` -> `tact` (READWRITE), filtrat
`sters=0 and an=gnAn and luna=gnLuna and cod=lnCod` (daca nu se arata stersele) sau fara
filtrul de sters, ORDER BY `id_act`.
8. `2370-2427`: daca succes, incarca similar `vrul_tot` -> `rul_temp`/`trul` si
`vrul_obinv_tot` -> `rul_temp_obinv`/`trul_obinv`, cu recalcul de `valoare`/`valtva`/
`valoarev`/`valtvav` pe randurile goale (2383-2387, 2412-2416) inainte de a construi
`trul`/`trul_obinv`.
9. `2429-2442`: alege clasa de formular dupa an (`gnAn >= gnAnFormNou` implicit 2007) ->
**`frm_modific2024`** (`Createobject([frm_modific2024], lnIdSet)`) sau varianta veche
`frm_modific`; `Select tact` inainte de `Omodif.Show()`.
10. `2444-2538`: daca `buton=1`, deschide tranzactie manuala (`do_deschide_tranzactie`),
`oscrie_in_fisiere(2,.T.,llRul)`, reconstruieste `actactan`/`RUL_TEMP`/`RUL_TEMP_OBINV` din
`tact`/`trul`/`trul_obinv` cu `id_util`/`sters=0`, apoi `oscrie_in_fisiere(0,.T.,llRul)`,
apoi **`pack_contafin.finalizeaza_modificare_nota(pnLuna,pnAn,pdDataOra,lnIdSet,lnCod,
lnIdFact,lnIdfactd,gnIdUtil)`** (2484-2487), `do_inchide_tranzactie` si `do_cauta` la final.
11. Cod comentat (2496-2513, dezactivat) arata o incercare anterioara de a apela direct
`pack_facturare.actualizeaza_vanzari` din client dupa `finalizeaza_modificare_nota` - azi
e mort, apelul real se face DOAR server-side, in interiorul lui
`finalizeaza_modificare_nota` (confirma faptul deja stabilit in `progres.md`).
12. `llVanzari` e declarata (`Store .F.`, 2235) dar logica ei de activare e tot comentata
(2292-2307) - variabila ramane mereu `.F.`, deci sincronizarea cu `VANZARI` e complet
transparenta pentru `afisjurcom`, indiferent de tipul documentului.
### A7. frm_modific2024 - COMUN\clase\omodificari.vc2:6375-...
Clasa (`DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"`) incepe la linia 6375.
Metodele proprii merg de la `Activate` (12238) pana la ultimul handler de grid
(`pgfArticole.PAGE2.grdRulajeObinv.Init`, 15422-15424) - interval `12238-15424`, usor deplasat
fata de planul vechi (`12200-15319`).
**Contract de intrare** (`Init`, `13551-13660`):
```
Lparameters tnIdSet, tlNotaNoua, toBackupXML, toSet, tlVizualizare
```
- `tnIdSet`: id-ul setului de nota (obligatoriu, stocat in `This.nid_set`).
- `tlNotaNoua`: `.T.` daca vine din nota fara predefinire.
- `toBackupXML`, `toSet`: obiecte optionale (backup XML, respectiv setul de editare
restrictionata "doar Salveaza/Renunta" - `This.lEditare`).
- `tlVizualizare`: parametru opus, numeric sau logic - `1`/`.T.`=vizualizare, `2`=modificare
(default), `3`=verificare note (`13576-13591`).
- **Nu primeste cursoare ca parametru.** Formularul se leaga la aliasul curent `tact` (setat de
apelant cu `Select tact` inainte de `Createobject`) - grid-ul principal `Grid1` are
`RecordSource` legat implicit pe `tact` (conventie mostenita, nu vazuta explicit in Init, dar
confirmata de apelul din A6 pas 9). Grid-urile din pageframe au `RecordSource` FIX in
definitia clasei: `pgfArticole.PAGE1.grdRulaje.RecordSource = "trul"`
(`omodificari.vc2:8669`) si (dupa acelasi tipar, de verificat direct) `grdRulajeObinv` pe
`trul_obinv`. **Deci apelantul trebuie sa aiba deschise, cu exact aceste nume de alias,
cursoarele `tact`/`trul`/`trul_obinv` READWRITE inainte de instantiere** - exact ce face A6
pas 7-8.
- **Iesire**: `do_termin` nu e suprascrisa in `frm_modific2024` - foloseste default-ul din
`_frmbase` (`_frm_base.vc2:363-376`, seteaza `gnButon=1`/`Buton=1` si inchide/ascunde), dar
trece prin `inainte_de_do_termin` proprie, foarte lunga (`13357-13549`, ~192 linii) - acolo e
validarea grea (verificari de total, TVA exigibil etc.) inainte sa lase `buton=1`. **Orice
validare noua legata de sume factura trebuie sa intre in acest lant**, nu doar in `do_salvare`.
- **La iesire cu `buton=1`, cursoarele `tact`/`trul`/`trul_obinv` raman deschise** (formularul nu
le inchide) - apelantul (A6 pas 10) le reciteste in `actactan`/`RUL_TEMP`/`RUL_TEMP_OBINV`
dupa `Show()`.
**Pageframe existent** (`pgfArticole`, `omodificari.vc2:8627-8642`, doar 2 pagini azi):
```
PAGE1.Caption = "Rulaje materii prime, materiale, marfuri, obiecte inventar (303)" (grid grdRulaje pe trul)
PAGE2.Caption = "Rulaje obiecte inventar in folosinta (8039)" (grid grdRulajeObinv pe trul_obinv)
```
Nu exista azi PAGE3 - de adaugat pentru S4.
### A8. Butonul/actiunea in bara formularului si modelul de adaugare
Modelul concret (`But_modifica2`, `ofacturare_comun.vc2:1433-1441`):
```
ADD OBJECT 'But_modifica2' AS but_modifica WITH ;
Anchor = 12, ;
caction = do_modifica_explicatie, ;
Caption = "", ;
Left = 710, ;
Name = "But_modifica2", ;
TabIndex = 27, ;
ToolTipText = "Modificare explicatie articol", ;
Top = 341
```
Dispatch generic: `Click` din clasa de baza a butoanelor (`_cmd_base.vc2:41-...` si a doua
implementare la `120-...`) citeste `This.cAction` si il executa pe `Thisform` (cu
`This.clistaparametri` optional ca argument). Deci un buton nou nu are nevoie de propriul
`Click` - doar de `caction = <nume_metoda_pe_thisform>`.
Pentru o actiune noua gateata de drept (ca `but_modifica1`, nu ca `But_modifica2`):
1. Adauga metoda `do_editare_sume` (sau numele ales) pe `frm_facturi`.
2. Adauga `ADD OBJECT 'But_editare_sume1' AS but_modifica WITH ... caption/picture/tooltip/
pozitie ...` (poate mosteni orice clasa vizuala din `cmd_butoane.vcx`, nu neaparat
`but_modifica`).
3. Daca actiunea trebuie gateata separat de token-ul "3" (modificare antet/explicatie) - decizie
de arhitectura, vezi D1 - adauga `inainte_de_do_editare_sume` proprie care verifica
`This.lactivN` (N = tokenul nou ales, ex. "5"), si seteaza `caction =
inainte_de_do_editare_sume` pe buton (dupa modelul `but_modifica1`, care NU seteaza caption
explicit pe buton ci mosteneste `inainte_de_do_modifica` din `cmd_butoane.vc2:188`).
4. Adauga proprietatea `cbuton5 = But_editare_sume1` pe `frm_facturi` (langa `cbuton2`/`cbuton3`
existente, `ofacturare_comun.vc2:1352-1353`) ca butonul sa fie ascuns automat cand tokenul
"5" lipseste din `gcAcces` (mecanismul din A4).
5. Vezi `COMUN\docs\conventie_ux_formulare.md` pentru pozitionare/anchor in bara existenta.
## B. Deosebiri de fond fata de plan
1. **Garda eFactura NU e in `do_sterge`, e in `do_modifica`** (A3). Planul o citeaza gresit ca
parte a sablonului `do_sterge` ("Garda eFactura, de refolosit: `ofacturare_comun.vc2:4428-4432`"
sub titlul despre `do_sterge`). Practic nu schimba directia (garda tot exista si e
refolosibila), dar sursa corecta de citat si tiparul de extras (azi e un simplu `If`, nu un
`Return` cu mesaj ca restul garzilor) trebuie corectate in implementare.
2. **`frm_facturi.do_modifica` NU deschide `frm_modifica_articol_factura`** (A5). Planul (si
textul din task) atribuie asta lui `do_modifica`; in realitate `do_modifica` deschide
`frm_modifica_factura` (antet, alte campuri), iar `frm_modifica_articol_factura` (explicatie+
taxcode) e deschis de `do_modifica_explicatie`, legata de `But_modifica2`. Nu schimba
concluzia planului (niciuna din cele doua nu atinge sume), dar numele metodei/formularului de
citat in orice implementare viitoare trebuie sa fie cel corect.
3. **Drepturile pe `frm_facturi` nu sunt "lactiv3/lactiv4 + tokeni in gcAcces" ca fapt
autonom al formularului** - sunt mecanismul GENERIC din `_frm_base.actualizeaza_drepturi`
(A4), aplicat oricarui formular care extinde `_frmbase`. `frm_facturi` doar declara ce
inseamna fiecare token pentru el (`cbuton2`, `cbuton3`) si manipuleaza direct `gcAcces`/
vizibilitatea pentru cazul special "luna inchisa" (`Init`, 4770-4773). Nu exista o lista
centrala DB-editabila a semnificatiei tokenilor (vezi D2) - planul nu gresea factual, dar
ii lipsea acest nivel de detaliu, relevant pentru cum se inregistreaza un token nou.
4. Restul ancorelor (A1, A2, A6, A7) confirma planul, doar cu liniile deplasate de commit-urile
#7/#8 - nicio diferenta de fond.
## C. Propunerea de implementare S1-S3
### Arhitectura: unde se pune ce
Decizia lui Marius (progres.md, punctul 5) cere ca garzile sa se aplice pe AMBELE puncte de
intrare (`frm_facturi` din ROAFACTURARE si `afisjurcom` din ROACONT/ROAGEST). Azi, garzile
"luna inchisa" si "luna curenta" **exista deja si independent** in ambele clase
(`do_sterge`/A1 respectiv `do_modifica`/A6) - fiecare punct de intrare are propria lor copie,
pattern deja folosit in cod (nu e o incalcare noua sa le duplic). Garda "referinte
incasari/plati" si garda "eFactura" insa **exista azi doar in `frm_facturi`** (ROAFACTURARE) -
`afisjurcom.do_modifica` nu le are deloc.
Recomandare:
- **`ReferinteDocumenteNota`** (`COMUN\programe\odocumente.prg:8`) e deja in `COMUN`, deci
reutilizabila ca atare din `afisjurcom.do_modifica` fara nicio mutare de cod - se apeleaza cu
aceiasi parametri (`an`, `luna`, `cod`), doar ca `afisjurcom` trebuie sa stie cand documentul
curent e o factura (vezi mai jos).
- **Garda eFactura** foloseste `poRec.id_fact` - `afisjurcom` are deja `lnIdFact`/`lnIdfactd`
(A6 pas 3) din `actjur`, deci parametrul exista, doar interogarea (azi inline in
`do_modifica` a lui `frm_facturi`) trebuie extrasa intr-o functie mica in `COMUN\programe\`
(ex. `EsteInEFactura(tnIdFact)`) ca sa fie apelabila din ambele clase fara duplicare literala
a SQL-ului.
- Cazul "documentul curent e o factura de vanzare" trebuie detectat in ambele puncte de intrare
(nu doar in `frm_facturi`, care STIE deja ca lucreaza cu facturi) - pentru `afisjurcom`
inseamna un test suplimentar (ex. `id_set` intre valorile care corespund facturarii, sau
existenta unui rand in `vanzari` cu acel `cod`) inainte de a aplica garda eFactura/referinte -
pe alte tipuri de note aceste garzi nu au sens si nu trebuie sa apara.
- **Cel mai simplu 80/20**: o singura functie noua in `COMUN\programe\` (langa
`odocumente.prg` sau intr-un fisier nou `ofacturare_editare.prg`), ex.
`VerificaEditareFactura(tnCod, tnAn, tnLuna, tnIdFact)`, care ruleaza toate garzile
aplicabile facturii (eFactura + referinte; luna inchisa/curenta raman ca azi, duplicate local,
pentru ca deja exista identic in ambele clase) si intoarce `.T./.F.` + mesajul de eroare deja
afisat. Apelata din `frm_facturi` (actiune noua, S1) SI din `afisjurcom.do_modifica` (adaugare
minima, cateva linii), cu un test prealabil "e factura?" facut de fiecare apelant dupa
contextul lui.
### S1 - Actiunea noua in frm_facturi
- Metoda noua `do_editare_sume` (nume de discutat) pe `frm_facturi`
(`COMUN\clase\ofacturare_comun.vc2`), clonata dupa scheletul de garzi din `do_sterge`
(A1 pasii 1-7), dar FARA ramurile de stergere efectiva (pasii 8-12) - se opreste dupa garzi si
preda la S2/S3.
- Buton nou dupa modelul A8, cu `caption = do_editare_sume` (sau `inainte_de_do_editare_sume`
daca se doreste gating explicit prin `lactivN`), token nou in `gcAcces` (propun "5", primul
liber - A4) + `cbuton5` pe `frm_facturi`.
- Semnatura: fara parametri (citeste contextul din `crsfacturi`/pozitia curenta, ca `do_sterge`).
### S2 - Incarcarea cursoarelor (COMUN, refolosibila)
Extrage pasii 7-8 din A6 (incarcarea `vact_tot`/`vrul_tot`/`vrul_obinv_tot` in
`tact`/`trul`/`trul_obinv`, filtrate pe `cod`+`an`+`luna`) intr-o procedura comuna, ex.
`IncarcaCursoareModificareNota(tnCod, tnAn, tnLuna, tlAratasterse)` in `COMUN\programe\`, apelata
identic din `afisjurcom.do_modifica` (inlocuind codul inline de azi, refactorizare minima) si din
noua actiune din `frm_facturi`. Asta e singura cale sa se garanteze ca cele doua puncte de
intrare incarca EXACT acelasi lucru, cerinta explicita a lui Marius.
### S3 - Deschiderea frm_modific2024 (cod apelant ~40 linii)
Schita (in `frm_facturi.do_editare_sume`, dupa ce S1 a validat garzile si S2 a incarcat
cursoarele):
```foxpro
PROCEDURE do_editare_sume
* garzi S1 (eFactura, referinte, luna inchisa/curenta) - vezi A1, A3
...
Local lnCod, pnAn, pnLuna, lnIdSet, lnIdFact, lnIdFactD
* citeste cod/an/luna/id_set/id_fact/id_factd din crsfacturi, ca in A1 pas 3
If !IncarcaCursoareModificareNota(lnCod, pnAn, pnLuna, .F.) && S2, COMUN
Return
Endif
If Reccount('actactan') = 0
amessagebox("Nu exista nota contabila pentru aceasta factura.",0+48,"Atentie")
Return
Endif
Select tact
Local Omodif
Omodif = Createobject([frm_modific2024], lnIdSet)
Omodif.Show()
If Omodif.gnButon = 1 && sau variabila globala Buton, ca in A6 pas 10
If Thisform.do_deschide_tranzactie()
lnSucces = OSCRIE_IN_FISIERE(2,.T.,.T.)
If lnSucces > 0
* reconstruieste actactan/RUL_TEMP/RUL_TEMP_OBINV din tact/trul/trul_obinv, ca in A6
...
lnSucces = OSCRIE_IN_FISIERE(0,.T.,.T.)
Endif
If lnSucces > 0
lcSql = [begin pack_contafin.finalizeaza_modificare_nota(...); end;] && A6 pas 10
lnSucces = Iif(goExecutor.oExecuta(lcSql),1,-1)
Endif
Thisform.do_inchide_tranzactie(Iif(lnSucces<0,2,1))
If lnSucces > 0
Thisform.do_cauta()
Endif
Endif
Endif
* inchide actactan/rul_temp/rul_temp_obinv/tact/trul/trul_obinv
ENDPROC
```
Notă: `do_deschide_tranzactie`/`do_inchide_tranzactie` exista deja pe `_frmbase`
(`_frm_base.vc2:252-265` si un omolog de inchidere, de verificat numele exact la implementare -
`afisjurcom` il foloseste direct, A6 pas 10) - de reutilizat, nu de reprodus manual ca in
`do_sterge` (care foloseste `SQLSetprop` direct, tipar mai vechi).
### Fisiere atinse (estimare S1-S3)
| Fisier | Proiect | Ce se schimba |
|---|---|---|
| `COMUN\clase\ofacturare_comun.vc2` | COMUN (cross-project) | metoda noua `do_editare_sume` + buton nou pe `frm_facturi`, token nou in `cbuton*` |
| `COMUN\clase\comun.vc2` | COMUN (cross-project) | `afisjurcom.do_modifica` - apel la garda noua + la `IncarcaCursoareModificareNota` (inlocuind codul inline) |
| `COMUN\programe\odocumente.prg` sau fisier nou `COMUN\programe\ofacturare_editare.prg` | COMUN (cross-project) | functiile comune noi: garda eFactura extrasa, `IncarcaCursoareModificareNota` |
| `COMUN\clase\omodificari.vc2` | COMUN (cross-project) | NEATINS in S1-S3 (S4 adauga PAGE3) |
Orice modificare in `COMUN\clase\comun.vc2` (`afisjurcom`) afecteaza registrul jurnal din TOATE
produsele ROA care il folosesc (ROACONT, ROAGEST, posibil altele) - de tratat cu maxima grija si
testat separat de `frm_facturi`.
## D. Intrebari deschise
1. **Ce token numeric folosim pentru dreptul nou** si daca trebuie sa fie distinct de tokenul
"3" (modificare) existent, sau daca e acceptabil ca cine are drept de "modificare" (token 3)
sa capete automat si dreptul de editare sume. Propunere: token separat (ex. "5"), pentru ca
editarea sumelor are impact contabil mult mai mare decat editarea campurilor de antet/
explicatie - un utilizator ar trebui sa primeasca acest drept explicit, nu implicit prin
dreptul existent.
2. **Cum se inregistreaza practic un token nou in sistemul de drepturi** ca un administrator sa-l
poata acorda per grup din `frm_grupuri` (`COMUN\clase\drept_grupuri.vc2`). Am gasit
mecanismul tehnic (`gcAcces` -> `lactivN`/`cbutonN`, populat prin `vdef_util_obiecte` +
`PACK_DREPTURI.grupdreptmodproc`), dar nu am gasit un catalog editabil al semnificatiei
tokenilor per program - posibil sa fie o eticheta hardcodata undeva neindexat inca in cache-ul
text, sau sa fie nevoie de un rand nou in Oracle. De clarificat inainte de S1, altfel tokenul
nou risca sa fie "orfan" (functioneaza in cod dar nimeni nu-l poate acorda din UI).
3. **Cum se determina in `afisjurcom` ca documentul curent e o factura de vanzare**, ca sa aplice
garda eFactura/referinte doar atunci (S4 foloseste acelasi test pentru afisarea PAGE3). Optiuni:
test pe `id_set` (interval cunoscut pentru facturare) sau pe existenta unui rand in `vanzari`
cu `cod`-ul curent. A doua varianta e mai robusta (nu depinde de conventia de `id_set`) dar
costa un SELECT suplimentar la fiecare deschidere - de decis cu Marius pragul de cost acceptat.
4. ~~Numele exact al metodelor de tranzactie pe `_frmbase`~~ - rezolvat in cercetare:
`do_deschide_tranzactie` (`_frm_base.vc2:252-265`) si `do_inchide_tranzactie`
(`_frm_base.vc2:279`) exista amandoua pe `_frmbase`, deci reutilizabile ca atare in S3.

View File

@@ -147,7 +147,7 @@ fara pas de write-back binar.
Neatinse (interzise): `COMUN\clase\omodificari.vc2`, `COMUN\clase\ofacturare_comun.vc2`.
**Fara commit** — diff-ul: `docs\diff_s4_apelanti_frm_modific2024.patch` (2 sectiuni: `COMUN` din
**Fara commit** — diff-ul: diff aplicat (sters) (2 sectiuni: `COMUN` din
`comun.git`, `ROAGEST\Programe\roagest.prg` din `roagest.git`).
## Ce ramane pentru decizia lui Marius

View File

@@ -1,221 +0,0 @@
# S4 — doua defecte pe pagina de articole: culoarea liniei sterse + valuta liniilor noi (09.08.2026)
Doua defecte raportate dupa livrarea sub-blocului B (stergere + adaugare de linii). Ambele in
`COMUN\clase\omodificari.vc2` (`frm_modific2024`, `pgfArticole.PAGE3`); al doilea atinge si
`COMUN\programe\ofacturare_editare.prg`. **Ambele REZOLVATE, dovedite, scrise in binar,
necomise.**
## Defectul 1 — marcajul vizual `DynamicForeColor` nu se aplica pe linia stearsa
### Cauza reala (nu ipoteza de start, confirmata pe cod)
`grdArticoleFactura` e definit ca `ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura' AS _grdrow`
(`omodificari.vc2:12306`), unde `_grdrow` (`COMUN\clase\_grd_base.vc2:445-489`) e o clasa a suitei
comune (nu proprietatea acestei livrari — doar citita) care evidentiaza linia curenta a gridului:
```
PROCEDURE Init
DoDefault()
If This.nRgbrow = 1
...
This.SetAll("DynamicForeColor","iif(RECNO() = This.nRecno,RGB(" + This.cRGB_Font + "),RGB(0,0,0))","Column")
Endif
ENDPROC
```
`nrgbrow` implicit e `1`. La instantiere, dupa ce `PropValue`-urile clasei (inclusiv
`Column1..14.DynamicForeColor = "IIF(tvd.sters=1,RGB(150,150,150),RGB(0,0,0))"`) sunt aplicate,
`Init` ruleaza si **`SetAll` suprascrie necondiționat** `DynamicForeColor` pe toate cele 14
coloane cu o expresie care ignora `tvd.sters` complet — de-asta linia stearsa avea pixeli negri
puri (0,0,0), nu gri (150,150,150): codul din clasa era corect, dar era deja inlocuit inainte de
primul `Refresh()`.
Ipoteza de start din briefing ("`_grdrow.Init` castiga in fata lui `DynamicForeColor`") s-a
confirmat exact, cu mecanismul precis identificat (`SetAll` in `Init`, nu doar `AfterRowColChange`).
### De ce nu solutia gridurilor surori
`grdRulaje`/`grdRulajeObinv` (`pgfArticole.PAGE1`/`PAGE2`) rezolva coliziunea cu `Init` **gol**
(`*Nu sterge`, `omodificari.vc2:~15659`/`~15926`) — asta taie tot lantul `DoDefault()`, deci si
`_grid.Init()` (cel care seteaza `ReadOnly` pe coloanele text dupa `lcamptextneeditabil`).
`grdArticoleFactura` are nevoie sa ramana editabil pe `cantitate`/`pret`/`pret_cu_tva`
(`lcamptextneeditabil=.F.`, fix din sesiunea anterioara) — un `Init` gol ar fi rupt din nou
editabilitatea.
### Fix
O singura proprietate pe `ADD OBJECT`-ul gridului (`omodificari.vc2:12317`):
```
nrgbrow = 0, ;
```
`nrgbrow=0` scurt-circuiteaza intreg blocul `If This.nRgbrow = 1` din `_grdrow.Init` (deci si
`SetAll`) **fara sa taie** `DoDefault()` -> `_grid.Init()` — editabilitatea ramane intacta.
Tiparul e deja folosit in **20+ griduri** din suita comuna (`COMUN\clase\configurare.vc2`,
`COMUN\clase\onomenclatoare.vc2`), deci nu e o solutie inventata pentru acest caz — e conventia
existenta pentru "grid cu culoare proprie pe randuri, fara evidentierea implicita a liniei
curente".
### Dovada — esantionare de pixeli, nu vizual
Doua capturi noi, sub `vfp_ui_harness.ps1 -SyncDir` explicit (capcana de sincronizare deja
rezolvata in sesiunea precedenta):
- `COMUN\utile\Teste\editare_factura\screenshots_after_fix_culoare\step_0_contrast_gri_vs_negru.png`
— document cu 4 linii (`cod=1140895`/`id_vanzare=1050`), linia 2 marcata stearsa prin
`cmdStergeArticol.Click()`, linia curenta a gridului mutata pe linia 3 (`GO 3` +
`loGrid.SetFocus()`) ca selectia (fundal albastru) sa nu acopere nici linia stearsa, nici o
linie de control. Esantionare cu `System.Drawing.Bitmap.GetPixel` pe banda de text a fiecarei
linii (PowerShell, cautare pixel cu luminanta minima in regiune):
| Linie | Pixel cel mai inchis (RGB) |
|---|---|
| Linia 1 (normala, `sters=0`) | `(0,0,0)` |
| **Linia 2 (STEARSA, `sters=1`)** | **`(150,150,150)`** — exact `RGB(150,150,150)` din `DynamicForeColor` |
| Linia 4 (normala, `sters=0`) | `(0,0,0)` |
- `COMUN\utile\Teste\editare_factura\screenshots_after_fix_culoare\step_0_linia_grizata.png` —
document cu 2 linii (`cod=1139934`/`id_vanzare=882`), aceeasi verificare, acelasi rezultat
(`RGB(150,150,150)` pe linia stearsa).
Capturile "before" (linia stearsa cu pixeli negri puri, dovada defectului inainte de fix), mutate
din sesiunea anterioara: `screenshots_before_fix_culoare\step_0_linia grizata dupa sters.png` +
`step_0_crop_zoom.png`.
### Testat, regresie
`test_ui_sterge_linie.prg` (existent, nemodificat in logica — doar rerulat): **8 PASS / 0 FAIL**,
log complet pana la `REZULTAT`. `test_page3_articole.prg`: **14 PASS / 2 FAIL** (identic cu
baseline, cele 2 FAIL sunt artefactul headless cunoscut de la datoria 7 — `ColumnCount`/`ReadOnly`
nu se materializeaza sub `-A -T`). `test_incarca_vanzare_din_nota.prg`: **5 PASS / 0 FAIL**.
Suita noua `test_ui_culoare_contrast.prg` (dedicata acestui fix, ramane in suita de regresie):
descopera dinamic un document cu minim 3 linii (`DescoperaCazTest('FACTURA_ARTICOLE', ...)`,
nu ancorat pe `cod`), marcheaza a doua linie stearsa, muta linia curenta pe a treia, face captura.
**1 PASS / 0 FAIL** pe asertia functionala (`sters=1` dupa click); dovada vizuala e in captura +
esantionarea de pixeli de mai sus, nu intr-o asertie automata (culoarea nu se poate verifica prin
`EVALUATE` in interiorul testului — eroarea 1929, deja documentata in `rec_s4_runda3b2.md`).
## Defectul 2 — liniile adaugate intrau fortat in RON
### Cauza reala (diferita de formularea initiala din briefing)
Briefingul presupunea ca `AdaugaLinieTvdDinArticol` scrie `tip_valuta = 0` fix — **verificat pe
cod, fals**: `tvd` (structura din `CreeazaCursorArticoleGol`, `ofacturare_editare.prg:268-271`) nu
are deloc un camp `tip_valuta`, `curs` sau `multiplicator` — acele campuri nu exista in view-ul
`VVANZARI_ARTICOLE` (linia stocheaza doar `id_valuta`, o referinta la `nom_valute`, fara factor de
conversie propriu).
Cauza reala e in alta parte: `tip_valuta=0`/`Curs=1`/`multiplicator=1` sunt hardcodate pe
**`poArticol`** in `CreeazaPoArticolNouTvd` (`ofacturare_editare.prg:429-431`), iar
`poDate.in_valuta` e hardcodat `0` in `cmdAdaugaArticol.Click` (`omodificari.vc2:16190`) — asta
tine dialogul `frm_articol_factura` in **modul RON** indiferent de valuta reala a documentului.
Dialogul calculeaza `pretftva`/`pretctva` (campurile RON) pe baza a ce introduce utilizatorul, iar
`AdaugaLinieTvdDinArticol` scria acele valori **neconvertite** in `tvd.pret`/`tvd.discount_unitar`.
Bara de totaluri (`ActualizeazaBaraTotaluri`, decizia 33, `omodificari.vc2:12856-12899`) insumeaza
`tvd.valoare` **brut** (`SUM valoare FOR sters<>1`) si aplica **o singura data**
`tvanz.curs`/`multiplicator` pe suma — asta presupune ca fiecare linie e deja stocata in valuta
documentului, nu in RON. Verificat pe date (schema `MARIUSM_AUTO`):
| `id_vanzare` | `VANZARI.in_valuta` | `VANZARI.id_valuta` | `curs` | linia (`VANZARI_DETALII.pret`) |
|---|---|---|---|---|
| 1037 | 1 | 2 (EURO) | 5.2688 | `pret=200` — 200 EUR brut, nu 200 RON |
O linie noua scrisa in RON (ex. utilizatorul intentioneaza 1053.76 RON) ar fi ramas `pret=1053.76`
in `tvd`, iar bara de totaluri ar fi calculat `1053.76 * 5.2688 = 5551.6` RON — de peste 5 ori
valoarea reala.
### Fix — scopat strict pe stocare, fara sa ating dialogul
`frm_articol_factura`/`ofacturare.vc2` **nu sunt in proprietatea acestei livrari** (partajate cu
tot restul suitei), si a face dialogul sa accepte pret direct in valuta ar cere
`poDate.id_valuta`/`poDate.zi_curs` populate corect (altfel validarea interna a dialogului
respinge la "Terminare" cu mesaj — verificat pe cod, `ofacturare.vc2:9484,9490`) — netestabil
headless (`Show()` e modal) si risc pe o clasa mare, necunoscuta. Fix ales, minim si sigur:
1. **`tvanz` extins** cu `in_valuta`, `id_valuta`, `nume_val` (join nou pe `nom_valute` in
`IncarcaVanzareNota`, `ofacturare_editare.prg:150-176`; `CreeazaCursorTvanzGol` la fel).
2. **`AdaugaLinieTvdDinArticol` (`omodificari.vc2:12901-12934`) converteste** pretul/discountul
calculate de dialog (RON) in valuta documentului, inainte de a le scrie in `tvd`:
`pret = pretRON * tvanz.multiplicator / tvanz.curs` (si simetric pentru `discount_unitar`) —
inversul exact al formulei din bara de totaluri, deci **no-op pe documente RON**
(`curs=multiplicator=1`, verificat neregresat pe suita existenta).
3. **`id_valuta`/`nume_val` ale liniei noi preiau valorile de pe `tvanz`** (`tvanz.id_valuta`,
`tvanz.nume_val`) in loc de `.Null.`/gol — simetric cu liniile existente, care le au populate
din `VVANZARI_ARTICOLE`.
**Limitare ramasa, de raportat explicit**: dialogul **tot lucreaza in RON** — utilizatorul introduce
pretul in RON chiar si pe un document in valuta, iar conversia se face "in spate", la scriere.
STOCAREA e acum corecta valutar (bara de totaluri calculeaza corect regardless de valuta
documentului), dar UX-ul de introducere a pretului direct in valuta nu e implementat — ar cere
atingerea `ofacturare.vc2`, in afara scope-ului primit ("nu era ceruta multi-valuta in briefing" —
decizie mostenita din sub-blocul B partea 2, `rec_s4_runda3b2.md`).
### Testat
- `test_page3_articole.prg`: **14 PASS / 2 FAIL** (identic cu baseline).
- `test_incarca_vanzare_din_nota.prg`: **5 PASS / 0 FAIL**.
- `test_adauga_linie_articol.prg` (existent, caz RON): **20 PASS / 0 FAIL** — confirma ca
conversia e no-op cand `curs=multiplicator=1`, nicio regresie pe calea deja acoperita.
- **Suita noua** `test_adauga_linie_valuta.prg`: foloseste un document real cu articole
(descoperit dinamic, nu ancorat pe `cod`), dar suprascrie manual `tvanz.curs=5.2688`,
`multiplicator=1`, `in_valuta=1`, `id_valuta=2`, `nume_val='EURO'` dupa `Show()` — nu exista in
schema un caz descoperibil simultan "cu articole" si "in valuta reala" (`id_vanzare=1037`, EURO,
are o singura linie, nefolosibila pentru un test de "adaugare langa liniile existente" fara
ambiguitate). Construieste `poArticol` cu `pretftva=1053.76` (echivalentul RON a 200 EUR la
cursul testat) si verifica: **6 PASS / 0 FAIL** —
`tvd.pret` convertit la `200.00`, `id_valuta=2`, `nume_val='EURO'`, `tvd.valoare=200.00`, iar
bara de totaluri creste cu exact `1053.76` RON (echivalentul corect, nu suma bruta).
## Cens de octeti si write-back
Baseline la inceputul sesiunii: `2 aa / 2 e3 / 2 fe`, zero `EF BF BD`. Primul `Edit` pe
`omodificari.vc2` (adaugarea `nrgbrow = 0`) a reencodat tot fisierul, stricand din nou cele doua
linii `Caption = "CTRL+F = Terminare; ESC = Renunțare; CTRL+N = Adăugare; CTRL+D = Ștergere"`
(capcana deja cunoscuta, lovita si in sesiunile precedente) — cens dupa: `6 ef / 6 bf / 6 bd`.
Reparat byte-cu-byte cu Perl (pozitional: octetul 1 din fiecare tripleta `EF BF BD` -> `0xFE`
(ț), octetul 2 -> `0xE3` (ă), octetul 3 -> `0xAA` (Ș), ciclic pe cele 2 linii x 3 caractere).
Cens final, verificat inainte si dupa `txt2vcx.ps1`: **identic cu baseline, `2 aa/2 e3/2 fe`, zero
`EF BF BD`**.
`ofacturare_editare.prg` e ASCII pur (verificat, zero octeti >0x7F) — fara risc de encoding, nu
necesita reparare.
**Fidelity-check trecut din prima incercare** (`txt2vcx.ps1 -AllowComun`, un singur fisier
regenerat) — spre deosebire de sesiunile precedente, nu a fost nevoie sa adopt textul regenerat
din `<staging>\verify\`.
## Fisiere atinse, stare write-back
| Fisier | Stare |
|---|---|
| `COMUN\clase\omodificari.vc2` | Editat (`nrgbrow=0` pe grid + `AdaugaLinieTvdDinArticol` rescrisa), write-back FACUT, fidelity check OK din prima, cens OK |
| `COMUN\clase\omodificari.vcx` / `.VCT` | Scrise, mtime sincron cu `.vc2` (16:59) |
| `COMUN\clase\omodificari.vc2.pre_fix_culoare.bak` | Backup, luat la inceputul sesiunii |
| `COMUN\programe\ofacturare_editare.prg` | Editat (`CreeazaCursorTvanzGol` + `IncarcaVanzareNota` extinse cu valuta documentului, antet rescris), ASCII pur |
| `COMUN\programe\ofacturare_editare.prg.pre_fix_culoare.bak` | Backup, luat la inceputul sesiunii |
| `COMUN\utile\Teste\editare_factura\test_adauga_linie_valuta.prg` | Nou, testat, 6/6 PASS |
| `COMUN\utile\Teste\editare_factura\test_ui_culoare_contrast.prg` | Nou, testat, captura + esantionare pixeli |
| `COMUN\utile\Teste\editare_factura\screenshots_after_fix_culoare\` | Nou — 2 capturi, dovada pe pixeli |
| `COMUN\utile\Teste\editare_factura\screenshots_before_fix_culoare\` | Capturile "before" din sesiunea anterioara, mutate din `screenshots\` ca sa nu se piarda |
| `docs\diff_s4_fix_culoare_valuta.patch` | Nou — `omodificari.vc2` |
| `docs\diff_s4_fix_culoare_valuta_ofacturare_editare.patch` | Nou — `ofacturare_editare.prg` |
| `docs\progres.md` | Actualizat |
**Fara commit** — asteapta review, conform regulii.
## Ce NU e acoperit
1. **Dialogul `frm_articol_factura` tot lucreaza in RON** — utilizatorul introduce pretul in RON
chiar si pe un document in valuta; conversia se aplica la scriere, nu la intrare. A schimba
asta ar cere atingerea `ofacturare.vc2` (`poDate.in_valuta=1` + `id_valuta`/`zi_curs`
populate), in afara proprietatii/scope-ului acestei livrari.
2. **`Show(1)` (dialogul modal chiar deschis)** — netestat automat (netestabil headless), ca in
sesiunile precedente; acoperit doar prin analiza de cod si testare manuala recomandata.
3. **Editarea unei linii existente prin acelasi dialog** (dublu-clic) — ramane nefacuta, in afara
scope-ului primit in aceasta sesiune.
4. **Decizia de arhitectura despre `_grd_base.vc2`**: fixul defectului 1 s-a facut fara sa ating
`_grd_base.vc2` (clasa comuna) — `nrgbrow` era deja o proprietate expusa pentru exact acest caz,
nu a fost nevoie de nicio modificare acolo.

View File

@@ -1,9 +1,9 @@
# S4 runda 1 (PAGE3, doar afisare) — raport de inchidere, 08.08.2026
Runda 1 din S4 (`plan_06_s4_proiectare.md`) e **inchisa**. Diff-ul de review:
`docs\diff_s4_runda1_page3.patch`. Istoricul complet al sesiunii de implementare/depanare:
`docs\cercetare\handoff_s4_runda1.md`, `docs\cercetare\handoff_propr_custom.md`,
`docs\handoff_sesiune_08082026_c.md`.
diff aplicat (sters). Istoricul complet al sesiunii de implementare/depanare:
`docs\cercetare\handoff_s4_runda1.md`, handoff intermediar (sters),
handoff intermediar (sters).
## Ce s-a implementat
@@ -61,7 +61,7 @@ Testul nu atinge Oracle in scriere — doar `SELECT`-uri prin `goExecutor`.
## Blocaje rezolvate in aceasta sesiune (istoric, nu de reluat)
Trei blocaje separate au impiedicat verificarea live inainte de aceasta runda de inchidere, toate
documentate pe larg in `handoff_sesiune_08082026_c.md` si `COMUN\docs\testare-ui-vfp.md`:
documentate pe larg in handoff intermediar (sters) si `COMUN\docs\testare-ui-vfp.md`:
1. `DO ... WITH gnAn, gnLuna` pasa prin referinta si umbrea variabilele in procedurile apelate,
provocand dialogul nativ "View Parameter" pe un `?gnAn` din SQL passthrough — remediat cu

View File

@@ -1,7 +1,7 @@
# S4 runda 2 (PAGE3 "Articole factura") - view VVANZARI_ARTICOLE, pozitionare in tact, garda ROACONT/ROAGEST
Runda 2 pe fisierele deja livrate in runda 1 (`docs\diff_s4_runda1_page3.patch`, netrimis inca la
commit). Diff: `docs\diff_s4_runda2_view_pozitionare.patch` (`COMUN\programe\ofacturare_editare.prg`
Runda 2 pe fisierele deja livrate in runda 1 (diff aplicat (sters), netrimis inca la
commit). Diff: diff aplicat (sters) (`COMUN\programe\ofacturare_editare.prg`
+ `COMUN\clase\omodificari.vc2`, clasa `frm_modific2024`). Fara commit.
## Ce s-a schimbat

View File

@@ -3,7 +3,7 @@
Stare: **stergerea logica e implementata si scrisa in binar**; **adaugarea (dialog
`frm_articol_factura`) NU e implementata** — sub-blocul s-a dovedit prea mare pentru un
singur context si a fost impartit, conform aprobarii din briefing. Cercetarea de contract
pentru adaugare e completa si predata mai jos / in `docs\handoff_s4_runda3b_adaugare.md`,
pentru adaugare e completa si predata mai jos / in handoff intermediar (sters),
ca urmatorul agent sa nu o reia.
## Ce s-a implementat: stergerea logica de linie
@@ -61,7 +61,7 @@ in manifestul clasei (`omodificari.vc2:6660`), cerinta FoxBin2Prg pentru orice c
## Diff
`docs\diff_s4_runda3b_linii.patch` — **scopat strict pe modificarile mele**, nu pe tot ce e
diff aplicat (sters) — **scopat strict pe modificarile mele**, nu pe tot ce e
necomis in `omodificari.vc2` (fisierul are si munca altor agenti din aceeasi zi, inca
necomisa). Reconstruit dintr-un baseline `.pre_runda3b.bak` obtinut prin reversul exact al
celor 4 editari facute (nu am luat backup INAINTE de prima editare — lectie pentru viitor,
@@ -144,7 +144,7 @@ nu blocheaza livrarea sub-blocului, dar merita bifat.
## Ce NU e acoperit (predat mai departe)
- **Adaugarea de linii** (dialog `frm_articol_factura`) — **neinceputa in cod**. Cercetarea
de contract e completa si predata in `docs\handoff_s4_runda3b_adaugare.md`.
de contract e completa si predata in handoff intermediar (sters).
- **Editarea per-linie prin acelasi dialog** (dublu-clic pe o linie existenta) — la fel,
parte din adaugare, nu inceputa.
- **Discountul de antet** (`tvanz`, decizia 17) si **bara de totaluri** — sub-blocul C,
@@ -158,7 +158,7 @@ nu blocheaza livrarea sub-blocului, dar merita bifat.
| `COMUN\clase\omodificari.vcx` / `.VCT` | Scrise, mtime sincron cu `.vc2` |
| `COMUN\clase\omodificari.vc2.pre_runda3b.bak` | Backup reconstruit (baseline pentru diff) |
| `COMUN\utile\Teste\editare_factura\test_ui_sterge_linie.prg` | Nou, testat |
| `docs\diff_s4_runda3b_linii.patch` | Nou, scopat pe sub-blocul B |
| `docs\handoff_s4_runda3b_adaugare.md` | Nou, cercetarea de contract pentru adaugare |
| diff aplicat (sters) | Nou, scopat pe sub-blocul B |
| handoff intermediar (sters) | Nou, cercetarea de contract pentru adaugare |
**Fara commit** — asteapta review, conform regulii.

View File

@@ -1,6 +1,6 @@
# S4 runda 3, sub-blocul B partea 2 — adaugarea de linii + doua goluri, 09.08.2026
Continuarea lui `rec_s4_runda3b.md` (stergerea logica, GATA) si `handoff_s4_runda3b_adaugare.md`
Continuarea lui `rec_s4_runda3b.md` (stergerea logica, GATA) si handoff intermediar (sters)
(cercetarea de contract, predata). Aici: **adaugarea de linii prin dialogul `frm_articol_factura`**,
plus inchiderea celor doua goluri lasate de partea 1.
@@ -165,10 +165,10 @@ interventie, doar asteptare.
| `COMUN\programe\ofacturare_editare.prg` | Editat (functie noua `CreeazaPoArticolNouTvd` + antet), ASCII pur, zero risc de encoding |
| `COMUN\utile\Teste\editare_factura\test_adauga_linie_articol.prg` | Nou, testat, 20/20 PASS |
| `COMUN\utile\Teste\editare_factura\test_ui_sterge_linie.prg` | Modificat (golul #2 + pozitionare pentru captura), testat, 8/8 PASS |
| `docs\diff_s4_runda3b2_adaugare.patch` | Nou — scopat strict pe modificarile mele in `omodificari.vc2` |
| `docs\diff_s4_runda3b2_ofacturare_editare.patch` | Nou — **atentie**: `COMUN` are git propriu, diff-ul e fata de ultimul commit, deci contine si munca altor agenti din aceeasi zi, inca necomisa (linia `CreeazaCursorTvdGol()` -> `CreeazaCursorArticoleGol` in `IncarcaArticoleFactura`, `PregatesteArticoleFacturaEditare` intreaga functie). **Partea mea**: antetul fisierului (rescris) + functia `CreeazaPoArticolNouTvd` intreaga, adaugata la coada fisierului. |
| diff aplicat (sters) | Nou — scopat strict pe modificarile mele in `omodificari.vc2` |
| diff aplicat (sters) | Nou — **atentie**: `COMUN` are git propriu, diff-ul e fata de ultimul commit, deci contine si munca altor agenti din aceeasi zi, inca necomisa (linia `CreeazaCursorTvdGol()` -> `CreeazaCursorArticoleGol` in `IncarcaArticoleFactura`, `PregatesteArticoleFacturaEditare` intreaga functie). **Partea mea**: antetul fisierului (rescris) + functia `CreeazaPoArticolNouTvd` intreaga, adaugata la coada fisierului. |
| `COMUN\utile\Teste\editare_factura\screenshots\step_0_linia grizata dupa sters.png` | Nou — dovada vizuala (revela defectul DynamicForeColor) |
| `docs\handoff_s4_runda3b2.md` | Handoff intermediar scris in timpul asteptarii write-back-ului — poate fi sters, sesiunea s-a incheiat normal |
| handoff intermediar (sters) | Handoff intermediar scris in timpul asteptarii write-back-ului — poate fi sters, sesiunea s-a incheiat normal |
**Fara commit** — asteapta review, conform regulii.

View File

@@ -41,7 +41,7 @@ predat separat, vezi sectiunea "Ce NU e acoperit".
- `tvanz` capata doua coloane noi, `curs N(10,4)` si `multiplicator N(10,4)`, atat in
`CreeazaCursorTvanzGol` (`:145-150`) cat si in `SELECT`-ul din `IncarcaVanzareNota` (`:172-174`) —
necesare pentru conversia RON (decizia 33). Diff izolat (2 linii):
`docs\diff_s4_runda3c_ofacturare_editare.patch`.
diff aplicat (sters).
## Defect gasit si reparat in aceeasi sesiune (nu era in cod inainte)
@@ -126,8 +126,8 @@ PASS in log, pe formular real instantiat, nu simulat) sta in picioare.
## Diff-uri
- `docs\diff_s4_runda3c_totaluri.patch` — `omodificari.vc2` (fata de `.pre_runda3c.bak`).
- `docs\diff_s4_runda3c_ofacturare_editare.patch` — `ofacturare_editare.prg`, izolat (2 linii).
- diff aplicat (sters) — `omodificari.vc2` (fata de `.pre_runda3c.bak`).
- diff aplicat (sters) — `ofacturare_editare.prg`, izolat (2 linii).
**Fara commit.**

View File

@@ -94,7 +94,7 @@ corectie). Nu a fost atins `AdaugaLinieTvdDinArticol` — in afara scopului aces
## Testat
**Regresie, headless, `vfp9.exe -A -T`, watchdog, exit 0, zero dialoguri**, identic cu baseline-ul
de plecare (`docs\handoff_s4_runda3c2.md`):
de plecare (handoff intermediar (sters)):
- `test_page3_articole.prg`: **14 PASS / 2 FAIL** (cele 2 = artefactul headless cunoscut de la
datoria 7, neschimbat).
- `test_incarca_vanzare_din_nota.prg`: **5 PASS / 0 FAIL**.
@@ -146,8 +146,8 @@ documentat mai sus, nu o dovada ca formula e gresita pe restul datelor.
## Diff-uri
- `docs\diff_s4_runda3c2_verdict.patch` — `omodificari.vc2` (fata de `.pre_verdict.bak`).
- `docs\diff_s4_runda3c2_ofacturare_editare.patch` — `ofacturare_editare.prg`, izolat.
- diff aplicat (sters) — `omodificari.vc2` (fata de `.pre_verdict.bak`).
- diff aplicat (sters) — `ofacturare_editare.prg`, izolat.
**Fara commit** (nici git, nici SVN).

View File

@@ -49,7 +49,7 @@ SUM (Nvl(cant,0) + Nvl(cante,0)) * Nvl(pretvtva,0) ;
TO lnTotalRul FOR Nvl(sters,0) = 0 AND Nvl(id_tip_rulaj,0) = 0
```
Diff complet: `docs\diff_s4_runda3c3_decizii_36_37.patch`.
Diff complet: diff aplicat (sters).
## Test actualizat
@@ -67,7 +67,7 @@ Diff complet: `docs\diff_s4_runda3c3_decizii_36_37.patch`.
- pe tip=1 (fara rata), acelasi rand mutat pe `461` NU mai intra — contul ramane strict `4111`,
verificand ca extinderea nu s-a scapat pe tipurile obisnuite de factura.
Diff complet: `docs\diff_s4_runda3c3_test.patch`.
Diff complet: diff aplicat (sters).
## Testat

View File

@@ -1,6 +1,6 @@
# Livrare - decizia 35: intrare directa in valuta la adaugarea de linii
Implementare pe baza cercetarii de contract deja facute (`docs\handoff_decizia35_valuta_dialog.md`):
Implementare pe baza cercetarii de contract deja facute (handoff intermediar (sters)):
premisa initiala (atingerea `ofacturare.vc2`) a fost infirmata acolo - dialogul `frm_articol_factura`
nu citeste `poDate.in_valuta`, ramura de valuta e condusa de `poArticol.tip_valuta`/`Curs`/
`multiplicator`/`nume_val`. Toata lucrarea de mai jos e in apelant, **`ofacturare.vc2` nu a fost atins**.
@@ -70,8 +70,8 @@ write-back necesar.
- `COMUN\programe\ofacturare_editare.prg` (+ `.pre_s4_valuta.bak`)
- `COMUN\clase\omodificari.vc2` (+ `.pre_s4_valuta.bak`), scris in `omodificari.vcx`/`.vct`
- `COMUN\utile\Teste\editare_factura\test_adauga_linie_valuta.prg` (+ `.pre_s4_valuta.bak`)
- Patch-uri: `docs\diff_s4_valuta_dialog.patch`, `docs\diff_s4_valuta_dialog_prg.patch`,
`docs\diff_s4_valuta_dialog_test.patch`
- Patch-uri: diff aplicat (sters), diff aplicat (sters),
diff aplicat (sters)
**Fara commit** (git/SVN). **Zero scrieri in Oracle** - toate testele lucreaza pe cursoare in
memorie.

View File

@@ -1,82 +0,0 @@
# S4b etapa 2 — smoke test headless al dialogului `frm_sincronizare_articole`
Suita nouă: `COMUN\utile\Teste\editare_factura\test_s4b_dialog.prg`, model
`test_s4b_sincronizare.prg` (același folder) — `tvd`/`trul` construite în test cu helperele
`AdaugaTvd`/`AdaugaTrul` (copiate identic), `dummyform` (copiat identic) refolosit ca
`oFormArticole`. Complet headless (`vfp9.exe -A -T`), **fără Oracle**.
**Nu s-a atins `COMUN\clase\omodificari.vc2` sau `COMUN\programe\ofacturare_editare.prg`** — doar
citite, niciun write-back.
## Rezultat
```
REZULTAT: 35 PASS / 0 FAIL
```
Log: `D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_s4b_dialog_log.txt`
Comandă de reproducere:
```
cd "D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura"
"C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe" -A -T test_s4b_dialog.prg
```
Niciun proces `vfp9.exe` rămas viu, verificat cu `tasklist` înainte și după rulare (0 ambele dăți).
## Mediu (fără Oracle, fără `test_init_env_auto`)
Clasa e `OF "_frm_child.vcx"` (`WindowType=1`, modală), dar modalitatea se declanșează la
`.Show()`, nu la `Createobject()` — verificat pe cod (`_frm_child.vc2`/`_frm_base.vc2`, niciun
`.Show(` în lanțul de moștenire) înainte de a scrie testul, ca niciun caz să nu rămână blocat.
Mediul de clase a fost replicat din `Programe\roafacturare.prg` (SET PATH + tot lanțul SET
CLASSLIB, minus procedurile Oracle/`init_program`), plus `SET PROCEDURE TO proceduri_comune.prg`
și `ofacturare_editare.prg` — suficient ca `CreateObject('frm_sincronizare_articole')` să rezolve
lanțul `_frm_child.vcx -> _frm_base.vcx -> _baza.vcx` și controalele `_grdrow`/`_optiongrup`/`_label`.
## Ce s-a testat (cele 7 puncte din brief, toate acoperite)
1. **Instanțiere fără eroare** — 6 instanțe create (T1, T2, T2b, T3, T4, T5, T6), pe seturi diferite
de `tvd`/`trul` (Modificare+Adaugare+Semnalare+N-A, document identic, doar N-A/Semnalare), toate
verificate `Vartype(loForm)=='O'` — PASS pe toate.
2. **`propunere_afisata` identică camp-cu-camp cu `propunere_sincronizare`** (T1) — comparație
completă (`id_articol`, `denumire`, `codmat`, `cantitate_veche/noua`, `pret_vechi/nou`,
`actiune`, `motiv`) prin helper dedicat `VerificaCursoareIdentice`, 0 nepotriviri pe 4 rânduri.
3. **`But_termin1.Enabled`** — `.T.` cu Modificare+Adaugare prezente (T1), `.F.` pe propunere goală
(document identic, T2) și `.F.` pe propunere cu doar N-A/Semnalare (T2b) — ambele variante cerute.
4. **Comutarea direcției** (T3) — `optDirectie.Value=2` + `.Click()` (apel direct de metodă, fără
input real): `propunere_afisata` s-a reumplut la tot 3 rânduri (nu dublat), rolurile s-au
inversat corect (900 Adaugare→Semnalare, 1000 Semnalare→Adaugare, 800 rămas Modificare) —
exact regresia pe care corecția (`rec_s4b_etapa2.md`, punctul 2) o vizează.
5. **`inainte_de_do_termin()`** (T4) — întoarce `.T.`, aplică efectiv în `tvd` (800 modificat
4/16, 900 adăugat ca linie nouă 1/50), `dummyform.nAdaugaCalls==1`, `nBaraCalls>=1`.
6. **`oFormArticole` rămas `.F.`** (T5) — nicio eroare, garda `Vartype(...)=='O'` funcționează,
REPLACE-ul de bază tot se aplică pe `tvd` (4/16) fără `toForm`.
7. **Unload/Release** (T6) — `propunere_afisata` deschisă înainte, închisă după `.Release()`.
Nicio asercțiune pe coloane de grid, lățimi sau `DynamicForeColor` — confirmat inutilizabil sub
`-A -T` (nu a fost nevoie: dialogul se instanțiază fără eroare fatală chiar și fără materializarea
gridului, deci n-a trebuit mutat nimic în harness-ul UI vizibil).
## Zgomot de mediu — NU e defect în clasa nouă
La fiecare `CreateObject`, `ON ERROR` a prins ~20 erori în cascadă în `ACTUALIZEAZA_DREPTURI`
(variabile `gcAcces`, `lcProp`, `lcButoane`, `lcButon`, `lnPf` negăsite) urmate de
`Object GOAPP is not found` în `_frmbase.Init`. Astea vin din codul de bază moștenit
(`_frmbase`/`_baza.vcx`, folosit de **toate** formularele aplicației, nu doar de
`frm_sincronizare_articole`) — gestionarea drepturilor pe butoane, care citește global `gcAcces` și
`goApp`, ambele setate normal la login-ul real în aplicație. Harness-ul acestui test nu face login
(fără Oracle, cum a cerut sarcina), deci aceste globale lipsesc. `frm_sincronizare_articole` **nu
suprascrie** `ACTUALIZEAZA_DREPTURI` — nu are nicio metodă cu acest nume în `omodificari.vc2`.
`ON ERROR` înghite fiecare eroare și continuă linie cu linie (comportament VFP normal la eroare
needivizată), iar `ConstruiesteEnumerare()` din `Init` rulează *după* `DoDefault()` și suprascrie
explicit `But_termin1.Enabled` — de-aia toate cele 35 de asercțiuni ies corect în ciuda zgomotului.
Nu e raportat ca defect (nu ține de clasa nouă), doar semnalat ca limitare de mediu a harness-ului
fără Oracle.
## Ce nu s-a putut testa
Nimic din cele 7 puncte cerute nu a fost blocat. Netestat (în afara scopului acestei sarcini):
comportamentul vizual real al gridului (coloane/culori — cere harness UI vizibil, nu a fost necesar
aici) și `.Show()` modal (deliberat neatins, ca să nu rămână vreun `vfp9.exe` blocat pe un dialog
modal fără input real).

View File

@@ -1,214 +0,0 @@
# S4b - documente reale cu divergenta (pentru testarea pe ecran a dialogului nou)
Cercetare read-only pe `MARIUSM_AUTO`. Niciun `INSERT`/`UPDATE`/`DELETE`, niciun `COMMIT`. Doar
`SELECT` prin `goExecutor.oExecute` si apeluri directe la `ConstruiestePropunereSincronizare('RUL_SURSA')`
(`COMUN\programe\ofacturare_editare.prg:572`), fara UI, fara scriere in `tvd`/`trul` reale (cursoare
in memorie, aruncate dupa fiecare document). Niciun proces `vfp9.exe` ramas viu la finalul cercetarii
(verificat cu `tasklist`, inainte si dupa fiecare rulare).
## Metoda
1. **Prefiltru SQL aproximativ** (nu verdictul final - doar ca sa nu testez document cu document
toata baza), doua interogari peste `vanzari`/`vrul_tot`/`vvanzari_articole` (sters=0, neproforma):
- **candidati A**: `id_articol` prezent doar in rulaj sau doar in articolele facturii (seturi
diferite, `MINUS` in ambele sensuri) - candidati pentru Adaugare/Semnalare.
- **candidati B**: articole comune la care cantitatea agregata difera (`SUM(cant + IIF(id_tip_rulaj<>3,cante,0))`
din `vrul_tot`, sters exclus, vs `SUM(cantitate)` din `vvanzari_articole`, sters exclus) -
candidati pentru Modificare.
- Reunite fara duplicate: **286 documente candidat** din toata istoria bazei.
2. **Verdictul real**: pentru fiecare din cei 286 candidati, incarcare completa a documentului exact
ca in fluxul de editare (`IncarcaCursoareModificareNota` -> `IncarcaVanzareDinNota` ->
`IncarcaArticoleFactura`), apoi apel direct `ConstruiestePropunereSincronizare('RUL_SURSA')` si
citirea cursorului rezultat. **Toti cei 286 candidati au fost testati** (nu doar un esantion).
3. **Sweep suplimentar, exhaustiv, fara prefiltru**, pe toate documentele din luna/anul curent
(`gnAn/gnLuna = 2026/8`) care au rulaje - 5 documente in total - ca sa acopar si un eventual caz
"doar diferenta de pret, cantitate si set de articole identice", pe care prefiltrul de mai sus
nu-l prinde daca articolul respectiv e singurul din document. Confirmare: aceleasi 2 documente
gasite si de acest sweep exhaustiv (fara documente noi ratate de prefiltru in luna curenta).
Comanda de reprodus (scripturile raman in scratchpad, nu in proiect):
```
"C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe" -A -T "<script>.prg"
```
Scripturi si loguri (in scratchpad-ul acestei sesiuni, nu in `docs/`):
`rec_s4b_finder.prg` / `rec_s4b_finder_log.txt` (cei 286 candidati, toata istoria),
`rec_s4b_finder_luna_curenta.prg` / `_log.txt` (sweep exhaustiv luna curenta),
`rec_s4b_finder_idfix.prg` / `_log.txt` (diagnostic id_articol, mai jos).
## Rezultat
**Din 286 candidati testati cu functia reala, 21 de documente produc cel putin o linie
Modificare/Adaugare.** Niciunul din cele 21 nu combina Modificare **si** Adaugare **si** Semnalare
in acelasi document - cel mai bogat caz gasit are Modificare + doua/trei linii N-A (context, nu
aplicabile). Zero documente cu Semnalare-efectiv-in-cursor au aparut printre cele 21 (Semnalare cere
articol prezent doar in `tvd`, stocat - in datele astea, articolele "doar in tvd" gasite erau toate
nestocate, deci cad pe N-A inaintea verificarii de Semnalare).
**Foarte important pentru testarea pe ecran**: fluxul real de editare (`do_editare_factura` /
`afisjurcom.do_modifica`) accepta la editare **doar documente din luna/anul curent al sesiunii**
(garda `(an*12+luna) = (gnAn*12+gnLuna)`, verificata in `test_s8_matrice_surse.prg`). Azi
(11.08.2026), `gnAn/gnLuna = 2026/8`. Din cele 21 documente cu Modificare/Adaugare, **doar 2 sunt in
luna curenta** - restul de 19 nu se pot deschide acum prin formularul real (ar trebui alt `gnAn/gnLuna`
de sesiune sau alta data de sistem ca sa fie editabile).
### Cele 2 documente editabile ACUM (luna curenta, 2026/8)
**#1 - id_vanzare=1050, cod=1140895, tip=1, id_fact=8009660, an/luna=2026/8** (cel mai bogat dintre
cele doua - 2 linii in propunere)
| id_articol | denumire | codmat | cant_veche | cant_noua | pret_vechi | pret_nou | actiune | motiv |
|---|---|---|---|---|---|---|---|---|
| 3598545102 | ACOPERIRE STILP B IVECO | IV93900901 | 2 | 0 | 121.0100 | 0 | Modificare | |
| 315554536 | ACOPERIRE FAR VOLVO FH12 | 11.00003 | 1 | 2 | 302.5000 | 302.5000 | N-A | Mai multe randuri RUL active pe acelasi articol, verificati manual |
**#2 - id_vanzare=1052, cod=1140921, tip=22 (aviz), id_fact=8009677, an/luna=2026/8**
| id_articol | denumire | codmat | cant_veche | cant_noua | pret_vechi | pret_nou | actiune | motiv |
|---|---|---|---|---|---|---|---|---|
| 3598545102 | ACOPERIRE STILP B IVECO | IV93900901 | 1 | 0 | 23.1100 | 0 | Modificare | |
### Constatare suplimentara, verificata pe date - overflow `id_articol` pe articolul IV93900901
`id_articol` real (din `nom_articole`, verificat cu `select id_articol from nom_articole where
codmat = 'IV93900901'`) = **3598545102** - depaseste limita reprezentabila de campul `id_articol I`
(Integer VFP, 4 octeti, max 2147483647) din cursorul `propunere_sincronizare`
(`CREATE CURSOR propunere_sincronizare (id_articol I, ...)`, `ofacturare_editare.prg:587`). Verificat
direct: `STR(id_articol,15)` pe randul citit din `propunere_sincronizare` dupa
`ConstruiestePropunereSincronizare` tot arata markerul de depasire VFP (`***************`), nu
valoarea - deci valoarea stocata in cursor e trunchiata/deja corupta, nu doar o problema de afisare
in scriptul meu de logare (am verificat cu doua latimi diferite, 15 si 20, acelasi rezultat).
Consecinta verificata in cod (nu doar presupusa): `AplicaSincronizareArticole` citeste
`lnIdArticol = id_articol` direct din `propunere_sincronizare` (linia 790) si il foloseste in
`AplicaModificareTvd`/`AplicaAdaugareTvd`/`AplicaModificareTrul` pentru `LOCATE FOR id_articol =
m.tnIdArticol` pe `tvd`/`trul` (liniile 836, 874, 910) - cursoare unde `id_articol` vine direct din
Oracle, deci pastreaza valoarea reala (3598545102). Cu valoarea din campul `I` deja trunchiata,
`LOCATE` nu are cum sa gaseasca randul corect pe acest articol. Ambele documente editabile acum
(#1 si #2 de mai sus) au randul lor de Modificare exact pe acest articol - deci propunerea s-ar
afisa corect in dialogul nou, dar `AplicaSincronizareArticole` ar putea sa nu scrie efectiv
modificarea pe acest rand quand se apasa "Aplica". Nu am testat efectiv `AplicaSincronizareArticole`
pe date reale (ar fi scriere, chiar daca doar in cursor in memorie, si nu era ceruta cercetarea de
aplicare) - constatarea e din citirea codului + valoarea reala confirmata din Oracle, nu din rulare.
## Alte documente cu Modificare/Adaugare, NU editabile acum (alta luna/an) - pentru context
Cele mai "curate" (fara efectul de trunchiere de mai sus, sau cu cantitate neschimbata si doar pretul
diferit intre doua valori nenule - nu artefact de zero):
**id_vanzare=943, cod=1140122, tip=-3, id_fact=8007141, an/luna=2022/4** - singurul document din cele
21 cu Adaugare (nu Modificare):
| id_articol | denumire | codmat | cant_veche | cant_noua | pret_vechi | pret_nou | actiune | motiv |
|---|---|---|---|---|---|---|---|---|
| (overflow, vezi mai sus) | ADAPTOR | SATACADU1 | 0 | 1 | 0 | 0 | Adaugare | |
**id_vanzare=631, cod=1138622, tip=3, id_fact=8001320, an/luna=2014/1** - singurul caz din toata
cautarea cu Modificare "curata": cantitate **neschimbata** (1->1), doar pretul difera intre doua
valori nenule:
| id_articol | denumire | codmat | cant_veche | cant_noua | pret_vechi | pret_nou | actiune | motiv |
|---|---|---|---|---|---|---|---|---|
| (overflow, vezi mai sus) | ACOPERIRE STILP B IVECO | IV93900901 | 1 | 1 | 24.9200 | 112.1600 | Modificare | |
| 315554536 | ACOPERIRE FAR VOLVO FH12 | 11.00003 | 10 | 20 | 124 | 558 | N-A | Mai multe randuri RUL active pe acelasi articol, verificati manual |
**id_vanzare=953, cod=1140144, tip=23, id_fact=8007201, an/luna=2022/5** si **id_vanzare=887,
cod=1139941, tip=23, id_fact=8006845, an/luna=2021/12** - alt tipar de Modificare curata pe cantitate
(neschimbata), doar pretul difera (articol "COCA COLA 0.33L", fara overflow de id_articol):
| document | id_articol | cant_veche | cant_noua | pret_vechi | pret_nou | actiune |
|---|---|---|---|---|---|---|
| 953 | (overflow diferit, neverificat individual) | 1 | 1 | 11.9000 | 0 | Modificare |
| 887 | (overflow diferit, neverificat individual) | 1 | 1 | 3.5100 | 0 | Modificare |
Restul de 14 documente (id_vanzare 976, 937, 793, 682, 681, 1006, 985, 905, 881, 695, 686, 685, 1013,
1014) urmeaza acelasi tipar predominant: un singur articol RUL cu un rand `id_tip_rulaj=3` (diferenta
de pret) al carui `cant` propriu e 0 - agregarea E.3 exclude `cante` pentru randurile tip 3, deci
`cant_articol`/`val_articol` ies 0, iar propunerea arata "Modificare, cantitate/pret -> 0". E un
rezultat corect al formulei documentate (nu o eroare de interogare), dar nu e un exemplu "tipic" de
sincronizare cantitate/pret - lista completa, cu toate liniile, e in
`rec_s4b_finder_log.txt` (liniile cu `GASIT`).
## Ce nu am gasit / limite ale cautarii
- **Zero documente cu Modificare + Adaugare in acelasi document**, din cei 286 candidati testati
(acoperire 100% pe cele doua euristici de prefiltru).
- **Zero documente cu actiune efectiv Semnalare** in cursorul rezultat, din aceiasi 286.
- Prefiltrul SQL (candidati A/B) **nu garanteaza acoperire completa**: un document la care UN SINGUR
articol difera **doar** prin pret (cantitate identica) si care e si singurul articol divergent din
acel document (fara alt articol cu set/cantitate diferita in acelasi document care sa-l fi adus in
lista de candidati) ar fi ratat de ambele euristici. Nu am facut un scan exhaustiv pe pret peste
toata istoria (ar fi insemnat sute de mii de documente testate cu functia reala, cost prea mare
pentru scopul cercetarii) - doar pe luna curenta (5 documente, exhaustiv, fara ratari).
- Nu am testat `AplicaSincronizareArticole` (scrierea efectiva in `tvd`/`trul` in memorie) pe niciun
document real - cercetarea ceruta a fost doar pentru `ConstruiestePropunereSincronizare`.
## Verificari de siguranta
- Toate interogarile au fost `SELECT` prin `goExecutor.oExecute`; niciun `INSERT`/`UPDATE`/`DELETE`,
niciun `goExecutor.oExecuta` (DML) apelat in aceasta cercetare.
- Niciun `COMMIT`/`ROLLBACK` - nicio tranzactie deschisa (nu s-a apelat `MyDeschideTranzactie`).
- Niciun formular deschis, nicio tasta/click injectat.
- `tasklist` verificat inainte si dupa fiecare rulare `vfp9.exe -A -T`: zero procese `vfp9.exe` ramase
vii la finalul cercetarii.
## Precizia coloanelor identificator
Interogare `ALL_TAB_COLUMNS`, read-only, pe coloanele identificator din cursoarele de editare a
facturii. Script: `rec_s4b_precizie_coloane.prg`, log: `rec_s4b_precizie_coloane_log.txt`.
| tabela/view | coloana | tip Oracle | precizie/scala |
|---|---|---|---|
| VVANZARI_ARTICOLE | ID_VANZARE / ID_VANZARE_DET / ID_ARTICOL / ID_JTVA_COLOANA / ID_VALUTA / ID_VANZARE_SET | NUMBER | 10/0 |
| VVANZARI_ARTICOLE | ID_GESTIUNE | NUMBER | 20/0 |
| VVANZARI_ARTICOLE | TAXCODE | NUMBER | 6/0 |
| VVANZARI_ARTICOLE | STERS | NUMBER | 1/0 |
| NOM_ARTICOLE | ID_ARTICOL | NUMBER | 20/0 |
| VRUL_TOT | ID_ARTICOL / ID_TIP_RULAJ / ID_VALUTA | NUMBER | 10/0 |
| VANZARI_DETALII | ID_VANZARE (MARIUSM_AUTO) / ID_VANZARE_DET / ID_ARTICOL / ID_JTVA_COLOANA / ID_VALUTA / ID_VANZARE_SET | NUMBER | 10/0 |
| VANZARI_DETALII | ID_VANZARE (schema ACN) | NUMBER | 20/0 (alta schema, acelasi nume de tabela) |
| VANZARI_DETALII | ID_GESTIUNE | NUMBER | 20/0 |
**Valoare maxima efectiva in date + randuri care depasesc 2147483647 (max VFP `I`, Integer 4 octeti):**
| coloana | max efectiv | randuri > 2147483647 | total randuri |
|---|---|---|---|
| NOM_ARTICOLE.ID_ARTICOL | 4294511702 | **5795** | 6457 (89.8%) |
| VRUL_TOT.ID_ARTICOL | 4294511700 | **6432** | 10293 (62.5%) |
| VANZARI_DETALII.ID_VANZARE_DET | 1609 | 0 | 1362 |
| VANZARI_DETALII.ID_VANZARE | 1060 | 0 | 1362 |
**Concluzie factuala**: `id_articol` e afectat masiv (nu e un caz izolat) - aproape 9 din 10 articole
din `NOM_ARTICOLE` si peste 6 din 10 randuri din `VRUL_TOT` au `id_articol` peste limita unui camp
VFP `I`. Valorile maxime (4294511700-4294511702) sunt foarte aproape de 2^32 (4294967296), consistent
cu un id generat in intervalul unsigned pe 32 de biti, nu cu o secventa Oracle standard. Precizia
declarata in Oracle (`NUMBER(10)` sau `NUMBER(20)`) e suficienta pentru aceste valori - problema e
strict de partea VFP (campul `I`), nu de precizia coloanei Oracle. `id_vanzare`/`id_vanzare_det`,
in schimb, sunt mici (sub 2000) in datele curente si nu au niciun rand peste limita - nu inseamna
insa ca schema le limiteaza (ambele sunt tot `NUMBER(10)`/`NUMBER(20)` dupa schema, fara CHECK
constraint vizibil aici care sa impuna un plafon sub 2^31).
## Restul campurilor I din tvd
Cursorul `tvd` (`CreeazaCursorArticoleGol`, `ofacturare_editare.prg:276`) mai declara `I` (Integer
VFP, 4 octeti, max 2147483647) pe: `id_gestiune`, `id_valuta`, `id_jtva_coloana`, `taxcode`, `sters`,
`id_vanzare_set` (plus `id_vanzare`/`id_vanzare_det`, deja verificate mai sus - fara depasiri).
Toate cele 6 coloane cerute exista in `VVANZARI_ARTICOLE` sub numele exact. Script:
`rec_s4b_restul_campuri_i.prg`, log: `rec_s4b_restul_campuri_i_log.txt`.
| coloana | sursa | max efectiv | randuri > 2147483647 |
|---|---|---|---|
| ID_GESTIUNE | VVANZARI_ARTICOLE (facturi existente) | 23 | 0 din 1362 |
| ID_GESTIUNE | NOM_GESTIUNI (nomenclator complet, `NUMBER(5,0)`) | 29 | 0 din 28 |
| ID_VALUTA | VVANZARI_ARTICOLE | 3 | 0 din 1362 |
| ID_JTVA_COLOANA | VVANZARI_ARTICOLE | 188 | 0 din 1362 |
| ID_VANZARE_SET | VVANZARI_ARTICOLE | 4 | 0 din 1362 |
| TAXCODE | VVANZARI_ARTICOLE | 310354 | 0 din 1362 |
| STERS | VVANZARI_ARTICOLE | 1 | 0 din 1362 |
**Raspuns la intrebare**: nu, niciunul din aceste 6 campuri nu are, azi, vreo valoare peste
2147483647, si niciunul nu e nici macar apropiat de limita (cel mai mare, `TAXCODE`, e la 310354 -
de ~6900 de ori sub prag). Spre deosebire de `id_articol` (`NUMBER(10)`/`NUMBER(20)` cu valori reale
pana la ~4.29 miliarde), `id_gestiune` are un plafon de schema explicit jos: `NOM_GESTIUNI.ID_GESTIUNE`
e declarata `NUMBER(5,0)` - max teoretic posibil 99999, cu 4-5 ordine de marime sub limita `I`. Nu
exista un risc plauzibil pe termen scurt pentru niciunul din aceste 6 campuri; `id_articol` ramane
singurul camp `I` din `tvd` cu depasire reala confirmata in date.

View File

@@ -1,175 +0,0 @@
# S4b etapa 1 - contractul ConstruiestePropunereSincronizare/AplicaSincronizareArticole
Implementare, nu doar proiectare. Cod nou exclusiv in `COMUN\programe\ofacturare_editare.prg` (dupa
`ScrieArticoleFacturaEditate`). Niciun `.vc2` atins - formularul si dialogul raman etapa 2, a altui
agent. Baza: `docs\propunere_s4b_sincronizare.md` (proiectarea aprobata, punctele 2 si 4) si
`docs\cercetare\rec_suma_act.md` E.3 (formula de agregare RUL, reutilizata neschimbata).
## Functii noi (publice, apelabile din etapa 2)
### `ConstruiestePropunereSincronizare(tcDirectie)`
Parametru: `tcDirectie` - accepta exact doua valori, `'RUL_SURSA'` (rulajul e sursa, actualizeaza
articolele facturii) sau `'ARTICOLE_SURSA'` (articolele sunt sursa, actualizeaza rulajul). Orice alta
valoare (inclusiv goala) cade pe `'RUL_SURSA'` - e implicit-ul recomandat de Marius (`docs\handoff_
punct6_10082026_seara.md`, decizia 4).
Lasa deschis, READWRITE, cursorul `propunere_sincronizare`:
| camp | tip | continut |
|---|---|---|
| `id_articol` | I | cheia de matching (singura comuna intre `trul`/`tvd`) |
| `denumire` | C(100) | preferata din `tvd` daca articolul exista acolo, altfel din `trul` |
| `codmat` | C(30) | idem |
| `cantitate_veche` | N(12,3) | valoarea curenta din cursorul-**tinta** |
| `cantitate_noua` | N(12,3) | valoarea calculata din cursorul-**sursa** |
| `pret_vechi` | N(14,4) | idem, pret unitar **cu TVA** |
| `pret_nou` | N(14,4) | idem |
| `actiune` | C(12) | `Modificare` / `Adaugare` / `Semnalare` / `N-A` |
| `motiv` | C(80) | populat pe `N-A`/`Semnalare`, si pe `Adaugare` in `ARTICOLE_SURSA` |
Articolele **identice** intre sursa si tinta nu apar in cursor (fara zgomot, ca in propunere.md).
Retur logic: `.F.` doar cand `tvd`/`trul` nu sunt ambele deschise la apel (cursorul iese oricum creat,
gol) - restul cazurilor (0 articole, document fara diferente) intorc `.T.` cu cursorul gol sau partial.
**Agregarea**, per `id_articol`, separat pe `trul` si pe `tvd`, doar randuri `Nvl(sters,0)<>1`:
- RUL: `cant_articol = SUM(cant) + SUM(IIF(id_tip_rulaj<>3, cante, 0))`,
`val_articol = SUM(cant*pretvtva) + SUM(IIF(id_tip_rulaj<>3, cante*pretvtva, 0))` (formula E.3
neschimbata), `pret_articol = val_articol/cant_articol`.
- tvd: `cant_articol = SUM(cantitate)`, `val_articol = SUM(valoare)` (coloana `tvd.valoare`, deja
calculata cu TVA la incarcare/editare - **citita, nu recalculata** - `IncarcaArticoleFactura`,
`ofacturare_editare.prg:318-320`, e chiar in acest fisier), `pret_articol = val_articol/cant_articol`.
**Actiune**, in ordinea exacta de verificare (prima conditie adevarata castiga):
1. **Documentul e in valuta** (`tvanz.in_valuta<>0`, cand `tvanz` e deschis cu un rand) -> `N-A` pe
**toate** articolele, indiferent de restul. *Decizie luata in aceasta implementare, nu era in
propunere.md*: conversia RON<->valuta intre `trul.pretvtva` (presupus RON) si `tvd.pret` (in
valuta documentului cand documentul e in valuta) nu a fost verificata pe date reale in bugetul
alocat - mai sigur sa semnalez decat sa scriu o suma gresita. Fara aceasta garda, restul logicii
(agregare, matching, Modificare/Adaugare/Semnalare) e neschimbata pe documente RON.
2. **Mai multe randuri RUL active pe acelasi articol** (`nrand_rul>1`) -> `N-A`, chiar daca agregatul
ar fi identic cu tinta (verificat explicit in test, caz A6: o pereche `id_tip_rulaj=3` a carei sume
egaleaza exact `tvd`, tot N-A) - decizia lui Marius/propunere.md punctul 6, generalizata la ambele
directii (nu doar la aplicare, ca in propunere.md sectiunea 4 - vezi "Diferente fata de propunere"
mai jos).
3. **Articol nestocat** (`tvd.in_stoc=0`, doar cand articolul exista in `tvd`) -> `N-A`.
4. **Doar in sursa** -> `Adaugare`.
5. **Doar in tinta** -> `Semnalare` (niciodata stergere automata).
6. **In ambele, diferit** -> `Modificare`; identic -> nu apare in cursor.
## `AplicaSincronizareArticole(tcDirectie, toForm)`
Parametru nou fata de brief: **`toForm`, opus** (contractul descris mai jos, punctul "Ce ramane pe
seama etapei 2"). Reconstruieste propunerea (apeleaza `ConstruiestePropunereSincronizare` intern -
etapa 2 nu trebuie sa o apeleze separat inainte) si aplica **tot ce nu e `N-A`/`Semnalare`** - deci
`Modificare` + `Adaugare`, decizia lui Marius ("fara selectie pe linie"). **Niciun `INSERT`/`UPDATE`
Oracle** - doar `tvd`/`trul` in memorie.
Retur numeric: cate linii au fost efectiv aplicate (nu cate erau in propunere) - formularul il
foloseste ca sa stie daca sa reactualizeze bara de totaluri/gridul.
- **`RUL_SURSA`**: `Modificare` -> `REPLACE tvd.cantitate/pret/discount_unitar` pe primul rand activ
gasit pe articol, **pastrand `pret_cu_tva` existent pe rand** (pretul propus, mereu cu TVA per E.3,
se converteste la fara-TVA prin `/proc_tvav` daca randul era asa) - decizie luata acum, nu era in
propunere.md (care zicea doar "REPLACE ... pret_cu_tva WITH ..." fara sa spuna cu ce): am ales sa
NU schimb convenția per-rand, ca sa nu inversez brusc semnificatia unei coloane pe care utilizatorul
a vazut-o intr-un fel; `Adaugare` -> `toForm.AdaugaLinieTvdDinArticol()`, cu obiectul construit din
`CreeazaPoArticolNouTvd` (tiparul cerut de brief), suprascris cu cantitate/pret din RUL,
`preturi_cu_tva=1` (linie noua, fara conventie de pastrat), `cont`/`id_gestiune`/`proc_tvav` din
randul RUL al articolului.
- **`ARTICOLE_SURSA`**: `Modificare` -> `REPLACE` doar `cant` sau `cante` (dupa care era deja populat
pe rand - verificat in test, caz C1) si `pretvtva`, pe singurul rand RUL activ (garantat unic, altfel
propunerea a marcat N-A la pasul 2). Nu atinge `id_tip_rulaj`/conturi/campuri derivate
(`valoare`/`tva`/etc.) - raman de recalculat de apelant daca e nevoie, in afara scopului acestei
livrari. `Adaugare` -> **nu se aplica niciodata** (niciun rand RUL nou, decizia din propunere.md
punctul 5.B).
## Ce ramane pe seama etapei 2 - contractul lui `toForm`
Am ales varianta **"primesc obiectul formular ca parametru"**, nu "duplic tiparul separat". Fara
`toForm` (sau un obiect care nu implementeaza metodele), `AplicaSincronizareArticole` tot face
`REPLACE`-ul de baza pe `tvd` pentru `Modificare` (verificat in test, caz B2), dar:
- **nu recalculeaza `tvd.valoare`** (ramane cea veche pana la un recalcul extern);
- **nu cheama `ActualizeazaBaraTotaluri`**;
- **sare complet liniile `Adaugare`** (fara `toForm.AdaugaLinieTvdDinArticol`, nu exista alta cale sa
adauge linia fara sa duplice acel helper).
Deci etapa 2 (butonul/dialogul din PAGE3) **trebuie sa apeleze `AplicaSincronizareArticole(tcDirectie,
Thisform)`**, cu `Thisform` fiind instanta `frm_modific2024` deja incarcata (are ambele metode:
`calculeaza_valori_articol`, `AdaugaLinieTvdDinArticol`). Contractul verificat prin `Pemstatus()`, nu
presupus - un obiect fara aceste metode e tratat exact ca "fara toForm".
## Diferente fata de `propunere_s4b_sincronizare.md` - de confirmat cu Marius/etapa 2
1. **Documentele in valuta sunt N-A pe tot** (mai sus, punctul 1 al ordinii de actiune) - propunere.md
nu mentiona deloc valuta pentru S4b. Scop deliberat restrans: fara o verificare pe un document real
in valuta CU randuri RUL, nu am vrut sa livrez o conversie neverificata. Daca Marius vrea si
documentele in valuta acoperite, e nevoie de o cercetare separata (confirmarea daca `trul.pretvtva`
e RON sau in valuta proprie a randului RUL - `VRUL_TOT` are propriile `CURS`/`ID_VALUTA` per rand,
verificat prin `DESCRIBE`, dar nu s-a confirmat ce inseamna practic pentru `PRETVTVA`).
2. **"Mai multe randuri RUL active" e N-A in ambele directii, la nivelul propunerii** (nu doar la
aplicarea `ARTICOLE_SURSA`, cum sugera propunere.md sectiunea 4) - generalizare ceruta explicit de
briefing-ul acestei sarcini ("niciodata alegere automata a randului", listat ca regula a
`ConstruiestePropunereSincronizare`, nu doar a aplicarii). Efect: pe un document cu perechi
`id_tip_rulaj=3` (diferenta de pret la marfa/produse la pret de vanzare, `rec_suma_act.md` E.1),
articolul respectiv ram**a** mereu N-A, chiar daca suma agregata (E.3) ar fi corecta si identica -
propunerea nu ofera Modificare/Adaugare automata pe acele articole, doar afisare informativa.
3. **`tvd` cu mai multe randuri active pe acelasi articol nu are o garda separata** - `AplicaModificare
Tvd` scrie pe **primul** rand activ gasit. Cazul e rar (articol adaugat de doua ori manual pe
aceeasi factura) si n-a fost cerut explicit in briefing; il semnalez ca limitare cunoscuta, nu l-am
tratat ca sa nu extind scopul peste ce s-a cerut.
## Teste
`COMUN\utile\Teste\editare_factura\test_s4b_sincronizare.prg`, model `test_s5_validari_articole.prg`.
Complet headless, **fara Oracle** - nici `ConstruiestePropunereSincronizare`, nici
`AplicaSincronizareArticole` nu ating `goExecutor`, deci testul nu are nevoie de `test_init_env_auto`/
conexiune - doar `SET PROCEDURE TO ofacturare_editare.prg` si `gnPC` setat manual. `tvd`/`trul` sunt
construite direct in test (helpere `AdaugaTvd`/`AdaugaTrul`); `trul` e o structura minimala (doar
campurile citite de cod), nu cele 218 coloane reale ale `VRUL_TOT`.
Cazuri acoperite (sectiunea A - `ConstruiestePropunereSincronizare`, cate un caz pe ambele directii
unde se aplica): identic (A1), modificare cu valori inversate corect intre directii (A2), doar-in-
sursa/doar-in-tinta -> Adaugare/Semnalare cu roluri schimbate intre directii (A3/A4), articol nestocat
(A5), mai multe randuri RUL active - N-A chiar cand agregatul ar fi identic (A6), randuri `sters`
excluse din agregare pe ambele cursoare (A7), document in valuta -> N-A pe tot (A8), tvd/trul lipsa la
apel (A9). Sectiunea B (`AplicaSincronizareArticole`, `RUL_SURSA`): aplicare completa cu `toForm`
(Modificare + Adaugare, verificate valorile scrise in `tvd` si apelurile pe test-double, semnalare/N-A
neatinse - B1), **fara** `toForm` (Adaugare sarita fara eroare, Modificare tot se aplica - B2),
pastrarea conventiei `pret_cu_tva=0` cu conversia pretului propus (B3). Sectiunea C
(`AplicaSincronizareArticole`, `ARTICOLE_SURSA`): `cant` vs `cante` pastrat dupa care era populat pe
rand, Adaugare niciodata scrisa in `trul` (C1).
`test-double`-ul `dummyform` (definit la finalul fisierului, tipar identic cu `dummyexecutor` din
`test_s5_validari_articole.prg`) oglindeste EXACT formula din `calculeaza_valori_articol`/
`AdaugaLinieTvdDinArticol` - verifica ca `AplicaSincronizareArticole` cheama metodele corecte cu
argumentele corecte, fara sa deschida formularul real sau sa atinga vreun `.vc2`.
**Capcana gasita si reparata in acest bloc**: comparatii `==` intre un camp `Character` de latime
fixa (`actiune`, C(12)) si un literal mai scurt (`'Modificare'`) esueaza mereu din cauza spatiilor de
umplere din dreapta - VFP `==` e comparatie stricta, nu trece prin `SET EXACT`. Aparea atat in codul
de productie (`AplicaSincronizareArticole`, filtrul `SCAN FOR Inlist(actiune,...)` si `DO CASE`), cat
si in asertiunile testului. Reparat cu `Alltrim()` pe partea citita din camp, in ambele fisiere.
**Cifra din log** (`test_s4b_sincronizare_log.txt`, rulare `vfp9.exe -A -T`):
```
REZULTAT: 35 PASS / 0 FAIL
```
Toate testate (headless, cursoare construite in test) - niciun caz "doar analizat static". Nu s-a
verificat pe un document real din Oracle (nu era ceruta si nici necesara pentru logica pura), si nici
comportamentul pe un document real in valuta (vezi punctul 1 din "Diferente fata de propunere" -
scop restrans deliberat).
## Ce lipseste pentru punctul #6 complet (etapa 2, alt agent)
1. Butonul `cmdSincronizeazaArticole` in PAGE3 si toggle-ul de `Enabled` in `Show()`
(`omodificari.vc2`, punctul 1 din propunere.md).
2. Dialogul modal `frm_sincronizare_articole` (radio pe directie, grid needitabil pe
`propunere_sincronizare`, Aplica/Renunta) - punctele 2-3 din propunere.md.
3. Verificarea la salvare (`inainte_de_do_termin`) care ofera enumerarea si permite salvarea mai
departe fara sincronizare - decizia 2 a lui Marius (`docs\handoff_punct6_10082026_seara.md`).
4. Apelul `AplicaSincronizareArticole(tcDirectie, Thisform)` din dialog, la "Aplica", si reactualizarea
gridului/barei de totaluri folosind numarul de linii aplicate intors.

View File

@@ -1,93 +0,0 @@
# S5 — agatarea scrierii de articole in cele doua puncte de intrare
Implementare, 09.08.2026 seara. Atinse: `COMUN\clase\ofacturare_comun.vc2`,
`COMUN\clase\comun.vc2` (+ write-back in binare). Niciun alt fisier atins, niciun commit.
## Ce s-a facut
In ambele metode, imediat dupa `Endif`-ul care inchide apelul
`pack_contafin.finalizeaza_modificare_nota` si inainte de `do_inchide_tranzactie` (tranzactia
manuala e inca deschisa acolo):
- `frm_facturi.do_editare_factura` — `ofacturare_comun.vc2:3828-3830` (intre vechile `:3827`/`:3828`,
deplasate cu +3 linii de insertie).
- `afisjurcom.do_modifica` — `comun.vc2:2491-2493` (intre vechile `:2490`/`:2538`; inserat imediat
dupa `Endif`, inaintea blocului de cod comentat existent, nedeplasat).
Bloc identic in ambele (o singura conditie, fara `Else`, ca sa nu strice `lnSucces` cand garda nu
trece):
```foxpro
If lnSucces > 0 And "OFACTURARE_EDITARE" $ Upper(Set("Procedure")) And Used('tvanz') And Reccount('tvanz') = 1
lnSucces = Iif(ScrieArticoleFacturaEditate(tvanz.id_vanzare), 1, -1)
Endif
```
`ScrieArticoleFacturaEditate` (definita de alt agent in `COMUN\programe\ofacturare_editare.prg:468`,
verificata la momentul scrierii apelului) intoarce logic si include deja pasul de recalcul
(`pack_facturare.recalculeaza_totaluri_vanzari`) — nu mai e nevoie de un apel separat din VFP, cum
sugera o formulare anterioara a planului.
## De ce asa
- `-1`, nu `0`, la esec — garda de commit e `Iif(lnSucces<0,2,1)`.
- Garda pe `"OFACTURARE_EDITARE" $ Upper(Set("Procedure"))` pusa si in `ofacturare_comun.vc2`
(desi acolo `ofacturare_editare.prg` e mereu inregistrat, ROAFACTURARE fiind singurul consumator),
pentru simetrie cu `comun.vc2`, unde e obligatorie (fisierul nu exista in `SET PROCEDURE` pe
ROACONT/ROAGEST).
- `Used('tvanz') And Reccount('tvanz') = 1` inainte de a citi `tvanz.id_vanzare` — formularul e deja
`Release`-uit la acest punct, dar cursorul supravietuieste; fara garda, `tvanz.id_vanzare` ar arunca
eroare de alias daca pagina de articole n-a fost activa.
- Un singur `If` fara `Else`: cand oricare conditie e falsa, blocul se sare complet si `lnSucces`
ramane neschimbat (comportamentul de dinainte de modificare).
## Cens de octeti (inainte / dupa, identic pe caracterele >=0x80)
| Fisier | octeti >0x7F inainte | octeti >0x7F dupa | `EF BF BD` | LF izolat |
|---|---|---|---|---|
| `ofacturare_comun.vc2` | 12 | 12 | 0 | 0 |
| `comun.vc2` | 1 | 1 | 0 | 0 |
Editare facuta byte-safe (PowerShell, round-trip `GetEncoding(1252)`, text nou strict ASCII) —
niciun octet existent atins.
## Write-back
Ambele `txt2vcx.ps1 -AllowComun` — fidelity-check trecut, binare cu mtime nou:
- `ofacturare_comun.vcx`/`.vct` — OK.
- `comun.vcx`/`.vct` — OK (fisier mare, ~330 KB text; write-back a durat >120s, rulat in fundal,
finalizat cu succes).
## Testare
**Testul de garda** (`test_page3_articole.prg`, ultimul caz din suita: scoate
`ofacturare_editare.prg` din `SET PROCEDURE`, verifica `PageCount=2`): **PASS**. Confirma ca in
ROACONT/ROAGEST, unde fisierul nu e inregistrat, blocul nou e complet inert — nu doar prin gardele
proprii, ci si prin faptul ca `ScrieArticoleFacturaEditate` nici nu ar fi rezolvabila acolo.
**Regresie**, rulata 09.08.2026 ~22:46-22:48, sub watchdog (`-AutoDismiss`, exit 0, zero dialoguri
pe toate):
| Suita | Rezultat | Baseline |
|---|---|---|
| `test_page3_articole` | 14 PASS / 2 FAIL | 14/2 (identic — cele 2 sunt artefactul headless cunoscut pe coloanele de grid) |
| `test_incarca_vanzare_din_nota` | 5/0 | 5/0 |
| `test_adauga_linie_articol` | 20/0 | 20/0 |
| `test_adauga_linie_valuta` | 16/0 | 16/0 |
| `test_ui_sterge_linie` | 8/0 | 8/0 |
| `test_verdict_act_rul` | 26/0 | 26/0 |
Toate cifrele identice cu baseline-ul dat — nicio regresie introdusa, nici de modificarea proprie,
nici de lucrarile paralele pe `omodificari.vc2` la ora rularii.
Cifrele s-au numarat din liniile `REZULTAT: N PASS / M FAIL` din fiecare log (`grep -c "PASS"/"FAIL"`
brut supra-numara cu 1, pentru ca linia `REZULTAT` insasi contine ambele cuvinte).
## Ce nu s-a testat
- Scrierea reala in Oracle prin noul apel (tranzactie -> `ScrieArticoleFacturaEditate` ->
`SELECT` de verificare -> rollback/commit) — nu face parte din aceasta livrare, ramane la pasul
de aplicare in `MARIUSM_AUTO` (nepornit inca, per `docs\handoff_s5.md`).
- Fluxul UI complet (click real pe butonul de editare, `frm_modific2024` deschis modal) — testele de
regresie folosesc harnessul headless existent, care nu exercita interactiunea reala de grid
(limitare documentata, nu introdusa aici).

View File

@@ -125,7 +125,7 @@ Se umple din `VVANZARI_ARTICOLE` prin `IncarcaArticoleFactura`
| **`lmodificat` (L)** | calculat, `.F.` la incarcare (`:316`) | — |
| **`valoare` (N 14,2)** | calculat la incarcare (`:316-319`) si recalculat la fiecare editare | nu (`Column14.ReadOnly = .T.`) |
Definitia view-ului: `docs\cercetare\ff_view_articole_vanzare.sql` (21 de coloane, valori brute,
Definitia view-ului: `COMUN\docs\cercetare\ff_view_articole_vanzare.sql` (21 de coloane, valori brute,
fara conversie valutara; filtrul `STERS` lasat pe seama apelantului).
**Doar 3 coloane sunt editabile: `cantitate`, `pret`, `pret_cu_tva`.** Tot restul e read-only in

View File

@@ -3,7 +3,7 @@
Inchide cele doua goluri declarate de `docs\cercetare\rec_s5_scriere_reala.md`, sectiunea
„Ce NU acopera testul". Suita: `COMUN\utile\Teste\editare_factura\test_s5_discount_valuta.prg`.
Log: `COMUN\utile\Teste\editare_factura\test_s5_discount_valuta_log.txt` (rulare 10.08.2026,
00:05:16-00:05:21). Diff: `docs\diff_s5_discount_valuta.patch`.
00:05:16-00:05:21). Diff: diff aplicat (sters).
## Rezultat

View File

@@ -201,4 +201,4 @@ Pe `id_vanzare=1049` (acelasi document folosit de toate suitele S5 anterioare):
`ofacturare_comun.vc2`, `comun.vc2`, `ofacturare_editare.prg`, `COMUN\clase\ofacturare.vc2` —
neatinse, conform interdictiei din briefing.
Diff (fisiere noi): `docs\diff_s5_goluri_test.patch`.
Diff (fisiere noi): diff aplicat (sters).

View File

@@ -1,186 +0,0 @@
# S5 — helper VFP `ScrieArticoleFacturaEditate` (`COMUN\programe\ofacturare_editare.prg`)
Implementare, nu doar cercetare. Singurul fisier atins: `COMUN\programe\ofacturare_editare.prg`
(`.prg` sursa directa, fara binar, fara write-back). Diff: `docs\diff_s5_helper_scriere.patch`.
## 1. Ce s-a facut
- `CreeazaCursorArticoleGol` (deci si `CreeazaCursorTvdGol`): adaugate `id_vanzare_set I NULL` si
`pret_achizitie N(14,4) NULL`, imediat dupa `sters`, inainte de `denumire` — aceeasi pozitie ca in
view-ul `VVANZARI_ARTICOLE` extins de `ff_2026_08_09_02_COMUN_VVANZARI_ARTICOLE.sql` (verificat pe
disc, coloanele intra la coada listei proprii tabelei, inainte de join-uri).
- `IncarcaArticoleFactura`: **nicio modificare de cod** — foloseste deja `select v.*, na.in_stoc from
vvanzari_articole v ...` (`:299`), deci cele doua coloane noi ale view-ului ajung automat in `tvd`
prin `v.*` in momentul in care view-ul e aplicat in Oracle. Extinderea cursorului gol (mai sus) e
suficienta pentru ca `tvd` sa poarte ambele coloane si pe ramura de eroare/fallback.
- **A doua definitie a cursorului, `omodificari.vc2:14571` (ramura ROACONT/ROAGEST, `CREATE CURSOR`
duplicat literal) NU a fost atinsa** — confirmarea ceruta explicit. Trebuie tinuta sincron manual de
agentul care lucreaza pe `.vc2`, altfel `tvd` are structuri diferite dupa aplicatie.
- Functie noua `ScrieArticoleFacturaEditate(tnIdVanzare, tcAliasArticole, tcAliasVanzare)` —
implicit `'tvd'`/`'tvanz'`. Patru pasi, in ordinea impusa de decizia 38 (marcheaza tot, invie ce
ramane, insereaza, recalculeaza), fara `COMMIT`/`ROLLBACK`, fara inchidere de cursoare,
salveaza/restaureaza workarea si `Recno()` pe alias.
## 2. Recalculul de totaluri (pasul 4) — LAMURIT de team-lead, acum in helper
Livrarea initiala nu includea apelul la `recalculeaza_totaluri_vanzari` in helper, motivat de
`rec_s5_cale_scriere_vfp.md` 3.3 ("apelul trebuie facut din VFP, ca pas separat, dupa helper") si de
secventa din decizia 38 care arata doua apeluri distincte la nivelul apelantului. **Team-lead a
corectat**: acea schita era la nivel de apelant, nu contractul final; apelul intra in helper tocmai ca
sa ramana un singur punct de scriere (altfel cele doua puncte de intrare, `ofacturare_comun.vc2` si
`comun.vc2`, trebuie amandoua sa-si aminteasca sa-l cheme, cu riscul de a uita unul).
**Implementat acum**: pasul 4, ultimul, dupa `INSERT`-uri, gardat de `IF m.llSucces`:
```
begin pack_facturare.recalculeaza_totaluri_vanzari(<tnIdVanzare>, <discount sau NULL>); end;
```
- discountul se citeste din `<tcAliasVanzare>.discount` (primul rand, garantat unic de garda de
no-op) imediat la inceputul functiei, inainte de pasii 1-3 (pozitia in cursorul de articole nu
intra in conflict, sunt cursoare separate).
- daca `discount` e `.NULL.` in cursor, se trimite literal `NULL` in apelul PL/SQL (pastreaza
discountul curent din baza) — **nu** `0`, care l-ar sterge. Daca are valoare, se trimite prin
`Alltrim(Str(...,18,4))`.
- niciun `UPDATE VANZARI SET DISCOUNT` separat — scrierea discountului ramane exclusiv in
responsabilitatea procedurii Oracle, primit ca parametru, exact cum cere decizia 41.
- acelasi tratament de eroare ca la ceilalti pasi: `goExecutor.oExecuta`, `.F.` la esec, fara mesaj
propriu, fara `COMMIT`/`ROLLBACK`.
## 3. `PRET_ACHIZITIE` pe linia noua — INCHIS: se citeste din cursor, nu se calculeaza in helper
Premisa initiala a deciziei 40 ("se preia din nomenclator / stoc") s-a dovedit gresita si a fost
revizuita de Marius, dupa constatarea de mai jos. Decizia finala: valoarea **o introduce
utilizatorul**, intr-o coloana noua editabila in gridul de pe PAGE3 (`omodificari.vc2`, doar pe
liniile noi — alt agent, nu se atinge aici). Helperul doar **citeste** `pret_achizitie` din cursorul
de articole (`Nvl(pret_achizitie,0)`), fara niciun lookup Oracle propriu.
**Constatarea care a schimbat decizia** (`SELECT` read-only in `MARIUSM_AUTO`, pastrata aici ca sa nu
se redescopere):
- `NOM_ARTICOLE` **nu are nicio coloana de pret de achizitie curent** — singura coloana cu "PRET" sau
"ACHIZ" in nume e `PRETACHCTVA` (`NUMBER`, `DEFAULT 0`), care e un **flag** ("pretul de achizitie
contine TVA?"), nu o valoare — confirmat prin utilizarea ei in
`pack_facturare.scrie_fact_aviz_custodie` (`docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:10116,
10168-10169, 10209`), unde e citita alaturi de `V_PRET_ACHIZITIE` (parametru separat), niciodata ca
sursa a lui.
- La emitere, `pret_achizitie` **nu vine dintr-o coloana statica** — vine fie din cursorul de stoc VFP
(`ofacturare_stoc.prg:221`, `a.Pret As pret_achizitie` din `rul_temp`, adica pretul lotului de stoc
ales), fie din cursorul de articole selectate la alegerea din gestiune
(`ofacturare.vc2:13822/13849`, `poArticol.pret_achizitie = Pret` din `crsartselectate`), fie e
re-derivat in Oracle in `adauga_articol_factura` (`docs\ff_...PACK_FACTURARE.sql:5020,
5093-5134`) — numai pe ramura restaurant (`ntip=45`) din `CRM_POLITICI_PRET_ART.PRETFTVA` +
procent de adaos; pe toate celelalte ramuri ramane valoarea primita ca parametru din VFP. Niciuna
din aceste cai exista in fluxul de editare: liniile noi la editare se adauga prin
`CreeazaPoArticolNouTvd` (`ofacturare_editare.prg:356-457`), care fixeaza
**`id_gestiune = -1000` si `gestionabil = 0`** necondtionat — adica editarea NU deschide dialogul
de alegere din stoc, deci n-are un lot/gestiune reala de unde sa citeasca pretul.
- `STOC` (verificat structura, `all_tab_columns`): tabela periodica `AN, LUNA, ID_ARTICOL,
ID_GESTIUNE, PRET, PRETV, CANTS, ...` — un rand pe lot/perioada/gestiune, aceeasi granularitate ca
`RUL`. **Nu exista un "pret curent" unic** fara o formula de agregare (ce perioada, ce gestiuni).
**Ce e implementat acum, in `ScrieArticoleFacturaEditate`**: la pasul `INSERT` al liniei noi,
`PRET_ACHIZITIE = Nvl(<tcAliasArticole>.pret_achizitie, 0)`, citit direct din cursor (coloana
adaugata la punctul 1) — fara `STOC`, fara `NOM_ARTICOLE`, fara functie ajutatoare. La `UPDATE`-ul
liniilor pastrate, coloana ramane **omisa din `SET`**, exact ca in specificatia initiala (pe liniile
existente nu e editabila, valoarea persistata nu se atinge).
## 4. Coloanele `NOT NULL` din `VANZARI_DETALII` — verificat, punctul NEVERIFICAT din cercetare e inchis
`SELECT column_name, nullable, data_default FROM all_tab_columns WHERE owner='MARIUSM_AUTO' AND
table_name='VANZARI_DETALII' AND nullable='N'` (read-only, `MARIUSM_AUTO`/`ROA_CENTRAL`):
| Coloana | `DATA_DEFAULT` | Tratament in `INSERT` |
|---|---|---|
| `ID_VANZARE_DET` | — | nu se scrie, vine din trigger `TRG_VANZARI_DET_BEFOINS` |
| `ID_VANZARE` | — | scris explicit (`tnIdVanzare`) |
| `PRET` | — | scris explicit (din `tvd.pret`) |
| `VALIDAT` | `0` | nescris, ramane `DEFAULT 0` |
| `STERS` | `0` | nescris, ramane `DEFAULT 0` (linie noua = activa) |
| `DIFERENTA` | `0` | nescris, ramane `DEFAULT 0` |
| `CUSTODIE` | `0` | nescris, ramane `DEFAULT 0` |
| `DESCARCAT` | `0` | nescris, ramane `DEFAULT 0` |
Toate cele cinci `NOT NULL` fara valoare din trigger **au `DEFAULT 0` la nivel de coloana** — nu e
nevoie sa fie enumerate in `INSERT`. Singurele `NOT NULL` care trebuie scrise explicit sunt
`ID_VANZARE` si `PRET`, deja acoperite de contract.
## 5. SQL generat, cate un exemplu per categorie
**Pasul 1 — marcheaza tot sters** (`tnIdVanzare = 12345`, `gnIdUtil = 7`):
```sql
update vanzari_detalii set sters = 1, id_utils = 7, dataoras = sysdate where id_vanzare = 12345 and sters = 0
```
**Pasul 2 — linie pastrata** (`id_vanzare_det = 98765`, `cantitate = 2.5`, `pret = 10.5`,
`pret_cu_tva = 0`):
```sql
update vanzari_detalii set sters = 0, cantitate = 2.500, pret = 10.5000, pret_cu_tva = 0, id_utils = 7, dataoras = sysdate where id_vanzare_det = 98765
```
**Pasul 3 — linie noua** (`id_articol = 111`, `cantitate = 1`, `pret = 20`, `pret_cu_tva = 0`,
`proc_tvav = 1.19`, `discount_unitar = 0`, `id_gestiune = -1000`, `cont` gol -> `NULL`, `id_valuta`
`.NULL.` -> `NULL`, `id_jtva_coloana = 3`, `serie`/`lot` goale -> `NULL`, `explicatie = "test 'x'"`,
`taxcode` `.NULL.` -> `NULL`, `pret_achizitie` tastat de utilizator in grid = `15.2300`):
```sql
insert into vanzari_detalii (id_vanzare, id_articol, cantitate, pret, pret_cu_tva, proc_tvav, discount_unitar, id_gestiune, cont, id_valuta, id_jtva_coloana, serie, explicatie, taxcode, lot, pret_achizitie, id_utils, dataoras) values (12345,111,1.000,20.0000,0,1.1900,0.0000,-1000,NULL,NULL,3,NULL,'test ''x''',NULL,NULL,15.2300,7,sysdate)
```
(`OracleSpecialCharacters` a dublat apostroful din `explicatie`.)
**Pasul 4 — recalculul totalurilor** (`tnIdVanzare = 12345`, `tvanz.discount = 5` — cazul cu valoare):
```sql
begin pack_facturare.recalculeaza_totaluri_vanzari(12345,5.0000); end;
```
Cazul `tvanz.discount` `.NULL.` (pastreaza discountul curent din baza):
```sql
begin pack_facturare.recalculeaza_totaluri_vanzari(12345,NULL); end;
```
## 6. Ce a ramas netestat, si de ce
- **Nimic rulat** — nu era in scope ("NU rulezi teste care scriu in baza"). Verificarea de mai sus
(coloane `NOT NULL`, tipuri, existenta view-ului) a fost facuta prin `SELECT`-uri read-only in
`MARIUSM_AUTO`, nu prin executarea functiei.
- Textul SQL generat pentru cei 4 pasi (sectiunea 5) e verificat manual, pe exemple, nu prin rularea
functiei cu un `goExecutor` mock.
- Restul e netestabil headless din motivele deja consemnate in `rec_s5_cale_scriere_vfp.md` sectiunea
7 (ordonarea fata de `actualizeaza_vanzari` cere Oracle real; grid-ul de pe PAGE3 care va scrie
`pret_achizitie` in cursor nu exista inca — depinde de agentul pe `omodificari.vc2`).
## 7. Rezumat pentru revizuire
Ambele puncte semnalate initial ca neconfirmate au fost lamurite de team-lead/Marius:
1. **Recalculul de totaluri** — intra in helper, ca pasul 4 (sectiunea 2).
2. **`PRET_ACHIZITIE`** — nu se mai calculeaza in helper; se citeste din cursor, unde va fi scrisa de
utilizator prin coloana noua din grid (sectiunea 3).
Toata functionalitatea (structura cursorului, cei 4 pasi de scriere, coloanele `NOT NULL`) e
implementata conform contractului final, fara ambiguitate ramasa in acest fisier.
## 8. Corectii din revizuirea team-lead
**1. Garda de no-op extinsa cu `Reccount(tcAliasArticole) = 0` — schimbare de fond fata de cercetare.**
`rec_s5_cale_scriere_vfp.md` sectiunea 6 spunea explicit ca un cursor de articole gol cu
`tnIdVanzare > 0` **nu** e no-op ("s-au sters toate liniile"), plecand de la premisa ca un cursor gol
apare doar prin stergerea tuturor liniilor de catre utilizator. Team-lead a aratat, cu dovada din cod,
ca premisa e incompleta: `IncarcaArticoleFactura` (`ofacturare_editare.prg:305-309`) intoarce **`.T.`
cu cursor gol** si la esec Oracle:
```
IF lnSucces < 0
AMESSAGEBOX(goExecutor.cEroare,0+16,"Eroare")
CreeazaCursorArticoleGol(m.lcAlias)
RETURN .T.
ENDIF
```
Helperul nu poate distinge "utilizatorul a sters tot" de "incarcarea a picat" — ambele ajung cu
`tvd` gol si `.T.` de la apelul de incarcare. Fara garda, al doilea caz ar duce, prin pasul 1
(marcheaza tot sters, fara nimic de inviat la pasul 2), la golirea tacuta a facturii la un simplu esec
de retea/Oracle la deschiderea formularului. Corectat: `Reccount(m.lcAliasArt) = 0` s-a adaugat la
garda initiala de no-op — cursorul gol nu mai scrie nimic. Cazul legitim (utilizatorul chiar sterge
toate liniile) e oricum oprit mai devreme de validarea din `inainte_de_do_termin` (alt agent,
`omodificari.vc2`), inainte ca helperul sa fie apelat.
**2. `UPDATE`-ul liniilor pastrate (pasul 2) ancorat si pe `id_vanzare`.** `WHERE id_vanzare_det = ...`
nu avea garda pe document. Adaugat `and id_vanzare = <tnIdVanzare>` — cost zero, inchide posibilitatea
teoretica de scriere intr-un alt document daca aliasul ar ajunge vreodata sa contina o linie straina
de `tnIdVanzare`.
Nimic altceva schimbat: ordinea pasilor, `NULL` pe discount, omiterea `PRET_ACHIZITIE` din `SET`-ul
de `UPDATE`, `OracleSpecialCharacters`, restaurarea `Recno()`/workarea raman ca in runda anterioara.

View File

@@ -1,780 +0,0 @@
# Cercetare S5 — proiectarea partii Oracle (plan #6, editare factura emisa)
Data: 09.08.2026. Sursa: export PROASPAT din `MARIUSM_AUTO@ROA_CENTRAL` (`all_source`), facut in
aceasta sesiune, in scratchpad (nu in proiect):
- `PACK_FACTURARE.pck` — 16160 linii
- `PACK_CONTAFIN.pck` — 8550 linii
**Toate numerele de linie de mai jos sunt din ACEST export.** Raportul precedent
(`rec_s5_oracle_vanzari.md`, 08.08.2026) declara `PACK_FACTURARE.pck = 17010` linii; offset-urile
procedurilor coincid totusi exact (`scrie_in_vanzari` la `:13491`, `actualizeaza_vanzari` la
`:16015`), deci diferenta e de formatare a spool-ului, nu de continut. Concluziile lui A.1-A.2, C si
D raman valabile pe sursa de azi si nu se repeta aici.
**Doua corectii de fond fata de raportul precedent** (detaliate la 3 si 4):
1. agregarea NU citeste `VANZARI_SETURI_TEMP`, ci tabela **persistenta `VANZARI_SETURI`**
(`:13916`) — deci liniile de set se pot reconstitui integral la editare;
2. recomandarea „procedura noua apelata din interiorul `finalizeaza_modificare_nota`" e
**incompatibila cu ordinea corecta de scriere** si trebuie abandonata.
---
## 1. Baza de plecare e la zi? DA (pentru `ff_`)
Comparatie `VERSIUNE` (4151 randuri) vs. `D:\ROA\DATABASE\SCRIPTURI_CLAR` (3030 fisiere `.sql`):
- **`ff_` pe disc dar neaplicate in `MARIUSM_AUTO`: 0.** Schema e la zi pe tot ce o priveste.
- Ultimul `ff_` inregistrat: `ff_2026_08_08_01_COMUN_VVANZARI_ARTICOLE.sql`, identic cu
`versiune_db.txt` din radacina proiectului (`2026_08_08_01`).
- Cele 26 de scripturi din 2026 care lipsesc din `VERSIUNE` sunt **exclusiv `co_` si `sys_`** — se
aplica pe `CONTAFIN_ORACLE`, respectiv `SYS`, nu pe schema firmei; `VERSIUNE` din `MARIUSM_AUTO`
contine doar 3 randuri `co_`, deci absenta lor e normala, nu o restanta.
**Verdict: se poate construi propunerea peste sursa exportata azi.**
### Doua anomalii de semnalat (nu blocheaza S5)
- **`ff_2026_08_08_01_COMUN_VVD_TOT.sql` e inregistrat in `VERSIUNE` dar NU exista nicaieri pe
disc** (cautat recursiv in tot `SCRIPTURI_CLAR`). Un obiect aplicat in dev fara script salvat nu
ajunge niciodata la clienti. De verificat cu Marius daca e un script de lucru abandonat sau daca
lipseste din SVN.
- Acelasi `NN` (`2026_08_08_01`) e folosit de doua scripturi `ff_` (`VVANZARI_ARTICOLE` si
`VVD_TOT`), contra regulii „NN e secventa unica pe zi".
---
## 2. Blocul de agregare din `scrie_in_vanzari` — integral
Procedura: `PACK_FACTURARE.pck:13491-13956`. Blocul de agregare + `UPDATE VANZARI` e
`:13762-13954`, citat integral:
```
13762 -- Completare totaluri in vanzari din vanzari_detalii pentru a usura selectiile din fact_vfacturi
13763 begin
13764 select DISC_TVA_VAL AS DISCOUNT_TVA,
13765 VALOARE_ACHIZITIE,
13766 a.suma_fara_tva_ron - a.disc_fara_tva_ron as TOTAL_FARA_TVA,
13767 a.suma_tva_ron - a.disc_tva_ron as TOTAL_TVA,
13768 a.suma_fara_tva_ron - a.disc_fara_tva_ron + a.suma_tva_ron -
13769 a.disc_tva_ron as TOTAL_CU_TVA,
13770 a.suma_fara_tva_val - a.disc_fara_tva_val as VALVAL,
13771 a.suma_tva_val - a.disc_tva_val as TVAVAL,
13772 a.suma_fara_tva_val - a.disc_fara_tva_val + a.suma_tva_val -
13773 a.disc_tva_val as TOTVAL,
13774 id_valuta,
13775 curs,
13776 multiplicator,
13777 pack_facturare.cserie_act_incasare as SERIE_INCASAT,
13778 pack_facturare.nnumar_act_incasare as NR_INCASAT,
13779 pack_facturare.nsuma_incasare AS SUMA_INCASAT,
13780 pack_facturare.ntip_doc_incasare as TIP_INCASAT
13781 INTO lnDiscountTVA,
13782 lnValoareAchizitie,
13783 lnTotalFaraTVA,
13784 lnTotalTVA,
13785 lnTotalCuTVA,
13786 lnValVal,
13787 lnTVAVal,
13788 lnTotVal,
13789 lnIdValuta,
13790 lnCurs,
13791 lnMultiplicator,
13792 lnSerieIncasat,
13793 lnNrIncasat,
13794 lnSumaIncasat,
13795 lnTipIncasat
13796 FROM (select MAX(decode(pack_facturare.nin_valuta,
13797 1,
13798 ROUND(a1.curs * NVL(V_DISCOUNT_FACTURA, 0) /
13799 a1.multiplicator,
13800 lnPreciziePretV),
13801 NVL(V_DISCOUNT_FACTURA, 0))) as DISC_FARA_TVA_RON,
13802 NVL(V_DISCOUNT_FACTURA, 0) as DISC_FARA_TVA_VAL,
13803 pack_facturare.nin_valuta AS IN_VALUTA,
13804 MAX(ROUND(decode(pack_facturare.nin_valuta,
13805 1,
13806 ROUND(a1.curs *
13807 NVL(V_DISCOUNT_FACTURA, 0) /
13808 a1.multiplicator,
13809 lnPreciziePretV),
13810 NVL(V_DISCOUNT_FACTURA, 0)) *
13811 (a1.proc_tvav - 1),
13812 lnPreciziePretV)) as DISC_TVA_RON,
13813 MAX(ROUND(NVL(V_DISCOUNT_FACTURA, 0) *
13814 (a1.proc_tvav - 1),
13815 lnPreciziePretV)) as DISC_TVA_VAL,
13816 sum(pack_facturare.calculeaza_total_fara_tva_fact(a1.pret_ron,
13817 0,
13818 1,
13819 NVL(a1.discount_unitar_ron,
13820 0),
13821 pack_facturare.ndiscount_evidentiat,
13822 a1.cantitate,
13823 a1.pret_cu_tva,
13824 a1.proc_tvav)) AS SUMA_FARA_TVA_RON,
13825 sum(pack_facturare.calculeaza_total_tva_fact(a1.pret_ron,
13826 0,
13827 1,
13828 NVL(a1.discount_unitar_ron,
13829 0),
13830 pack_facturare.ndiscount_evidentiat,
13831 a1.cantitate,
13832 a1.pret_cu_tva,
13833 a1.proc_tvav)) as SUMA_TVA_RON,
13834 sum(pack_facturare.calculeaza_total_fara_tva_fact(a1.pret_val,
13835 0,
13836 1,
13837 NVL(a1.discount_unitar_val,
13838 0),
13839 pack_facturare.ndiscount_evidentiat,
13840 a1.cantitate,
13841 a1.pret_cu_tva,
13842 a1.proc_tvav)) AS SUMA_FARA_TVA_VAL,
13843 sum(pack_facturare.calculeaza_total_tva_fact(a1.pret_val,
13844 0,
13845 1,
13846 NVL(a1.discount_unitar_val,
13847 0),
13848 pack_facturare.ndiscount_evidentiat,
13849 a1.cantitate,
13850 a1.pret_cu_tva,
13851 a1.proc_tvav)) as SUMA_TVA_VAL,
13852 sum(round(a1.cantitate * a1.pret_achizitie,
13853 lnPrecizieCalcul)) AS VALOARE_ACHIZITIE,
13854 max(decode(pack_facturare.nin_valuta, 1, a1.id_valuta, 0)) as id_valuta,
13855 max(decode(pack_facturare.nin_valuta, 1, a1.curs, 1)) as curs,
13856 max(decode(pack_facturare.nin_valuta, 1, a1.multiplicator, 1)) as multiplicator
13857 from (select vd.id_vanzare_set,
13858 (case
13859 when (pack_facturare.nin_valuta = 1 or
13860 vd.id_valuta <>
13861 pack_def.GetIdMonedaNationala()) then
13862 ROUND(vc.curs * vd.pret / vc.multiplicator,
13863 lnPreciziePretV)
13864 else
13865 vd.pret
13866 end) as pret_ron,
13867 vd.pret as pret_val,
13868 vd.proc_tvav,
13869 vd.cantitate,
13870 vd.diferenta,
13871 (case
13872 when (pack_facturare.nin_valuta = 1 or
13873 vd.id_valuta <>
13874 pack_def.GetIdMonedaNationala()) then
13875 ROUND(vc.curs * vd.discount_unitar /
13876 vc.multiplicator,
13877 lnPreciziePretV)
13878 else
13879 vd.discount_unitar
13880 end) as discount_unitar_ron,
13881 vd.discount_unitar as discount_unitar_val,
13882 vd.id_valuta,
13883 vd.pret_cu_tva,
13884 vd.pret_achizitie,
13885 vc.curs,
13886 vc.multiplicator
13887 from (select a.id_vanzare_set,
13888 a.pret,
13889 a.proc_tvav,
13890 a.cantitate,
13891 a.diferenta,
13892 a.discount_unitar,
13893 a.id_valuta,
13894 a.pret_cu_tva,
13895 a.pret_achizitie
13896 from VANZARI_DETALII_TEMP a
13897 where nvl(a.id_vanzare_set, 0) = 0
13898 union all
13899 select b.id_vanzare_set,
13900 b.pret,
13901 max(c.proc_tvav) as proc_tvav,
13902 b.cantitate,
13903 0 as diferenta,
13904 b.discount_unitar,
13905 decode(pack_facturare.nin_valuta,
13906 0,
13907 pack_def.GetIdMonedaNationala(),
13908 c.id_valuta) as id_valuta,
13909 b.pret_cu_tva,
13910 sum(decode(b.cantitate,
13911 0,
13912 0,
13913 c.pret_achizitie * c.cantitate /
13914 b.cantitate)) as pret_achizitie
13915 from vanzari_detalii_temp c
13916 left join vanzari_seturi b
13917 on b.id_vanzare_set = c.id_vanzare_set
13918 where nvl(c.id_vanzare_set, 0) <> 0
13919 and nvl(pack_facturare.nin_valuta, -1) > -1
13920 group by b.id_vanzare_set,
13921 b.pret,
13922 b.cantitate,
13923 b.discount_unitar,
13924 b.pret_cu_tva,
13925 decode(pack_facturare.nin_valuta,
13926 0,
13927 pack_def.GetIdMonedaNationala(),
13928 c.id_valuta)) vd
13929 left join vanzari_cursuri vc
13930 on vc.id_vanzare = V_ID_VANZARE
13931 and vd.id_valuta = vc.id_valuta) a1) a;
13932
13933 update vanzari
13934 set discount_tva = lnDiscountTVA,
13935 valoare_achizitie = lnValoareAchizitie,
13936 total_fara_tva = lnTotalFaraTVA,
13937 total_tva = lnTotalTVA,
13938 total_cu_tva = lnTotalCuTVA,
13939 valval = lnValVal,
13940 tvaval = lnTVAVal,
13941 totval = lnTotVal,
13942 id_valuta = lnIdValuta,
13943 curs = lnCurs,
13944 multiplicator = lnMultiplicator,
13945 serie_incasat = lnSerieIncasat,
13946 nr_incasat = lnNrIncasat,
13947 suma_incasat = lnSumaIncasat,
13948 tip_incasat = lnTipIncasat
13949 where id_vanzare = V_ID_VANZARE;
13950
13951 exception
13952 when NO_DATA_FOUND then
13953 null;
13954 end;
```
Variabilele locale relevante, declarate la `:13501-13523`:
```
13522 lnPrecizieCalcul NUMBER(2) := pack_sesiune.getOptiuneFirma('PC');
13523 lnPreciziePretV NUMBER(2) := pack_sesiune.getOptiuneFirma('PPRETV');
```
### Inventarul dependentelor blocului
| Dependenta | Linii | Sursa la emitere | Echivalent PERSISTENT la editare | Verdict |
|---|---|---|---|---|
| `V_DISCOUNT_FACTURA` | 13798, 13801, 13802, 13807, 13810, 13813 | parametru al procedurii | **`VANZARI.DISCOUNT`** — scrisa la INSERT din exact acelasi parametru (`:13621` / `:13682`) | reconstituibil |
| `pack_facturare.nin_valuta` | 13796, 13803, 13804, 13854-13856, 13859, 13872, 13905, 13919, 13925 | stare de sesiune pe pachet | **`VANZARI.IN_VALUTA`** (`NUMBER(1)`, NOT NULL) — scrisa la INSERT din aceeasi variabila (`:13625` / `:13686`) | reconstituibil |
| `pack_facturare.ndiscount_evidentiat` | 13821, 13830, 13839, 13848 | stare de sesiune pe pachet | **`VANZARI.DISCOUNT_EVIDENTIAT`** — scrisa la INSERT din aceeasi variabila (`:13622` / `:13683`) | reconstituibil |
| `cserie_act_incasare`, `nnumar_act_incasare`, `nsuma_incasare`, `ntip_doc_incasare` | 13777-13780 | stare de sesiune, setata numai in fluxul de emitere (`:13102-13144`; resetate la `:1882-1886`) | **NICIUNUL** | vezi 6 |
| `pack_def.GetIdMonedaNationala()` | 13861, 13874, 13907, 13927 | functie pura: `SELECT MIN(ID_VALUTA) FROM NOM_VALUTE WHERE STERS=0 AND MONEDA_NATIONALA=1` (PACK_DEF body `:214-230`) | idem — fara stare | fara probleme |
| `pack_sesiune.getOptiuneFirma('PC'/'PPRETV')` | 13522-13523, 13853 | `SELECT varvalue FROM optiuni WHERE ...` (PACK_SESIUNE body `:119-141`) — **lookup pe tabela, fara stare de pachet** | idem | fara probleme |
| `VANZARI_DETALII_TEMP` (liniile directe) | 13896-13897 | GTT `ON COMMIT DELETE ROWS` | **`VANZARI_DETALII WHERE ID_VANZARE = :id AND STERS = 0 AND NVL(ID_VANZARE_SET,0) = 0`** | vezi 3 |
| `VANZARI_DETALII_TEMP` (liniile de set, alias `c`) | 13915, 13918 | GTT | **`VANZARI_DETALII ... AND NVL(ID_VANZARE_SET,0) <> 0`** | vezi 3 |
| `vanzari_seturi` (alias `b`) | 13916 | **tabela PERSISTENTA, deja** | ea insasi | vezi 3 |
| `vanzari_cursuri vc` | 13929-13930 | tabela persistenta, populata cu `id_vanzare`-ul curent la `:13704` (`scrie_cursuri`) | ea insasi, deja legata pe `ID_VANZARE` | fara probleme |
Verificat pe `all_tab_columns`: **toate cele 9 coloane citite din `VANZARI_DETALII_TEMP` de
agregare** (`id_vanzare_set, pret, proc_tvav, cantitate, diferenta, discount_unitar, id_valuta,
pret_cu_tva, pret_achizitie`) exista, cu acelasi nume, in `VANZARI_DETALII`. Singurele coloane pe
care TEMP le are in plus si care nu exista in tabela reala sunt `CURS, MULTIPLICATOR, EXPLICATIA,
ID_COMANDA, NUMAR_ACT, ID_TEMP, ID_UTIL, IN_STOC, PRETV_ORIG, ID_GESTIUNE_DEST, ID_LUCRARE_REZ,
ID_PART_REZ` — **niciuna nu e folosita de blocul de agregare** (`curs`/`multiplicator` vin din
`vanzari_cursuri vc`, nu din linie).
**Concluzie: blocul se reproduce 1:1 pe surse persistente, schimband doar clauzele `FROM` si
inlocuind cele 3 valori de stare cu cele 3 coloane din `VANZARI`.** Nu e nevoie de nicio
reformulare a formulei — inclusiv `calculeaza_total_fara_tva_fact` / `calculeaza_total_tva_fact`
(`PACK_FACTURARE.pck:15858-16013`, semnaturi in spec la `:1167-1185`) raman apelate identic.
Doua observatii de detaliu:
- `a1.diferenta` e selectata (`:13870`, `:13891`) dar **nu e folosita nicaieri** in agregarea din
`scrie_in_vanzari` (parametrul `V_DIFERENTA` e `0` hard-codat la `:13817`, `:13826`, `:13835`,
`:13844`). Se poate pastra pentru fidelitate sau elimina; recomand pastrarea, ca diff-ul fata de
original sa ramana citibil.
- Handler-ul `WHEN NO_DATA_FOUND THEN NULL` (`:13951-13953`) e defensiv si practic inaccesibil:
subinterogarea are agregate fara `GROUP BY`, deci intoarce mereu exact un rand. **Dar** pe zero
linii agregatele intorc `NULL`, nu `0` — la emitere cazul nu poate aparea, la editare da (vezi
riscul R4).
---
## 3. Liniile din seturi — EXISTA echivalent persistent
**Corectia raportului precedent.** Agregarea nu citeste `VANZARI_SETURI_TEMP`, ci
**`VANZARI_SETURI`** (`PACK_FACTURARE.pck:13916`), care e o tabela **normala, persistenta**
(verificat pe `all_tables`: `VANZARI_SETURI temporary=N`; doar `VANZARI_SETURI_TEMP` si
`VANZARI_DETALII_TEMP` sunt `temporary=Y duration=SYS$TRANSACTION`).
Trecerea TEMP -> persistent o face `pack_facturare.scrie_seturi` (`:13993-14028`), apelata la
`:13706`, **inainte** de agregare: insereaza fiecare rand din `VANZARI_SETURI_TEMP` in
`VANZARI_SETURI` (`ID_VANZARE_SET` din `SEQ_VANZARI_SETURI`, prin trigger
`TRG_VANZARI_SET_BEFOINS`) si reface pointerul in `VANZARI_DETALII_TEMP.ID_VANZARE_SET`. De aceea
agregarea de la `:13915-13928` face join intre TEMP (componentele) si tabela persistenta (capul de
set).
Structura `VANZARI_SETURI` (`all_tab_columns`), identica cu a TEMP-ului:
```
ID_VANZARE_SET NUMBER(10) NOT NULL -- PK, din SEQ_VANZARI_SETURI
DENUMIRE VARCHAR2(100)
EXPLICATIE VARCHAR2(100)
CANTITATE NUMBER(10,4)
UM VARCHAR2(10)
SERIE VARCHAR2(100)
PRET NUMBER(20,4)
DISCOUNT_UNITAR NUMBER(20,4)
PRET_CU_TVA NUMBER(1) NOT NULL
```
Nu are `ID_VANZARE` si nu are `STERS`: legatura cu documentul e **exclusiv** prin
`VANZARI_DETALII.ID_VANZARE_SET`. Deci filtrarea pe document se face tot din `VANZARI_DETALII`.
**Precedent care confirma reconstituirea**: `pack_facturare.citeste_vanzari_seturi`
(`:16619-16698`) reface deja exact acest lucru pe surse persistente — `VANZARI` (`cod`, `sters=0`)
+ `VANZARI_DETALII` (`sters=0`, `id_vanzare_set is not null`) + `VANZARI_CURSURI` +
`VANZARI_SETURI`, cu acelasi `GROUP BY b.id_vanzare_set`. Nu inventam un tipar nou.
**Raspuns la intrebarea din brief: DA, recalculul poate acoperi si liniile de set, fara pierdere de
informatie.** Transformarea necesara in ramura de set:
```
from vanzari_detalii c -- in loc de vanzari_detalii_temp c
left join vanzari_seturi b on b.id_vanzare_set = c.id_vanzare_set
where nvl(c.id_vanzare_set, 0) <> 0
and c.id_vanzare = V_ID_VANZARE
and c.sters = 0
```
Date (test, `MARIUSM_AUTO`): 4 randuri in `VANZARI_SETURI`, 4 documente cu linii de set. **Nu e o
dovada** — validarea ramane pe cod, nu pe volum.
### Ce NU se poate face din interfata (limitare de semnalat pentru S4)
View-ul `VVANZARI_ARTICOLE` (sursa lui `IncarcaArticoleFactura`,
`COMUN\programe\ofacturare_editare.prg:288-330`) **nu expune `ID_VANZARE_SET` si nici
`PRET_ACHIZITIE`**:
```
select vd.id_vanzare, vd.id_vanzare_det, vd.id_articol, vd.cantitate, vd.pret, vd.pret_cu_tva,
vd.proc_tvav, vd.discount_unitar, vd.id_gestiune, vd.cont, vd.id_valuta,
vd.id_jtva_coloana, vd.serie, vd.explicatie, vd.taxcode, vd.lot, vd.sters,
na.denumire, na.codmat, ng.nume_gestiune, nv.nume_val
from vanzari_detalii vd
left join nom_articole na on na.id_articol = vd.id_articol
left join nom_gestiuni ng on ng.id_gestiune = vd.id_gestiune
left join nom_valute nv on nv.id_valuta = vd.id_valuta
```
Consecinte concrete:
1. componentele de set apar in grid ca linii obisnuite, dar formularul **nu poate sti** ca sunt
componente si nu poate edita capul de set (`VANZARI_SETURI.PRET`/`CANTITATE`), care e ceea ce
intra efectiv in totaluri. Un utilizator care schimba pretul unei componente **nu schimba
totalul documentului** — recalculul ia pretul din `VANZARI_SETURI`. Divergenta tacuta.
2. `PRET_ACHIZITIE` lipseste din cursor, deci VFP nu-l poate rescrie la un `UPDATE` de linie: la
scriere trebuie **omis din `SET`**, ca sa ramana valoarea existenta (altfel `VALOARE_ACHIZITIE`
se pierde). Pentru liniile **noi** insa nu exista sursa — vor intra cu `PRET_ACHIZITIE` NULL si
vor contribui cu NULL la `SUM(round(cantitate * pret_achizitie))`, deci **`VALOARE_ACHIZITIE`
devine NULL pe tot documentul** daca fie si o singura linie noua are NULL. Vezi riscul R3.
---
## 4. Capcana de ordonare — punctul central
### Ce ruleaza azi, in ce ordine
Punctul de intrare nou (deja scris in ramura curenta):
`COMUN\clase\ofacturare_comun.vc2`, `do_editare_factura`, blocul de salvare:
```
3798 If Thisform.do_deschide_tranzactie() && SQLSetprop(gnHandle,"Transactions",2)
3800 lnSucces = OSCRIE_IN_FISIERE(2,.T.,.T.) && marcheaza STERS=1 nota veche
...
3820 lnSucces = OSCRIE_IN_FISIERE(0,.T.,.T.) && scrie nota noua (COD nou din SCRIE_IN_ACT)
3823 If lnSucces > 0
3824 lcSql = [begin pack_contafin.finalizeaza_modificare_nota(...); end]
3826 lnSucces = Iif(goExecutor.oExecuta(lcSql),1,-1)
3827 Endif
3828 If Thisform.do_inchide_tranzactie(Iif(lnSucces<0,2,1)) && SQLCOMMIT / SQLROLLBACK
```
`do_deschide_tranzactie` / `do_inchide_tranzactie`: `COMUN\clase\_frm_base.vc2:251-269` si
`:278-302` — `SQLSetprop(gnHandle,"Transactions",2)` / `Sqlcommit(gnHandle)`.
`finalizeaza_modificare_nota` (`PACK_CONTAFIN.pck:8601-8651`) apeleaza `actualizeaza_vanzari` la
`:8616`, gardat de `SELECT COUNT(*) FROM vanzari WHERE cod = tnCod > 0` (`:8613-8615`).
`actualizeaza_vanzari` (`PACK_FACTURARE.pck:16015-16025`):
```
16018 -- de modificat in caz ca il las sa stearga manual inregistrari din VANZARI_DETALII
16019 -- acum se marcheaza cu STERS = 1 doar cand se sterge toata factura
16020 UPDATE VANZARI_DETALII
16021 SET STERS = 0
16022 WHERE ID_VANZARE IN
16023 (SELECT ID_VANZARE FROM VANZARI WHERE COD = V_COD_VECHI);
16024 UPDATE VANZARI SET COD = V_COD_NOU, STERS = 0 WHERE COD = V_COD_VECHI;
```
### De ce exista `STERS = 0` acolo (nu e cod mort)
E perechea lui `sterge_din_vanzari` -> `sterge_factura`, care marcheaza documentul sters:
```
5549 UPDATE VANZARI_DETALII
5550 SET STERS = V_STERS, ID_UTILS = V_ID_UTIL, DATAORAS = V_DATAORA
5551 WHERE ID_VANZARE = V_ID_VANZARE
5552 AND STERS = V_NESTERS
```
Reeditarea unei note sterse trebuie sa readuca la viata si randul din `VANZARI`, si liniile lui.
**Scoaterea reset-ului ar rupe fluxul „stergi nota, apoi o reeditezi" pe toata suita ROA.**
### Consecinta pentru S5 — mai grava decat „stergerile se pierd"
Reset-ul e **in bloc, fara nicio garda**: nici `AND STERS = 1` (irelevant), nici o discriminare
intre „stersa ca linie" si „stersa odata cu documentul". `sterge_factura` marcheaza doar liniile
active (`AND STERS = V_NESTERS`, `:5552`), deci o linie stearsa la o editare anterioara ramane
`STERS=1` — si e **inviata** de `actualizeaza_vanzari` la urmatoarea salvare a notei.
Deci daca liniile se scriu inainte de `finalizeaza_modificare_nota`:
- stergerile din editarea CURENTA se pierd tacut;
- **si**, independent de ce face utilizatorul acum, orice stergere facuta la o editare
ANTERIOARA e anulata la fiecare salvare ulterioara — inclusiv la o salvare care nu atinge deloc
articolele. Stergerea de linie **nu s-ar fixa niciodata**.
`UPDATE`-urile de pret/cantitate si `INSERT`-urile de linii noi ar supravietui — deci esecul e
partial si asimetric, exact tipul care trece de un test superficial.
### Variantele de ordonare
**(a) VFP scrie detaliile inainte, `actualizeaza_vanzari` neatinsa.**
Respinsa. Motivul complet e cel de mai sus: nu doar ca stergerile din sesiunea curenta se pierd,
dar mecanismul de stergere de linie devine structural imposibil, fiindca fiecare salvare a notei
reseteaza tot documentul la `STERS = 0`. In plus, dupa `actualizeaza_vanzari` `VANZARI.COD` s-a
schimbat, deci orice scriere ulterioara ancorata pe `cod` ar rata randul (`ID_VANZARE` ramane —
vezi A.1 din raportul precedent, reconfirmat la `:16024`).
**(a') VFP scrie inainte + `actualizeaza_vanzari` primeste o garda.**
Respinsa. Ar cere un discriminator „stearsa ca linie" vs „stearsa cu documentul", care nu exista in
schema (`VANZARI_DETALII` nu are alt marcaj decat `STERS`/`ID_UTILS`/`DATAORAS`); orice euristica
pe `DATAORAS` e fragila. Si e Varianta A din raportul precedent — modificare in-place a unei
proceduri apelate de **orice** editare de nota cu `cod` in `vanzari`, din toata suita ROA.
**(b) VFP scrie detaliile DUPA ce `finalizeaza_modificare_nota` s-a intors, apoi apeleaza
`pack_facturare.recalculeaza_totaluri_vanzari(id_vanzare, discount)`, in aceeasi tranzactie.**
**RECOMANDATA.** Verificat, nu presupus:
- **tranzactia e inca deschisa** cand se intoarce `finalizeaza_modificare_nota`: aceasta ruleaza la
`ofacturare_comun.vc2:3826`, iar `do_inchide_tranzactie` abia la `:3828`; tranzactia e manuala pe
`gnHandle` (`_frm_base.vc2:255`), aceeasi conexiune ODBC pe care ruleaza `goExecutor`. Deci
scrierile de dupa intra in acelasi `COMMIT`/`ROLLBACK`, fara fereastra de inconsistenta.
- `actualizeaza_vanzari` ramane **neatinsa** — zero regresie pe ROAGEST/ROACONT.
- `PACK_CONTAFIN` ramane **neatins** — nu se recompileaza pachetul central de scriere a
documentelor.
- reset-ul `STERS = 0` ruleaza primul, iar VFP re-aplica dupa el starea autoritativa a liniilor.
- `VANZARI.COD` e deja rescris cand VFP scrie — de aceea toate scrierile se ancoreaza pe
`ID_VANZARE` (`lnIdVanzare`, citit din `crsfacturi` la `ofacturare_comun.vc2:3735`, stabil).
**Atentie — (b) naiv are un defect.** `IncarcaArticoleFactura` incarca **doar `sters = 0`**
(`ofacturare_editare.prg:302`), deci liniile sterse la o editare anterioara nu sunt in
`crsArticoleFactura`: reset-ul le-a inviat, iar VFP nu le atinge, deci raman active. Corectia e in
**forma scrierii**, nu in Oracle — VFP scrie o stare completa, nu un delta:
```
1. UPDATE VANZARI_DETALII SET STERS = 1, ID_UTILS = ?, DATAORAS = SYSDATE
WHERE ID_VANZARE = <id> AND STERS = 0 -- marcheaza tot
2. pentru fiecare linie pastrata din cursor, cu id_vanzare_det > 0:
UPDATE VANZARI_DETALII SET STERS = 0, CANTITATE = ?, PRET = ?, PRET_CU_TVA = ?, ...
WHERE ID_VANZARE_DET = <det> -- invie doar ce ramane
3. pentru fiecare linie noua: INSERT INTO VANZARI_DETALII (...) -- ID_VANZARE_DET din trigger
4. pack_facturare.recalculeaza_totaluri_vanzari(<id>, <discount>)
```
Idiomul „marcheaza tot, invie ce ramane" e idempotent, nu are limita de 1000 de elemente intr-un
`IN`, nu cere lista separata de linii sterse, si pastreaza sterse liniile scoase la editari
anterioare. La pasul 2, `PRET_ACHIZITIE` se **omite** din `SET` (nu e in cursor — vezi 3).
**(c) recalcul apelat din interiorul `finalizeaza_modificare_nota`** (recomandarea raportului
precedent, sectiunea B). **De abandonat.** Este incompatibila cu (b): daca recalculul ruleaza
inauntrul lui `finalizeaza_modificare_nota`, el vede liniile **vechi** (VFP nu le-a scris inca,
pentru ca nu poate scrie inainte de reset), deci ar produce exact totalurile de dinainte de editare
— tacut corecte ca formula, tacut gresite ca valoare. Nu e o varianta mai riscanta, e o varianta
gresita.
**(c') procedura Oracle care primeste si liniile** (prin `VANZARI_DETALII_TEMP` sau o colectie) si
face si scrierea, si recalculul. Respinsa: reintroduce calea TEMP pe care planul a exclus-o explicit
(`plan_06_editare_factura.md:106-114`), cere o forma de parametru incomoda prin ODBC, si dubleaza
scrierea per-linie pe care planul a decis-o deja in VFP, dupa modelul `modifica_explicatie_articol`
(`PACK_FACTURARE.pck:14514-14522`).
### Recomandare
**Varianta (b), cu scrierea in forma „marcheaza tot, invie ce ramane".** Argumentul decisiv nu e
comoditatea, ci ca e **singura ordine in care reset-ul `STERS = 0` din `actualizeaza_vanzari` ramane
inofensiv fara sa modificam procedura** — iar procedura aceea e folosita azi de toata suita, pentru
un scop legitim (reeditarea unei note sterse) pe care nu-l putem sacrifica.
---
## 5. Discountul de document (`VANZARI.DISCOUNT`)
**Cine il scrie azi: nimeni, dupa emitere.** Verificat pe toata schema, nu doar pe `PACK_FACTURARE`:
- `all_source` (`PACKAGE BODY`/`PROCEDURE`/`FUNCTION`/`TRIGGER`, `MARIUSM_AUTO`), cautand
`discount\s*=` exclusiv coloanele `discount_unitar|discount_tva|discount_evidentiat`: **niciun
`UPDATE ... SET DISCOUNT = ...` pe `VANZARI`.** Rezultatele sunt toate pe alte tabele
(`PACK_COMENZI.PROC_DISCOUNT`, `PACK_CRM.val_discount`, `PACK_OFERTARE.valdiscount`, ...).
- Toate cele 8 instructiuni `UPDATE VANZARI` din `PACK_FACTURARE` (`:5485, :5493, :5516, :5615,
:14817, :15387, :15397, :15509`) plus `modifica_date_factura` (`:14463-14512`, singura procedura
de „modifica antetul facturii" existenta) ating `STERS`/`FACTURAT`/`ID_FACT`/`AVIZE`/
`SERIE_ACT`/`NUMAR_ACT`/`DATA_ACT`/`DATA_SCAD` — **niciuna `DISCOUNT`**.
- In VFP: cautare pe `COMUN\` dupa `set discount =` / `vanzari set ... discount` — **niciun
rezultat**.
- Trigger-ele pe `VANZARI` nu-l ating: `TRG_VANZARI_BEFOUPD` face doar audit pe
`NR_ACT`/`SERIE_ACT`/`DATA_ACT`/`DATA_SCAD` (`pack_audit.verifica_val`).
Deci `VANZARI.DISCOUNT` e scris **o singura data in viata documentului**, la `INSERT`-ul din
`scrie_in_vanzari` (`:13621` in lista de coloane, `:13682` in `VALUES`, din `V_DISCOUNT_FACTURA`).
Nu exista nici procedura de modificare, nici cale VFP.
Pe partea VFP valoarea e deja disponibila in memorie: cursorul `tvanz` are coloana `discount`
(`ofacturare_editare.prg:152`, `CreeazaCursorTvanzGol`), populata din `VANZARI` de
`IncarcaVanzareNota` (`:176`).
### Recomandare: **parametru al procedurii noi**, nu `UPDATE` separat din VFP
```
recalculeaza_totaluri_vanzari(V_ID_VANZARE IN NUMBER, V_DISCOUNT IN NUMBER DEFAULT NULL)
```
cu semantica `V_DISCOUNT IS NULL` = „pastreaza valoarea curenta". Motive:
1. **discountul si totalurile nu pot diverge.** Cu doua instructiuni separate din VFP, un esec pe
a doua (sau o omisiune la un viitor call-site) lasa `DISCOUNT` nou si totaluri calculate pe cel
vechi. Cu un parametru, e imposibil sa recalculezi cu un discount invechit.
2. procedura ramane utilizabila ca **recalcul pur** (fara al doilea argument) de oriunde altundeva
— de exemplu dintr-un script de backfill.
3. e o instructiune ODBC in minus pe drumul critic.
Implementare: `V_DISCOUNT` se aplica in acelasi `UPDATE vanzari` final,
`discount = NVL(V_DISCOUNT, discount)`, iar valoarea folosita in agregare se citeste **inainte**,
ca `NVL(V_DISCOUNT, (select discount from vanzari where id_vanzare = V_ID_VANZARE))` — altfel
agregarea ar lucra pe discountul vechi.
---
## 6. Coloanele care NU se recalculeaza — reconfirmat pe sursa proaspata
`SERIE_INCASAT` / `NR_INCASAT` / `SUMA_INCASAT` / `TIP_INCASAT` (`:13777-13780`, scrise la
`:13945-13948`) vin din `pack_facturare.cserie_act_incasare` / `nnumar_act_incasare` /
`nsuma_incasare` / `ntip_doc_incasare`.
Cautare exhaustiva a atribuirilor catre aceste 4 variabile in `PACK_FACTURARE.pck` — **7 rezultate,
toate in fluxul de emitere**:
```
1882-1886 cserie_act_incasare := NULL; nnumar_act_incasare := NULL;
ntip_doc_incasare := NULL; nsuma_incasare := NULL; (initializeaza_date_factura)
13102-13105 cserie_act_incasare := V_SERIE_ACT_INCASARE; nnumar_act_incasare := V_NUMAR_ACT_INCASARE;
ntip_doc_incasare := nTipIncasareChitanta; nsuma_incasare := 0;
13136 nsuma_incasare := nsuma_incasare + ...
13140,13144 ntip_doc_incasare := V_TIP / nTipIncasareBonFiscal;
```
Sursele lor (`V_SERIE_ACT_INCASARE`, `V_NUMAR_ACT_INCASARE`) sunt parametri ai emiterii unei
facturi-cu-incasare combinata. **Nu exista nicio tabela din care sa fie reconstituite la o editare
ulterioara** — singura urma persistenta sunt chiar cele 4 coloane din `VANZARI`, care ar fi
suprascrise cu `NULL` de o copiere naiva a `UPDATE`-ului.
**Concluzie reconfirmata: procedura noua scrie 11 coloane** (`discount_tva`, `valoare_achizitie`,
`total_fara_tva`, `total_tva`, `total_cu_tva`, `valval`, `tvaval`, `totval`, `id_valuta`, `curs`,
`multiplicator`), **plus optional `discount`** (vezi 5). Cele 4 de incasare raman la valoarea de la
emitere.
---
## 7. Semnatura propusa si scripturile de migrare
### Declaratia din PACKAGE SPEC
Se adauga imediat dupa `actualizeaza_vanzari` (`PACK_FACTURARE.pck:1187-1188`), langa procedurile
surori:
```sql
PROCEDURE recalculeaza_totaluri_vanzari(V_ID_VANZARE IN NUMBER,
V_DISCOUNT IN NUMBER DEFAULT NULL);
```
`recalculeaza_totaluri_vanzari` = **29 de caractere**, sub limita de 30 a lui Oracle 10.2/11
(peste 30 ar da `ORA-00972`). Nu mai lungi numele.
### Corpul (schita, compatibila 10.2)
Constructii folosite: `SELECT INTO`, `UPDATE`, `DECODE`, `CASE`, `NVL`, `ROUND`, `MAX`, `SUM`,
`LEFT JOIN`, `UNION ALL`, `GROUP BY`, subinterogari inline. **Nimic din tabelul de incompatibilitati
din `scripturi-migrare-db.md`** — fara `LISTAGG`, `CONTINUE`, `REGEXP_COUNT`, `FETCH FIRST`,
`PIVOT`, `secventa.NEXTVAL` in atribuire.
```sql
PROCEDURE recalculeaza_totaluri_vanzari(V_ID_VANZARE IN NUMBER,
V_DISCOUNT IN NUMBER DEFAULT NULL) IS
lnDiscountFactura VANZARI.DISCOUNT%TYPE;
lnInValuta VANZARI.IN_VALUTA%TYPE;
lnDiscountEvidentiat VANZARI.DISCOUNT_EVIDENTIAT%TYPE;
lnDiscountTVA VANZARI.DISCOUNT_TVA%TYPE;
lnValoareAchizitie VANZARI.VALOARE_ACHIZITIE%TYPE;
lnTotalFaraTVA VANZARI.TOTAL_FARA_TVA%TYPE;
lnTotalTVA VANZARI.TOTAL_TVA%TYPE;
lnTotalCuTVA VANZARI.TOTAL_CU_TVA%TYPE;
lnValVal VANZARI.VALVAL%TYPE;
lnTVAVal VANZARI.TVAVAL%TYPE;
lnTotVal VANZARI.TOTVAL%TYPE;
lnIdValuta VANZARI.ID_VALUTA%TYPE;
lnCurs VANZARI.CURS%TYPE;
lnMultiplicator VANZARI.MULTIPLICATOR%TYPE;
lnPrecizieCalcul NUMBER(2) := pack_sesiune.getOptiuneFirma('PC');
lnPreciziePretV NUMBER(2) := pack_sesiune.getOptiuneFirma('PPRETV');
BEGIN
SELECT NVL(V_DISCOUNT, discount), in_valuta, NVL(discount_evidentiat, 0)
INTO lnDiscountFactura, lnInValuta, lnDiscountEvidentiat
FROM vanzari
WHERE id_vanzare = V_ID_VANZARE;
-- acelasi bloc de agregare ca in scrie_in_vanzari (:13764-13931), cu trei substitutii:
-- VANZARI_DETALII_TEMP a -> VANZARI_DETALII a WHERE a.id_vanzare = V_ID_VANZARE AND a.sters = 0
-- vanzari_detalii_temp c -> vanzari_detalii c WHERE c.id_vanzare = V_ID_VANZARE AND c.sters = 0
-- pack_facturare.nin_valuta -> lnInValuta
-- pack_facturare.ndiscount_evidentiat -> lnDiscountEvidentiat
-- V_DISCOUNT_FACTURA -> lnDiscountFactura
-- fara coloanele de incasare (serie/nr/suma/tip)
SELECT ... INTO lnDiscountTVA, lnValoareAchizitie, lnTotalFaraTVA, lnTotalTVA,
lnTotalCuTVA, lnValVal, lnTVAVal, lnTotVal,
lnIdValuta, lnCurs, lnMultiplicator
FROM ( ... );
UPDATE vanzari
SET discount = lnDiscountFactura,
discount_tva = lnDiscountTVA,
valoare_achizitie = lnValoareAchizitie,
total_fara_tva = lnTotalFaraTVA,
total_tva = lnTotalTVA,
total_cu_tva = lnTotalCuTVA,
valval = lnValVal,
tvaval = lnTVAVal,
totval = lnTotVal,
id_valuta = lnIdValuta,
curs = lnCurs,
multiplicator = lnMultiplicator
WHERE id_vanzare = V_ID_VANZARE;
END recalculeaza_totaluri_vanzari;
```
Idempotenta: `SELECT` + `UPDATE ... WHERE id_vanzare = :id`, fara `INSERT` — rularea de doua ori pe
acelasi id da acelasi rezultat.
**Fara handler `WHEN NO_DATA_FOUND THEN NULL`** pe modelul originalului: la editare, un `id_vanzare`
inexistent e o eroare reala care trebuie sa opreasca tranzactia, nu sa fie inghitita. (Primul
`SELECT INTO`, pe cheia primara, e singurul care poate ridica `NO_DATA_FOUND`.)
### Scripturile de migrare
Azi, 09.08.2026, in `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08` nu exista niciun script cu data de azi
(ultimele sunt `..._2026_08_08_01` si `..._2026_08_08_02`), deci **`NN` porneste de la `01`**.
`NN` e secventa unica pe zi, comuna tuturor prefixelor.
**Un singur script**, fiindca S5 atinge un singur pachet si nimic altceva:
```
ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql
```
- prefix `ff_` — pachetul sta pe schema fiecarei firme;
- **un pachet sta singur in scriptul lui**: fara DDL de tabele si fara DML alaturi (nu e nevoie de
niciunul — nu se adauga coloane si nu se curata date);
- contine SPEC + BODY (SPEC-ul se schimba: declaratia noua), CRLF obligatoriu, antet de 4-5 randuri,
fara `select` de raportare, si se incheie cu
`exec pack_migrare.UpdateVersiune('ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql');` + `commit;`;
- `versiune_db.txt` din radacina proiectului se muta pe `2026_08_09_01` (fara newline final).
**Nu e nevoie de un script separat pentru `VVANZARI_ARTICOLE`** pentru S5 asa cum e proiectat aici
— dar vezi intrebarea 3 de mai jos, care ar cere unul (`NN = 02`, si atunci **inainte** de cel al
pachetului daca pachetul l-ar folosi; aici nu-l foloseste, deci ordinea e libera).
---
## 8. Riscuri si intrebari deschise
**R1 — Componentele de set sunt editabile in grid dar nu influenteaza totalurile. (mediu)**
`VVANZARI_ARTICOLE` nu expune `ID_VANZARE_SET`, deci S4 nu poate distinge componentele de liniile
normale; recalculul ia insa pretul/cantitatea din `VANZARI_SETURI`, nu din componente. Utilizatorul
modifica o componenta, apasa salvare, totalul nu se schimba. Tacut.
*Recomandarea mea:* pentru #6, **adauga `ID_VANZARE_SET` in `VVANZARI_ARTICOLE`** (script separat,
`ff_2026_08_09_02_COMUN_VVANZARI_ARTICOLE.sql`) si fa liniile cu `id_vanzare_set` nenul
**needitabile in grid**, cu o eticheta („linie din set"). Editarea seturilor e o functionalitate
proprie, nu o extindere gratuita a lui S4. Alternativa minimala, daca Marius nu vrea scriptul de
view: blocheaza intreaga factura care contine seturi — dar asta contrazice decizia din
`plan_06_editare_factura.md:183-186` („fara blocarea facturilor care le contin").
**R2 — Stergerea unei componente de set. (mic, dar urat)**
Cu idiomul „marcheaza tot, invie ce ramane", stergerea in grid a unei componente lasa capul de set
in `VANZARI_SETURI` si celelalte componente pe loc: totalul ramane neschimbat (vine din cap), dar
`VALOARE_ACHIZITIE` scade (se pierde `pret_achizitie`-ul componentei). Divergenta partiala.
*Recomandare:* acoperit de R1 — daca liniile de set sunt needitabile, cazul dispare.
**R3 — `PRET_ACHIZITIE` NULL pe liniile noi anuleaza `VALOARE_ACHIZITIE` pe tot documentul. (mediu)**
`SUM(round(cantitate * pret_achizitie))` cu un singur operand NULL nu da NULL pe total (SUM ignora
NULL-urile), dar **linia noua nu contribuie deloc** — deci `VALOARE_ACHIZITIE` (baza de calcul a
marjei) subestimeaza sistematic dupa fiecare adaugare de linie. Coloana nu e in cursorul din grid si
nu are sursa la editare (la emitere vine din stoc/politica de pret).
*Recomandare:* la `INSERT`-ul liniei noi, VFP scrie `PRET_ACHIZITIE` cu pretul de achizitie curent
al articolului (acelasi lookup pe care il face `adauga_articol_factura_stoc`), sau, daca nu se poate
determina, cu `0` explicit si o avertizare in verificarile din S4b. **Nu lasa NULL tacut.**
**R4 — Factura fara nicio linie da totaluri NULL, nu 0. (mic)**
Agregatele pe zero randuri intorc NULL; la emitere cazul nu poate aparea, la editare da.
*Recomandare:* nu modifica formula (ar diverge de original). Interzice in S4b salvarea unei facturi
cu zero linii active — e oricum un document invalid.
**R5 — Linie cu valuta fara rand in `VANZARI_CURSURI`. (mic)**
`left join vanzari_cursuri vc on vc.id_vanzare = V_ID_VANZARE and vd.id_valuta = vc.id_valuta`
(`:13929-13930`): daca o linie ajunge cu o valuta pentru care documentul nu are curs, `vc.curs` e
NULL si `pret_ron` iese NULL. `CreeazaPoArticolNouTvd` primeste explicit valuta documentului
(`tnIdValutaDoc`, `ofacturare_editare.prg:356`), deci in fluxul proiectat nu ar trebui sa apara.
**NEVERIFICAT** ca S4 chiar transmite acel parametru pe toate caile de adaugare.
*Recomandare:* verificare in S4b, nu garda in Oracle.
**R6 — `pack_sesiune.getOptiuneFirma` intoarce `''` la orice eroare. (mic)**
`PACK_SESIUNE` body `:128-131`: `WHEN OTHERS THEN lcValue := ''`. Atribuit intr-un `NUMBER(2)`, `''`
devine NULL, iar `ROUND(x, NULL)` da NULL. Comportament identic cu cel de la emitere — deci nu e o
regresie introdusa de S5, dar merita stiut daca apar totaluri NULL inexplicabile.
*Recomandare:* nimic de facut in S5; consemnat pentru depanare.
**R7 — `ff_2026_08_08_01_COMUN_VVD_TOT.sql` aplicat in dev fara script pe disc. (de clarificat)**
Obiectul nu exista in `all_objects` sub niciun nume `VVD%`, deci probabil scriptul a creat altceva
sau a fost anulat ulterior. Fisierul lipseste din `SCRIPTURI_CLAR` -> nu ajunge la clienti.
*Recomandare:* intrebare pentru Marius, nu blocheaza S5.
### Intrebari pentru Marius
1. **Liniile de set (R1)** — le facem needitabile in grid, cu `ID_VANZARE_SET` adaugat in
`VVANZARI_ARTICOLE` printr-un al doilea script? *Recomandarea mea: da.* Fara asta, editarea unei
facturi cu seturi arata ca merge si nu merge.
2. **Discountul de document** — parametru al procedurii (`V_DISCOUNT ... DEFAULT NULL`), sau
`UPDATE VANZARI SET DISCOUNT` separat din VFP? *Recomandarea mea: parametru*, ca discountul si
totalurile sa nu poata diverge (vezi 5).
3. **`PRET_ACHIZITIE` pe linia noua (R3)** — se citeste din nomenclator/stoc la adaugare, sau se
scrie `0` cu avertizare? *Recomandarea mea: citit din nomenclator*, cu `0` doar ca ultima
rezerva, niciodata NULL.
4. **`VALVAL`/`TVAVAL`/`TOTVAL`** — raman in recalcul? *Recomandarea mea: da* (cost zero, fac parte
din acelasi `SELECT`; excluderea lor ar lasa facturile in valuta inconsistente). Confirmare
ceruta si in raportul precedent, inca neconfirmata.
5. **`ff_2026_08_08_01_COMUN_VVD_TOT.sql`** — script de lucru abandonat, sau lipseste din SVN?
---
## Ce a ramas neverificat
- **R5**: nu am verificat pe codul S4 in lucru ca `CreeazaPoArticolNouTvd` primeste efectiv valuta
documentului pe toate caile de adaugare de linie.
- Nu am rulat nimic in Oracle in afara de `SELECT`-uri de dictionar si de export — **niciun DDL,
niciun DML, niciun test de executie a procedurii propuse.** Corpul propus la 7 e schita, nu cod
compilat.
- Numarul de documente cu seturi in `MARIUSM_AUTO` (4) e din date de test si **nu constituie
dovada** pentru niciuna dintre afirmatiile de mai sus; toate concluziile sunt din cod.

View File

@@ -1,9 +1,9 @@
# S5 — testul cu scriere reala in Oracle. Rezultat
Aprobat de Marius (09.08.2026, consemnat in `docs\handoff_s5.md`). Suita:
Aprobat de Marius (09.08.2026, consemnat in handoff intermediar (sters)). Suita:
`COMUN\utile\Teste\editare_factura\test_s5_scriere_reala.prg`. Log:
`COMUN\utile\Teste\editare_factura\test_s5_scriere_reala_log.txt` (rulare 09.08.2026 23:41:32-23:41:35).
Diff: `docs\diff_s5_test_scriere_reala.patch`.
Diff: diff aplicat (sters).
## Rezultat

View File

@@ -1,296 +0,0 @@
# Verificare script Oracle S5 — PACK_FACTURARE.recalculeaza_totaluri_vanzari
Data: 09.08.2026. Livrabil: `docs/ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (823433 octeti,
17231 randuri; 17010->17231 fata de `.pck`-ul sursa, +221 randuri de continut adaugat).
Construit programatic dintr-un script PowerShell (nu retastat): citeste `PACK_FACTURARE.pck`
(export proaspat, scratchpad, 810960 octeti, 17011 randuri) ca octeti ASCII, insereaza declaratia
noua in SPEC dupa `actualizeaza_vanzari` si corpul nou in BODY dupa `actualizeaza_vanzari`, adauga
`CREATE OR REPLACE` pe cele doua linii de start (absente in exportul brut din `all_source`),
antetul si coada, si scrie rezultatul CRLF. Fiecare punct de insertie e verificat printr-un
assert pe textul exact al ancorei (throw daca nu se potriveste) — scriptul s-a oprit si a fost
corectat de doua ori in timpul lucrului (vezi „Erori prinse" mai jos), rularea finala a trecut
toate ancorele.
## Ce s-a facut
1. **PACKAGE SPEC** (`.pck:1187-1189`): dupa declaratia `actualizeaza_vanzari`, s-a inserat
`PROCEDURE recalculeaza_totaluri_vanzari(V_ID_VANZARE IN NUMBER, V_DISCOUNT IN NUMBER DEFAULT
NULL);` — text identic cu cel din brief.
2. **PACKAGE BODY** (`.pck:16015-16025`, dupa `END actualizeaza_vanzari;`): s-a inserat procedura
noua, corpul fiind blocul de agregare din `scrie_in_vanzari` (`.pck:13762-13954`) cu substitutiile
cerute, plus SELECT-ul de discount/in_valuta/discount_evidentiat inainte, plus `discount` in
UPDATE, fara handler de exceptie — toate exact ca in sectiunea 7 a specificatiei.
3. Antet de 6 randuri (4 randuri text + 1 rand `--` gol + titlu), fara referinte la planuri/rapoarte.
4. Coada: `exec pack_migrare.UpdateVersiune('ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql'); commit;`
## Verificari cerute, cu cifre
**CRLF** — octeti LF fara CR inainte in fisierul final: **0**.
**Nume sub 30 caractere** — `'recalculeaza_totaluri_vanzari'.Length` = **29**. Confirmat.
**Diff-ul blocului de agregare** — original (`.pck:13762-13954`, 193 randuri, citat integral in
`rec_s5_proiectare_oracle.md` sectiunea 2) vs. blocul nou din procedura (extras din fisierul
livrat). Generat cu `diff -u -b` (ignora *doar* diferentele de cantitate de spatiu — necesar
pentru ca tot blocul a fost mutat cu un nivel de indentare mai putin, vezi nota de mai jos; `-b`
nu ascunde nicio diferenta de continut). Diff-ul integral:
```diff
--- orig_block.txt (PACK_FACTURARE.pck:13762-13954)
+++ new_block.txt (recalculeaza_totaluri_vanzari, corpul agregarii)
@@ -1,5 +1,4 @@
- -- Completare totaluri in vanzari din vanzari_detalii pentru a usura selectiile din fact_vfacturi
- begin
+-- Completare totaluri in vanzari din vanzari_detalii pentru a usura selectiile din fact_vfacturi
select DISC_TVA_VAL AS DISCOUNT_TVA,
VALOARE_ACHIZITIE,
a.suma_fara_tva_ron - a.disc_fara_tva_ron as TOTAL_FARA_TVA,
@@ -12,11 +11,7 @@
a.disc_tva_val as TOTVAL,
id_valuta,
curs,
- multiplicator,
- pack_facturare.cserie_act_incasare as SERIE_INCASAT,
- pack_facturare.nnumar_act_incasare as NR_INCASAT,
- pack_facturare.nsuma_incasare AS SUMA_INCASAT,
- pack_facturare.ntip_doc_incasare as TIP_INCASAT
+ multiplicator
INTO lnDiscountTVA,
lnValoareAchizitie,
lnTotalFaraTVA,
@@ -27,29 +22,25 @@
lnTotVal,
lnIdValuta,
lnCurs,
- lnMultiplicator,
- lnSerieIncasat,
- lnNrIncasat,
- lnSumaIncasat,
- lnTipIncasat
- FROM (select MAX(decode(pack_facturare.nin_valuta,
+ lnMultiplicator
+ FROM (select MAX(decode(lnInValuta,
1,
- ROUND(a1.curs * NVL(V_DISCOUNT_FACTURA, 0) /
+ ROUND(a1.curs * NVL(lnDiscountFactura, 0) /
a1.multiplicator,
lnPreciziePretV),
- NVL(V_DISCOUNT_FACTURA, 0))) as DISC_FARA_TVA_RON,
- NVL(V_DISCOUNT_FACTURA, 0) as DISC_FARA_TVA_VAL,
- pack_facturare.nin_valuta AS IN_VALUTA,
- MAX(ROUND(decode(pack_facturare.nin_valuta,
+ NVL(lnDiscountFactura, 0))) as DISC_FARA_TVA_RON,
+ NVL(lnDiscountFactura, 0) as DISC_FARA_TVA_VAL,
+ lnInValuta AS IN_VALUTA,
+ MAX(ROUND(decode(lnInValuta,
1,
ROUND(a1.curs *
- NVL(V_DISCOUNT_FACTURA, 0) /
+ NVL(lnDiscountFactura, 0) /
a1.multiplicator,
lnPreciziePretV),
- NVL(V_DISCOUNT_FACTURA, 0)) *
+ NVL(lnDiscountFactura, 0)) *
(a1.proc_tvav - 1),
lnPreciziePretV)) as DISC_TVA_RON,
- MAX(ROUND(NVL(V_DISCOUNT_FACTURA, 0) *
+ MAX(ROUND(NVL(lnDiscountFactura, 0) *
(a1.proc_tvav - 1),
lnPreciziePretV)) as DISC_TVA_VAL,
sum(pack_facturare.calculeaza_total_fara_tva_fact(a1.pret_ron,
@@ -57,7 +48,7 @@
1,
NVL(a1.discount_unitar_ron,
0),
- pack_facturare.ndiscount_evidentiat,
+ lnDiscountEvidentiat,
a1.cantitate,
a1.pret_cu_tva,
a1.proc_tvav)) AS SUMA_FARA_TVA_RON,
@@ -66,7 +57,7 @@
1,
NVL(a1.discount_unitar_ron,
0),
- pack_facturare.ndiscount_evidentiat,
+ lnDiscountEvidentiat,
a1.cantitate,
a1.pret_cu_tva,
a1.proc_tvav)) as SUMA_TVA_RON,
@@ -75,7 +66,7 @@
1,
NVL(a1.discount_unitar_val,
0),
- pack_facturare.ndiscount_evidentiat,
+ lnDiscountEvidentiat,
a1.cantitate,
a1.pret_cu_tva,
a1.proc_tvav)) AS SUMA_FARA_TVA_VAL,
@@ -84,18 +75,18 @@
1,
NVL(a1.discount_unitar_val,
0),
- pack_facturare.ndiscount_evidentiat,
+ lnDiscountEvidentiat,
a1.cantitate,
a1.pret_cu_tva,
a1.proc_tvav)) as SUMA_TVA_VAL,
sum(round(a1.cantitate * a1.pret_achizitie,
lnPrecizieCalcul)) AS VALOARE_ACHIZITIE,
- max(decode(pack_facturare.nin_valuta, 1, a1.id_valuta, 0)) as id_valuta,
- max(decode(pack_facturare.nin_valuta, 1, a1.curs, 1)) as curs,
- max(decode(pack_facturare.nin_valuta, 1, a1.multiplicator, 1)) as multiplicator
+ max(decode(lnInValuta, 1, a1.id_valuta, 0)) as id_valuta,
+ max(decode(lnInValuta, 1, a1.curs, 1)) as curs,
+ max(decode(lnInValuta, 1, a1.multiplicator, 1)) as multiplicator
from (select vd.id_vanzare_set,
(case
- when (pack_facturare.nin_valuta = 1 or
+ when (lnInValuta = 1 or
vd.id_valuta <>
pack_def.GetIdMonedaNationala()) then
ROUND(vc.curs * vd.pret / vc.multiplicator,
@@ -108,7 +99,7 @@
vd.cantitate,
vd.diferenta,
(case
- when (pack_facturare.nin_valuta = 1 or
+ when (lnInValuta = 1 or
vd.id_valuta <>
pack_def.GetIdMonedaNationala()) then
ROUND(vc.curs * vd.discount_unitar /
@@ -132,8 +123,10 @@
a.id_valuta,
a.pret_cu_tva,
a.pret_achizitie
- from VANZARI_DETALII_TEMP a
+ from VANZARI_DETALII a
where nvl(a.id_vanzare_set, 0) = 0
+ and a.id_vanzare = V_ID_VANZARE
+ and a.sters = 0
union all
select b.id_vanzare_set,
b.pret,
@@ -141,7 +134,7 @@
b.cantitate,
0 as diferenta,
b.discount_unitar,
- decode(pack_facturare.nin_valuta,
+ decode(lnInValuta,
0,
pack_def.GetIdMonedaNationala(),
c.id_valuta) as id_valuta,
@@ -151,17 +144,19 @@
0,
c.pret_achizitie * c.cantitate /
b.cantitate)) as pret_achizitie
- from vanzari_detalii_temp c
+ from vanzari_detalii c
left join vanzari_seturi b
on b.id_vanzare_set = c.id_vanzare_set
where nvl(c.id_vanzare_set, 0) <> 0
- and nvl(pack_facturare.nin_valuta, -1) > -1
+ and c.id_vanzare = V_ID_VANZARE
+ and c.sters = 0
+ and nvl(lnInValuta, -1) > -1
group by b.id_vanzare_set,
b.pret,
b.cantitate,
b.discount_unitar,
b.pret_cu_tva,
- decode(pack_facturare.nin_valuta,
+ decode(lnInValuta,
0,
pack_def.GetIdMonedaNationala(),
c.id_valuta)) vd
@@ -170,7 +165,8 @@
and vd.id_valuta = vc.id_valuta) a1) a;
update vanzari
- set discount_tva = lnDiscountTVA,
+ set discount = lnDiscountFactura,
+ discount_tva = lnDiscountTVA,
valoare_achizitie = lnValoareAchizitie,
total_fara_tva = lnTotalFaraTVA,
total_tva = lnTotalTVA,
@@ -180,14 +176,5 @@
totval = lnTotVal,
id_valuta = lnIdValuta,
curs = lnCurs,
- multiplicator = lnMultiplicator,
- serie_incasat = lnSerieIncasat,
- nr_incasat = lnNrIncasat,
- suma_incasat = lnSumaIncasat,
- tip_incasat = lnTipIncasat
+ multiplicator = lnMultiplicator
where id_vanzare = V_ID_VANZARE;
-
- exception
- when NO_DATA_FOUND then
- null;
- end;
```
Diff-ul contine **exact**: cele 6 substitutii din tabelul din brief (`nin_valuta`->`lnInValuta` x11,
`ndiscount_evidentiat`->`lnDiscountEvidentiat` x4, `NVL(V_DISCOUNT_FACTURA, 0)`->
`NVL(lnDiscountFactura, 0)` x6, cele doua perechi FROM/WHERE), eliminarea celor 4 coloane de
incasare din SELECT/INTO/UPDATE (cu fixarea virgulei ramase), adaugarea `discount =
lnDiscountFactura,` in UPDATE si eliminarea wrapper-ului `begin ... exception ... end;` (cerut
explicit: „Fara handler WHEN NO_DATA_FOUND THEN NULL"). **Nicio alta diferenta de continut.**
Nota pe metoda: `-b` a fost necesar (nu `diff` simplu) pentru ca tot blocul, o data scos din
`begin...end;`-ul intern, a coborat cu un nivel de indentare (2 spatii) — o consecinta mecanica,
uniforma, a aplatizarii cerute de sectiunea 7, nu o modificare de continut. Fara `-b`, diff-ul ar
fi aratat *toate* liniile ca schimbate, desi doar spatiul de inceput difera pe liniile
neatinse de tabelul de substitutii (verificat separat: liniile fara nicio substitutie, ex.
`select DISC_TVA_VAL AS DISCOUNT_TVA,`, `VALOARE_ACHIZITIE,`, nu apar deloc in diff-ul de mai sus).
**`;` in comentarii `--` in interiorul unei instructiuni** — 11 aparitii ale tiparului `--.*;` in
tot fisierul, **toate preexistente** in codul neatins (`scrie_incasari`, `contabilizeaza_articol`
etc., linii 5908-14852 din script), **niciuna** introdusa de mine (verificat separat: 0 in antetul
nou, 0 in declaratia SPEC noua, 0 in corpul noii proceduri). Riscul descris in
`scripturi-migrare-db.md` (SP2-0734) se aplica instructiunilor SQL terminate cu `;`
(`CREATE VIEW` etc.); intregul script de fata e un singur bloc `CREATE OR REPLACE PACKAGE`/
`PACKAGE BODY` terminat cu `/`, deci riscul nu se aplica structural — dar cifra e cea ceruta.
**Constructii peste Oracle 10.2** — scanat corpul noii proceduri pentru
`LISTAGG|CONTINUE|REGEXP_COUNT|FETCH FIRST|PIVOT|NEXTVAL`: **0 aparitii** pentru fiecare.
Identificatori: cel mai lung e `recalculeaza_totaluri_vanzari` (29) si `lnDiscountEvidentiat` (20)
— niciunul peste 30.
**Numarul de linii** — fisier final: **17231** (17230 dupa convenția `wc -l`, care nu numara
ultimul rand fiindca fisierul, la fel ca sursa, nu are newline final); `.pck` original:
**17011** (17010 `wc -l`). Delta: +221 randuri adaugate (antet 7 + insert SPEC 3 + rand gol inainte
de `CREATE OR REPLACE PACKAGE BODY` 1 + procedura noua in BODY 205 + coada 4 + `CREATE OR REPLACE`
adaugat pe 2 linii existente, fara linii noi acolo).
**Coloanele de incasare** — `serie_incasat`, `nr_incasat`, `suma_incasat`, `tip_incasat`: **0**
aparitii in SELECT/INTO/UPDATE-ul noii proceduri (verificat separat, izolat pe textul extras al
procedurii). Apar in continuare de 5 ori fiecare **in restul fisierului** — in `scrie_in_vanzari`,
neatinsa, unde e corect sa ramana (comportamentul de emitere nu se schimba).
## Erori prinse si corectate in timpul lucrului (nu au ajuns in fisierul livrat)
1. Prima rulare a omis complet linia `discount = lnDiscountFactura,` din `UPDATE` (am copiat doar
eliminarea coloanelor de incasare, am uitat adaugarea cerincetei separat in brief). Prins de
verificarea numerica (`lnDiscountFactura` aparea de 8 ori in loc de 9) inainte de a scrie
raportul; corectat si re-rulat.
2. Prima rulare a scris `PACKAGE "PACK_FACTURARE" is` si `PACKAGE BODY PACK_FACTURARE is` fara
prefixul `CREATE OR REPLACE` pe **linia de SPEC** (l-am adaugat doar pe linia de BODY). Ar fi
dat eroare de sintaxa la aplicare — `PACKAGE ... is` singur nu e o instructiune DDL valida.
Prins prin citirea directa a antetului fisierului scris; corectat si re-rulat.
## Ce NU am facut / neverificat
- Nu am rulat nimic in Oracle — niciun `sqlplus`, niciun DDL, niciun test de compilare a
pachetului. Corectitudinea sintactica dincolo de verificarile de mai sus (paranteze, virgule,
cuvinte cheie) nu e garantata decat prin inspectie si prin construirea mecanica din blocul
original deja compilat.
- Coada scriptului foloseste `UpdateVersiune('ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql')` **cu**
extensia `.sql`, asa cum cere explicit brief-ul si `scripturi-migrare-db.md` („script_final =
numele fisierului, cu tot cu .sql"). Modelul citat (`ff_2026_08_06_10_...sql:17019`) foloseste
de fapt numele **fara** `.sql` — o inconsistenta intre precedent si regula scrisa. Am urmat
regula scrisa si instructiunea explicita, nu precedentul; semnalez discrepanta, nu am
„reparat-o" in modelul vechi (nu era in scop).
- Nu am atins `versiune_db.txt`, nu am scris in `D:\ROA\DATABASE\SCRIPTURI_CLAR`, nu am dat
commit — conform interdictiilor din brief.

View File

@@ -1,8 +1,8 @@
# S5 — acoperirea de teste pentru scrierea articolelor (decizii 38-41)
Raport de testare pentru functionalitatea S5 (`docs\handoff_s5.md`), care nu avea niciun test la
Raport de testare pentru functionalitatea S5 (handoff intermediar (sters)), care nu avea niciun test la
inceputul acestei lucrari. Trei fisiere de test atinse, toate in
`COMUN\utile\Teste\editare_factura\`, plus diff-ul: `docs\diff_s5_teste.patch`.
`COMUN\utile\Teste\editare_factura\`, plus diff-ul: diff aplicat (sters).
Niciun fisier de productie nu a fost atins (`omodificari.vc2`, `ofacturare_editare.prg`,
`ofacturare_comun.vc2`, `comun.vc2`, `ofacturare.vc2` — toate neschimbate de acest agent). Nu s-a
@@ -151,7 +151,7 @@ mtime):
\* cifra `raport_teste.ps1` (regex pe inceput de linie — subraporteaza pentru aceasta suita
specifica, vezi mai jos). \*\* cifra reala, numarata ca ocurente literale `PASS`/`FAIL` in log —
aceasta e conventia din `docs\handoff_s5.md` ("test_page3_articole 14/2"), verificata identica
aceasta e conventia din handoff intermediar (sters) ("test_page3_articole 14/2"), verificata identica
inainte si dupa editarea mea.
**Atentie separata pentru viitor**: `raport_teste.ps1` numara doar liniile care incep cu
@@ -162,12 +162,12 @@ deja in cod dinainte), dar inseamna ca **pentru `test_page3_articole`, raportul
incredere** — verificarea trebuie facuta manual (`grep -o PASS/FAIL`, cum s-a facut aici), nu doar
cu `raport_teste.ps1`.
Toate celelalte suite: identice cu baseline-ul din `docs\handoff_s5.md`, nicio regresie.
Toate celelalte suite: identice cu baseline-ul din handoff intermediar (sters), nicio regresie.
## F. Ce nu s-a acoperit si de ce
- **Test cu scriere reala in Oracle** (aprobat de Marius pentru S5, dar separat de mandatul acestui
agent — interzis explicit sa scrie in baza) — ramane pentru o lucrare ulterioara, dupa modelul
`test_writeback_buton1.prg`.
- **R5** (linie cu valuta fara rand in `VANZARI_CURSURI`) — ramane deschis din `handoff_s5.md`, nu
- **R5** (linie cu valuta fara rand in `VANZARI_CURSURI`) — ramane deschis din handoff intermediar (sters), nu
s-a adaugat un test nou pentru el, in afara mandatului de "validari + helper + grid".

View File

@@ -15,7 +15,7 @@ inainte. Nu e nevoie de reparatie — nu exista defect.
Sursa: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (fisierul
real aplicat in baza, nu un export `all_source` — capcana deja platita in S5, vezi
`docs\handoff_s5.md`).
handoff intermediar (sters)).
**1. `ACT_TEMP` e tabela de lucru (scratch), golita automat la fiecare COMMIT/ROLLBACK.**
Verificat direct din dictionar, nu presupus:
@@ -27,7 +27,7 @@ select table_name, temporary, duration from all_tables where table_name in ('ACT
```
Un GTT cu `DURATION = SYS$TRANSACTION` se goleste singur la finalul TRANZACTIEI curente. Decizia 38
(`docs\handoff_s5.md`, deja testata cu scriere reala in S5) stabileste ca **fiecare editare ruleaza
(handoff intermediar (sters), deja testata cu scriere reala in S5) stabileste ca **fiecare editare ruleaza
intr-o singura tranzactie manuala, incheiata cu COMMIT** — deci `ACT_TEMP` porneste mereu **goala**
la inceputul fiecarei editari; nu poate purta randuri dintr-o editare anterioara.
@@ -183,7 +183,7 @@ consistent cu punctul 4 din dovada pe cod (blocul vechi se retrage integral).
## Date de test consumate
Continuare pe **`id_vanzare = 1049`** (deja in lucru din S5, `docs\handoff_punct6_dupa_s5.md`):
Continuare pe **`id_vanzare = 1049`** (deja in lucru din S5, handoff intermediar (sters)):
`cod` realocat suplimentar **1140900 -> 1140901 -> 1140902 -> 1140903** (prima rulare, cu interogarea
de numarare gresita — pastrata doar ca generatie reala, nu s-a revenit peste ea) **-> 1140904 ->
1140905 -> 1140906** (rularea finala, cea raportata mai sus). **Cod curent: `1140906`.** Niciun

View File

@@ -1,131 +0,0 @@
# S8 — Inventar pe tipuri de sursa. Rezultat
Cerinta din plan (`docs\plan_06_editare_factura.md:282-291`): test pe fluxul real, cate un caz din
fiecare tip de sursa (lista de preturi, comanda, contract, aviz), fiecare rulat **de doua ori** (o
data din ROAFACTURARE, o data din registrul jurnal ROACONT), plus un al treilea caz obligatoriu — un
document care nu e factura, deschis din jurnal (**deja acoperit**, testul de garda
`ofacturare_editare.prg` scos din `SET PROCEDURE` -> `PageCount = 2`).
Faza de fata e **inventar, READ-ONLY**: doar `SELECT` si un apel de functie PL/SQL
(`pack_documente.ReferinteDocumenteNota`, functie de citire, fara `INSERT`/`UPDATE`/`COMMIT`).
Zero scriere, zero editare de documente, zero modificare de cod.
## Verdict
**Matricea completa NU e realizabila azi.** Doar tipul **lista de preturi** are documente eligibile
in luna curenta (august 2026) — 3 documente, din care **2 sunt deja indisponibile** (consumate/baza
de regresie in lucrari anterioare). Ramane **un singur candidat neatins**: `id_vanzare=1048`.
Celelalte trei tipuri — **comanda, contract, aviz** — au **zero documente in luna curenta**. Nu e o
limitare de cod sau de garda: nu exista niciun document de acel tip datat in august 2026, in toata
`MARIUSM_AUTO`. Cea mai recenta factura pe comanda e din 26.03.2026, pe contract din 30.06.2026, iar
pe aviz (`tip=4`, "FACT. DIN AVIZ") din **30.11.2023**. Nu se fabrica date.
## 1. Cum se determina „tipul de sursa" — dovada pe cod
`VANZARI.TIP` — mapat explicit in `COMUN\clase\ofacturare.vc2`, atat in configurarea UI a
formularului de facturare (`frm_facturare_articole.Init`, `Do Case` pe `poDate.tip`, `:15122-15153`)
cat si in constantele denumite din `do_copiaza` (`:3628-3681`):
| Tip sursa (cerut de S8) | `VANZARI.TIP` | Eticheta din cod | Sursa |
|---|---|---|---|
| lista de preturi | `1, 5, 7, 10` | POLITICA PRETURI (lei / invoice / credit note / factura valuta) | `ofacturare.vc2:15122-15123`, `:3629-3632` |
| contract | `2, 6` | CONTRACT / CONTRACT - VALUTA | `ofacturare.vc2:15129-15130`, `:3638`, `:3658` |
| comanda | `3` | COMANDA | `ofacturare.vc2:15144-15145`, `:3639` |
| aviz | `4` | FACT. DIN AVIZ (factura emisa pe baza unui aviz anterior) | `ofacturare.vc2:15151-15152`, `:3640` |
Se mapeaza curat pe un singur camp (`VANZARI.TIP`), fara ambiguitate. Precizari:
- Tipurile `21/22/23/24/25/26/28/29/41` etc. sunt **avize propriu-zise sau transferuri** (documente
separate, nu facturi cu sursa aviz) — nu intra in matrice, pentru ca S8 cere editarea unei
**facturi**, nu a unui aviz.
- `tip=-12` (facturi din ROAAUTO, devize auto) e alt caz, deja documentat separat in
`docs\cercetare\roaauto_facturi.md` — nu face parte din cele patru tipuri cerute de plan.
- Contractul (`2,6`) are azi acces liber la lista de preturi in dialogul de adaugare articole
(`docs\cercetare\retur_si_lista_preturi.md`, sectiunea B), dar asta nu schimba clasificarea sursei
— clasificarea e pe `VANZARI.TIP`, nu pe ce se poate adauga ulterior.
## 2. Cate documente exista, per filtru — cifre pe `MARIUSM_AUTO`
Garda de editare cumulata (varianta strictă, `frm_facturi.do_editare_factura`,
`ofacturare_comun.vc2:3715-3872`): `sters=0`, `eproforma<>1`, luna curenta (`data_act` in august
2026), fara linii din seturi (`id_vanzare_set` nenul pe nicio linie activa), fara referinte
(`pack_documente.ReferinteDocumenteNota`), netrimisa in eFactura (`anaf_efactura.id_fact`).
| Pas / filtru | lista de preturi | contract | comanda | aviz |
|---|---|---|---|---|
| 1. `sters=0`, tip in grup, luna curenta (08.2026) | **3** | 0 | 0 | 0 |
| 2. + `eproforma<>1` | 3 (neschimbat) | 0 | 0 | 0 |
| 3. + fara linii din seturi | 3 (neschimbat) | 0 | 0 | 0 |
| 4. + fara referinte incasari/plati | 3 (neschimbat) | 0 | 0 | 0 |
| 5. + netrimis in eFactura (**eligibil final**) | **3** | 0 | 0 | 0 |
Niciun filtru nu a eliminat vreun document din grupul „lista de preturi" — cele 3 existente treceau
deja toate gardele. Pentru celelalte trei tipuri, blocajul e la pasul 1: **nu exista document in
luna curenta**, deci pasii 2-5 sunt irelevanti (cifra ramane 0, nu se pierde nimic pe drum).
**Istoric, ca sa se vada ca nu e o problema de cautare**: `comanda` are 38 de facturi nesterse in
total (cea mai recenta 26.03.2026), `contract` 23 (cea mai recenta 30.06.2026), `aviz` doar 5 in tot
istoricul (cea mai recenta **30.11.2023**) — tipul `aviz` (facturare directa dintr-un aviz emis, fara
trecere prin lista de preturi/comanda/contract) e practic neutilizat de câţiva ani, nu doar in luna
curenta.
**Al doilea punct de intrare (ROACONT/`afisjurcom.do_modifica`, `comun.vc2:2222-2572`)**: garda e
mai laxa — verifica doar luna curenta si `id_set` in afara intervalului `[30000,30009]` (rezervat
ROAPRODUCTIE); nu verifica `eproforma`, referinte sau eFactura (vezi `handoff_punct6_dupa_s5.md`,
confirmat din nou pe cod la aceasta cercetare). Verificat pe cei 3 candidati lista de preturi:
`id_set=25010` pentru toti trei (an=2026, luna=8) — in afara intervalului interzis, deci **toti trei
trec si garda ROACONT**. Cum niciun filtru specific ROAFACTURARE (eproforma/referinte/eFactura) n-a
eliminat vreun document din cele 3, garda mai laxa a jurnalului **nu aduce candidati suplimentari**
pentru lista de preturi — si, evident, nu poate aduce candidati pentru comanda/contract/aviz, unde
blocajul e lipsa documentului insusi (ambele puncte de intrare cer luna curenta).
## 3. Lista concreta de candidati propusi
| Tip sursa | `id_vanzare` | `cod` | `id_fact` | Stare | De ce |
|---|---|---|---|---|---|
| lista de preturi | **1048** | 1140894 | 8009658 | **neatins, eligibil** | 1 linie activa, fara valuta (`in_valuta=0`), `discount=0`, client RAJA (`id_part=463`) — document simplu, curat, tip=1 |
| lista de preturi | 1049 | 1140906 (curent) | 8009659 | eligibil pe cod, dar **deja consumat** | documentul de test S5/S7 — `cod` realocat de 8 ori, folosit intentionat ca baza de continuitate; nu se reia pentru S8 fara sa se stie ca istoricul lui e deja incarcat |
| lista de preturi | 1050 | 1140895 | 8009660 | eligibil pe cod, dar **interzis explicit** | „baza suitelor de regresie — nu se atinge" (`handoff_punct6_dupa_s5.md`) |
| contract | — | — | — | **zero** | niciun document `tip in (2,6)` in august 2026 (cel mai recent 30.06.2026) |
| comanda | — | — | — | **zero** | niciun document `tip=3` in august 2026 (cel mai recent 26.03.2026) |
| aviz | — | — | — | **zero** | niciun document `tip=4` in august 2026 (cel mai recent **30.11.2023**) |
**Singurul candidat utilizabil pentru matrice, azi: `id_vanzare=1048` (lista de preturi).** Pentru
comanda/contract/aviz nu exista alternativa in luna curenta — orice executie ar cere fie asteptarea
pana quando apare un document nou de acel tip in perioada curenta, fie o decizie explicita de a
relaxa criteriul „luna curenta" (schimbare de scop, nu de agent).
## 4. Ce ar consuma executia matricei (daca se aproba)
- **Un singur `cod` disponibil de consumat**: `id_vanzare=1048`, `cod=1140894`. Fiecare trecere prin
fluxul de editare realoca `cod` ireversibil (pattern confirmat empiric in S5/S7: 8 realocari pe
`id_vanzare=1049`). Testarea „de doua ori" (ROAFACTURARE + ROACONT) ar realoca `cod`-ul cel putin
**de doua ori** pe acest document.
- **Comanda/contract/aviz**: executie **imposibila** azi, indiferent de aprobare — nu exista document
de consumat. Singura cale de a acoperi aceste trei tipuri e sa apara documente noi in productie in
luna curenta, sau o decizie separata de relaxare a scopului (nu s-a luat).
- Al treilea caz obligatoriu (document care nu e factura, din jurnal) — deja acoperit, zero consum
suplimentar.
- Nimic din inventarul de fata nu a consumat date: read-only, zero `INSERT`/`UPDATE`/`COMMIT`.
## Ce NU acopera cercetarea
- `glLunaInchisa` (garda VFP „luna contabila inchisa") nu e verificabila din Oracle — presupusa
deschisa (mediul de test curent), neverificata direct.
- Nu s-a cautat in alte luni/ani pentru un eventual document comanda/contract/aviz care sa fi ramas
needitat din alt motiv — cerinta explicita a fost „luna curenta", conform gardei reale de editare.
- Coloana `VANZARI.ID_VANZARE_SET` nu exista direct pe `VANZARI` — verificarea „fara linii din
seturi" s-a facut pe `VANZARI_DETALII.ID_VANZARE_SET` (linii active), consistent cu decizia 39
(`handoff_s5.md`).
## Date de test — NIMIC consumat
Interogari `SELECT` + un apel de functie PL/SQL de citire (`pack_documente.ReferinteDocumenteNota`).
Zero `INSERT`/`UPDATE`/`DELETE`/`COMMIT`. `id_vanzare=1049` si `1050` — neatinse, doar citite.
`id_vanzare=1048` — doar citit, nu editat; ramane candidatul propus pentru executia viitoare.
## Fisiere atinse
Niciunul de productie. Scripturi `.sql` de interogare, in scratchpad (nu in `docs\`, nu in
`SCRIPTURI_CLAR`) — pur exploratorii, nu fac parte din livrare.

View File

@@ -1,164 +0,0 @@
# S8 — matricea pe tipuri de sursa, cele 4 documente
Test: `COMUN\utile\Teste\editare_factura\test_s8_matrice_surse.prg`, log:
`COMUN\utile\Teste\editare_factura\test_s8_matrice_surse_log.txt` (rescris la fiecare rulare -
cifrele de mai jos sunt citite din log **imediat dupa fiecare rulare**, inainte de a activa
urmatorul document, si verificate independent prin `sqlplus`).
Matricea completa (4 documente) a fost rulata, cate unul pe rand, activat prin `gaCazuriActive` in
`test_s8_matrice_surse.prg`. Codul (`EditeazaDinRoafacturare`/`EditeazaDinRegistruJurnal`/
`VerificaDupaEditare`/`CalculeazaTotaluriS4b`) e neschimbat intre rulari - parametrizarea prin
`id_vanzare` a functionat neschimbata pe toate cele 4 tipuri.
## Sinteza cifrelor `REZULTAT` (autoritare, din log)
| Document | Tip sursa | REZULTAT | FAIL-uri | Cauza FAIL-urilor |
|---|---|---|---|---|
| 1048 | lista de preturi (tip 1) | **44 PASS / 0 FAIL** | - | - |
| 1055 | factura din contract (tip 2) | **44 PASS / 0 FAIL** | - | - |
| 1052 | aviz (tip 22) | **26 PASS / 1 FAIL** | 1 | garda `ReferinteDocumenteNota` blocheaza corect intrarea ROAFACTURARE (constatare, nu defect de test - vezi mai jos) |
| 1054 | factura din aviz (tip 4) | **42 PASS / 2 FAIL** | 2 | `Reccount(trul)=0` pe ambele intrari - normal pentru tip 4 (vezi mai jos), nu defect |
Niciun `EROARE` in niciunul din cele 4 loguri.
## Document 1048 — lista de preturi (tip 1)
Deja raportat integral in versiunea anterioara a acestui document (ambele intrari au reusit complet,
0 anomalii). Stare finala neschimbata de rularile ulterioare pe celelalte documente: `cod=1140918`,
`id_fact=8009658` (neschimbat), totaluri `250.01/52.50/302.51` (neschimbate), 1 linie activa.
## Document 1055 — factura din contract (tip 2)
Ambele intrari au reusit complet (`COMMIT`), fara nicio anomalie in lantul de scriere.
| | inainte | dupa ROAFACTURARE | dupa registrul jurnal |
|---|---|---|---|
| `cod` | 1140911 | 1140919 | **1140920** |
| `id_fact` | 8009680 | 8009680 | 8009680 (neschimbat) |
| totaluri | 200.00 / 42.00 / 242.00 | neschimbate | neschimbate |
| linii active | 2 | 2 | 2 |
`vact_tot`: cod 1140911 si 1140919 (notele vechi) - toate randurile `STERS=1`; cod 1140920 (nota
curenta) - toate randurile `STERS=0`.
**Constatare (nu defect)**: verdictul S4b e **divergent** pe tot parcursul - `ACT=242`, `RUL=121`
(exact jumatate), neschimbat de cele doua editari (`121 -> 121` pe ambele treceri). Verdictul e
etichetat explicit "informativ, nu e eroare" de catre `frm_modific2024` insusi (decizia din S4b:
formularul arata divergenta, nu o blocheaza). Asertiile testului nu presupun `ACT=RUL` - verifica
doar ca fiecare total ramane **concordant fata de inainte de editare**, ceea ce s-a confirmat.
## Document 1052 — aviz (tip 22)
**Nu e factura** - constatare confirmata, exact cum a semnalat briefingul.
### Intrarea ROAFACTURARE (`do_editare_factura`): BLOCATA de garda, corect
```
FAIL ... document fara referinte / netrimis in eFactura [.T.]
```
`ReferinteDocumenteNota(2026, 8, 1140908)` a intors adevarat - verificat direct in Oracle:
`ACT.id_factc = 8009677` (id_fact-ul avizului 1052) exista pe cod=1140910, care e nota lui **1054**
("factura din aviz", emisa din acest aviz). Garda functioneaza exact cum trebuie: **blocheaza
editarea unui document sursa care are deja o factura emisa din el** - nicio scriere nu s-a produs
(verificat: `cod` a ramas `1140908` neschimbat pana la intrarea urmatoare). `EsteInEFactura` nu a
contribuit (`anaf_efactura` nu are randuri pentru `id_fact=8009677`).
Aceasta e o `FAIL` de asertie **asteptata si corecta** - testul a presupus (mostenit din modelul
S5, gandit pentru facturi) ca documentul e editabil; pentru un aviz cu factura deja emisa din el,
nu e. Marcata ca atare, nu ca defect.
### Intrarea registru jurnal ROACONT (`do_modifica`): A REUSIT COMPLET, fara aceeasi garda
```
PASS ... blocul ScrieArticoleFacturaEditate s-a executat pe aceasta cale (garda satisfacuta) [.T.]
PASS ... lantul complet a reusit (COMMIT) [lnSucces=1]
```
**Constatare reala, de raportat lui Marius**: `afisjurcom.do_modifica` (`comun.vc2:2222-2569`) **nu
are garda `ReferinteDocumenteNota`/`EsteInEFactura`** in secventa reprodusa (confirmat deja indirect
de `test_s5_al_doilea_intrare.prg`, dar niciodata exercitata pana acum pe un document care CHIAR are
o referinta reala). Rezultat: editarea prin registrul jurnal a trecut pana la `COMMIT` pe un
document (1052) pe care intrarea ROAFACTURARE l-a blocat explicit din acelasi motiv.
Pe aceasta rulare **fara** consecinta vizibila (editarea nu a modificat nicio linie - doar a
realocat `cod`-ul si a refacut nota; documentul 1054, care il refera, a fost verificat neschimbat:
`cod=1140910`, `id_fact=8009679`, totaluri `252.07/52.93/305.00`, toate identice cu inainte).
Legatura structurala ramane valida pentru ca trece prin `id_fact`/`id_vanzare`, niciodata prin `cod`
(S6, deja inchis). Dar daca editarea prin ROACONT ar fi inclus si o modificare de continut pe un
document cu referinte reale, nimic nu ar fi oprit-o - asimetria intre cele doua puncte de intrare e
reala, nu doar teoretica. **Nu s-a atins `comun.vc2`/`omodificari.vc2` pentru a o corecta** (livrare
inchisa) - se raporteaza pentru decizia lui Marius.
| | inainte | dupa ROAFACTURARE | dupa registrul jurnal |
|---|---|---|---|
| `cod` | 1140908 | *(blocat, nescris)* | **1140921** |
| `id_fact` | 8009677 | - | 8009677 (neschimbat) |
| totaluri | 271.17 / 56.94 / 328.11 | - | neschimbate |
| linii active | 2 | - | 2 |
`vact_tot`: cod 1140908 (nota veche) - toate randurile `STERS=1`; cod 1140921 (nota curenta) -
toate randurile `STERS=0`. S4b: `ACT=RUL=328.11`, verdict sincronizat, neschimbat de editare.
## Document 1054 — factura din aviz (tip 4)
Ambele intrari au reusit complet (`COMMIT`), singurele 2 `FAIL` din aceasta rulare sunt pe
`Reccount(trul)>0`.
**Stabilit inainte de editare, nu ghicit**: interogare pe toate cele 6 documente `tip=4` din baza
(`145, 665, 668, 697, 974, 1054`) - **toate** au exact 2 randuri `ACT` si **0** randuri `RUL`,
indiferent de `total_cu_tva`. Tiparul e 100% consistent pe populatia completa de documente tip 4,
nu doar pe 1054 - **normal pentru tip 4**, nu o particularitate a acestui document. Explicatia
structurala plauzibila: miscarea de stoc s-a inregistrat deja la emiterea avizului sursa; factura
emisa din aviz nu mai genereaza randuri `RUL` proprii (ar dubla miscarea), doar nota contabila
(`ACT`). Cele doua `FAIL` (`Reccount(trul)>0` cerut de asertia generica, `Reccount(trul)=0` gasit)
sunt **asteptate si corecte pentru acest tip de document** - verificarea "rulaje refacute" nu e
concludenta pentru tip 4 (nu exista rulaje de refacut), nu semnaleaza un defect.
Restul verificarilor (nota veche/noua, `id_fact`, totaluri denormalizate, S4b ACT concordant,
stoc) au trecut integral pe ambele intrari.
| | inainte | dupa ROAFACTURARE | dupa registrul jurnal |
|---|---|---|---|
| `cod` | 1140910 | 1140922 | **1140923** |
| `id_fact` | 8009679 | 8009679 | 8009679 (neschimbat) |
| totaluri | 252.07 / 52.93 / 305.00 | neschimbate | neschimbate |
| linii active | 1 | 1 | 1 |
`vact_tot`: cod 1140910 si 1140922 (notele vechi) - toate randurile `STERS=1`; cod 1140923 (nota
curenta) - toate randurile `STERS=0`. S4b: `ACT=305`, `RUL=0`, verdict divergent (informativ),
neschimbat de editare (`305->305`, `0->0`).
## Verdict explicit pe cele 8 verificari cerute de plan (`plan_06_editare_factura.md:286-288`)
| # | Verificare | Verdict pe matrice |
|---|---|---|
| 1 | nota veche `STERS=1` | **PASS** pe toate cele 7 scrieri reusite (1048x2, 1055x2, 1052x1 - ROACONT, 1054x2). N/A pe 1052/ROAFACTURARE (blocat inainte de scriere, nu s-a creat nicio nota noua). |
| 2 | nota noua corecta (exista, activa, acelasi `id_fact`) | **PASS** pe toate cele 7 scrieri reusite. |
| 3 | `id_fact` neschimbat | **PASS** pe toate cele 7 - 8009658, 8009680, 8009677, 8009679 identice inainte/dupa. |
| 4 | `VANZARI`/`VANZARI_DETALII` sincronizate | **PASS** pe toate cele 7 - numar de linii active neschimbat, totaluri coerente (`ftva+tva=ctva`). |
| 5 | totalurile denormalizate corecte | **PASS** pe toate cele 7 - identice cu inainte de editare (reeditare fara modificari de continut). |
| 6 | rulajele refacute | **PASS** pe 1048 (x2), 1055 (x2), 1052 (x1, ROACONT). **FAIL asteptat** pe 1054 (x2) - `RUL=0` e normal pentru tip 4 (confirmat pe toate cele 6 documente tip 4 din baza), verificarea nu e concludenta pentru acest tip. |
| 7 | totalurile de control S4b concordante | **PASS** pe toate cele 7 - `Total ACT` si `Total RUL` raman fiecare **neschimbate fata de inainte de editare**, indiferent daca verdictul absolut e sincronizat (1048, 1052) sau divergent (1055, 1054 - divergenta insasi e preexistenta editarii, nu cauzata de ea). |
| 8 | verificarile de stoc de la emitere NU s-au declansat | **PASS** pe toate cele 7 - `gcMockUltimMesaj` ramas gol dupa fiecare lant de scriere; structural, `verifica_stoc` (`oscrie_in_fisiere.prg:92`) nu se poate declansa pentru ca ambele puncte de intrare trec `tlModificare=.T.`. |
**Al treilea caz obligatoriu** (document care nu e factura, deschis din registru jurnal, fara
pagina de articole) - deja acoperit separat, per handoff (`docs\handoff_punct6_10082026_pm.md:113`).
## Constatare de raportat separat (nu de reparat aici)
**Asimetria de garda intre punctele de intrare** (sectiunea document 1052 de mai sus): intrarea
ROAFACTURARE (`ofacturare_comun.vc2`, `do_editare_factura`) verifica `ReferinteDocumenteNota`/
`EsteInEFactura` inainte de a permite editarea; intrarea registru jurnal ROACONT
(`comun.vc2`, `afisjurcom.do_modifica`) nu are aceasta garda in secventa reprodusa si a scris pana
la capat pe acelasi document pe care ROAFACTURARE l-a blocat. Nicio consecinta vizibila pe aceasta
rulare (editare fara modificari de continut, documentul care refera - 1054 - verificat neschimbat),
dar protectia lipseste structural pe calea ROACONT. `omodificari.vc2`/`comun.vc2` **nu au fost
atinse** (livrari inchise) - decizia (adaugarea gardei si pe ROACONT, sau acceptarea asimetriei) ii
revine lui Marius.
## Ramas de facut
Toate cele 4 documente din matrice au fost editate de doua ori si verificate. Nimic ramas pe
felia S8 in sine. Documentele consumate (coduri realocate, note vechi sterse ireversibil):
1048 (-> 1140918), 1052 (-> 1140921), 1054 (-> 1140923), 1055 (-> 1140920).

View File

@@ -1,7 +1,7 @@
# S9 — documentatia fluxului de editare a facturii, adaugata in flux-modificare-stergere-nota-jurnal.md
Fisier editat: `D:\ROA\ROAGEST\COMUN\docs\flux-modificare-stergere-nota-jurnal.md`.
Diff salvat: `D:\ROA\ROAFACTURARE\docs\diff_s9_flux_nota_jurnal.patch`.
Diff salvat: diff aplicat (sters).
**Nimic comis** (nici git, nici SVN) - `COMUN` e dublu-versionat SVN+git, `git stash` acolo e
interzis; nu s-a folosit.
@@ -49,7 +49,7 @@ Doua sectiuni noi, dupa `## Atentie: nu e valabil la fel pentru stergerea simpla
pe care il documenteaza fisierul tinta. L-am scos ca sa nu ingreunez sectiunea cu un subiect
distinct (planul cere explicit doar "ramura de facturi" pe fluxul de modificare/stergere).
- **Actiunea de sincronizare cu enumerarea liniilor vechi->noi** - nu exista inca in cod (S4b
partial, per `docs\handoff_punct6_dupa_s5.md`), n-am documentat ceva nelivrat.
partial, per handoff intermediar (sters)), n-am documentat ceva nelivrat.
- **Eticheta text "linie din set"** - handoff-ul S5 o mentioneaza, dar in cod (grep pe
`omodificari.vc2`) nu exista un literal cu acest text; marcajul e doar vizual, prin
`DynamicForeColor` (culoare distincta). Am scris "culoare distincta", nu "eticheta", ca sa nu
@@ -69,7 +69,7 @@ Doua sectiuni noi, dupa `## Atentie: nu e valabil la fel pentru stergerea simpla
pot spune din documentatie daca e o omisiune ramasa din S1 sau o decizie asumata (planul spune
doar ca "garzile trebuie sa fie in formular sau in codul comun", fara sa specifice care cale
trebuia sa le primeasca). Am documentat faptul, nu l-am calificat drept bug.
2. **Eticheta "linie din set"** mentionata in `handoff_s5.md` (decizia 39) nu exista ca text in cod
2. **Eticheta "linie din set"** mentionata in handoff intermediar (sters) (decizia 39) nu exista ca text in cod
la verificare - posibil ramasa doar la nivel de intentie sau inlocuita de marcajul de culoare in
implementarea finala. N-am putut confirma din git log/istoric fara sa ies din scop; las-o ca
discrepanta cunoscuta intre document de decizie si livrare.

View File

@@ -1,341 +0,0 @@
# Cercetare: TVA calculat vs salvat (#7) + denormalizare VANZARI (#8)
Sursele principale sunt fisierele "curate" din arhiva de migrare Oracle
`D:\ROA\DATABASE\SCRIPTURI_CLAR\...` (nu in working copy VFP git — DDL/PL-SQL nu e versionat in
`ROAFACTURARE`), plus `D:\ROA\ROAFACTURARE\COMUN\clase\ofacturare.vc2` (working copy VFP, text
`.vc2` deja la zi).
Cea mai recenta definitie **completa** a pachetului `PACK_FACTURARE` (COMUN, folosit de toate
produsele ROA care factureaza) e in
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql` (16948 linii).
Toate liniile citate mai jos fara alta mentiune sunt din acest fisier.
---
## SUBIECT A — TVA calculat, nu salvat (#7)
### 1. Structura VANZARI / VANZARI_DETALII (coloane pret/TVA)
Nu exista `CREATE TABLE VANZARI_DETALII` in arhiva cautata (tabela e mai veche decat
`SCRIPTURI_CLAR`, care incepe efectiv din 2009; originea e probabil in
`D:\ROA\DATABASE\SCRIPTURI\2006-2008`, nu am parcurs exhaustiv acel arhiv de migrari vechi).
Coloanele efective au fost confirmate prin utilizarea lor in cod (view-uri + SQL dinamic VFP):
**VANZARI_DETALII** (per linie articol):
- `PRET` — pret unitar (fara/cu TVA, in functie de flag)
- `DIFERENTA` — ajustare pret (folosita in `calculeaza_total_*_fact`)
- `DISCOUNT_UNITAR`
- `CANTITATE`
- `PRET_CU_TVA` — flag NUMBER(1): 1 = pretul de mai sus e cu TVA inclus, 0 = fara TVA
(`ff_2026_07_27_01_FACTURARE.sql:25,43` — `b.pret_cu_tva`)
- `PROC_TVAV` — procent TVA ca multiplicator (ex. 1.19), nu procent brut
(`ff_2026_07_27_01_FACTURARE.sql:26` — `b.proc_tvav`)
- `PRET_ACHIZITIE` (`ff_2026_07_27_01_FACTURARE.sql:105,130`)
- `ID_ARTICOL`, `ID_VALUTA`, `ID_POL` (politica de pret), `SERIE`, `STERS`, `ID_VANZARE`,
`ID_VANZARE_DET` (`ff_2026_07_27_01_FACTURARE.sql:11-76`)
- `TAXCODE` — adaugata `2022\03\ff_2022_03_24_01_COMUN_SAFT.sql:6` (cod taxa SAFT)
- `ID_JTVA_COLOANA_EX` — adaugata `2019\08\ff_2019_08_20_04_COMUN.sql:7`
- `LOT` — adaugata `2024\06\ff_2024_06_04_01_COMUN_FACTURARE.sql:3`
**NU exista** o coloana de TVA calculata/salvata per linie (nici `valoare_tva`, nici
`pret_fara_tva` rezultat) — doar inputurile (`pret`, `pret_cu_tva` flag, `proc_tvav`), confirmand
exact ce zice todo #7: TVA e derivat, nu stocat.
**VANZARI** (antet factura) — coloane denormalizate relevante TVA, toate adaugate prin
`2017\03\ff_2017_03_28_01_FACTURARE.sql:9-38`:
- `DISCOUNT_TVA` — "TVA DISCOUNT (DISCOUNT * MAX(PROC_TVA) ARTICOLE)"
- `TOTAL_FARA_TVA`, `TOTAL_TVA`, `TOTAL_CU_TVA` — totaluri pe document (denormalizate)
- `VALOARE_ACHIZITIE`
- vezi si Subiect B pt. `SERIE_INCASAT`/`NR_INCASAT`/`SUMA_INCASAT`/`TIP_INCASAT`/`AVIZE`
### 2. Unde se calculeaza TVA-ul pe linie — toate locurile
Calculul e centralizat in doua straturi Oracle, apelate de fiecare punct de consum (VFP nu face
calcul TVA local — doar construieste SQL dinamic care cheama functiile Oracle):
- **`PACK_SESIUNE.calculeaza_pret_fara_tva/tva/cu_tva`** — motorul de rotunjire per-unitate de
pret (nu e in `PACK_FACTURARE`; pachetul `PACK_SESIUNE` nu a fost gasit definit separat in
arhiva cautata — cautare punctuala pe cateva luni din 2025/2026, fara succes; probabil e intr-un
script `COMUN_PACK_SESIUNE` mai vechi, netestat exhaustiv).
- **`PACK_FACTURARE.calculeaza_pret`** (linia 14557) — wrapper subtire peste cele 3 functii
`PACK_SESIUNE` de mai sus.
- **`PACK_FACTURARE.calculeaza_sume`** (linia 14631, spec 980) — calculeaza suma_fara_tva /
suma_tva / suma_cu_tva pe linie (cantitate * pret), delegand catre:
- **`calculeaza_total_fara_tva`** (linia 15745/15769) — delega la `pack_sesiune.calculeaza_total_fara_tva`
- **`calculeaza_total_tva`** (linia 15850/15874) — delega la `pack_sesiune.calculeaza_total_tva`
- **`calculeaza_total_cu_tva`** (linia 15638/15662) — delega la `pack_sesiune.calculeaza_total_cu_tva`
- variantele `_fact` (`calculeaza_total_fara_tva_fact` 15794, `calculeaza_total_tva_fact` 15899,
`calculeaza_total_cu_tva_fact` 15687) au **formula proprie inline** (nu delega la
`pack_sesiune`), documentata explicit in cod ca fiind "folosita in view-ul
fact_vrap_centralizator_fact" (comentarii 15686, 15744, 15793, 15848, 15897).
Formula `_fact` (exemplu `calculeaza_total_tva_fact`, 15899-15949) e explicit ROUND-based, cu
ramuri separate pentru `discount_evidentiat` — aici e punctul central de rotunjire per linie.
- **Puncte de CONSUM ale acestor functii** (unde efectiv se calculeaza TVA afisat/raportat):
- Views `fact_vrap_fact_articole` si `fact_vrap_articole_vandute`
(`ff_2026_07_27_01_FACTURARE.sql:18-44, 131-196` — apeleaza
`calculeaza_total_fara_tva`/`calculeaza_total_tva` direct in `SELECT`)
- Raport VFP dinamic: `COMUN\programe\oproceduri_rapoarte_fact.prg:581-590` — SQL construit in
VFP apeleaza direct `pack_sesiune.calculeaza_pret_cu_tva(...)` si
`pack_sesiune.calculeaza_total_cu_tva(...)` pentru listare/relistare rapoarte articole vandute.
- `PACK_FACTURARE.scrie_in_vanzari` (13468) si `finalizeaza_avize_lucrare` (14807) — calculeaza
si scriu `VANZARI.TOTAL_FARA_TVA`/`TOTAL_CU_TVA` folosind `calculeaza_total_fara_tva_fact` in
subquery-uri (13716-13786, 14965-15008).
- `verifica_total_document` (16009) — vezi punctul 5, verifica totalul calculat vs. cel din
notele contabile si genereaza o corectie.
Nu am gasit un apel VFP direct catre `calculeaza_pret(` sau `calculeaza_sume(` in working copy
`ROAFACTURARE`/`COMUN` (grep pe nume exact, fara rezultate) — deci formularul de introducere
factura in VFP nu recalculeaza local pretul/TVA-ul linie cu linie prin apel explicit de
procedura; cel mai probabil articolele + preturile lor (deja cu `pret`, `pret_cu_tva`,
`proc_tvav`) vin dintr-un cursor Oracle (`PACK_FACTURARE.cursor_preturi`, spec 335, body 2121)
populat cand se adauga articolul, iar TVA vizibila in grid e calculata la afisare din acele
coloane brute — nu am gasit expresia VFP exacta (`cursor_preturi` e ~500 linii, nu am parcurs
linie cu linie in bugetul acestei cercetari).
### 3. Ce inseamna "preturi_cu_tva" / `pret_cu_tva`
- Pe linie: `VANZARI_DETALII.PRET_CU_TVA` — NUMBER(1), 0/1, transmis ca parametru `V_PRET_CU_TVA`
/ `V_PRET_ARE_TVA` la toate functiile de calcul de mai sus (controleaza care ramura de formula
se aplica — pornind de la pret cu TVA sau fara TVA).
- In grid-ul VFP exista o coloana **checkbox** `cPret_cu_tva` in
`D:\ROA\ROAFACTURARE\Clase\ofundal_facturare.vc2:696-699` (`_grdrow2.cPret_cu_tva...`) — probabil
afiseaza/permite editarea flagului per linie in formular.
- **Nu am gasit** coloana `PRET_CU_TVA` (sau similara) direct pe `CRM_POLITICI_PRETURI` in
scripturile de migrare cautate (am cautat `ALTER TABLE CRM_POLITICI_PRETURI ADD`, fara hit
pe acest nume) — deci originea exacta a valorii implicite per politica de pret ("politica are
bifat 'preturi fara TVA'", cum descrie todo #7) nu e confirmata cu `fisier:linie`; e probabil
citita/propagata in `PACK_FACTURARE.cursor_preturi` (2121) sau
`citeste_setari_pol_pret` (spec 324, body 2025) cand se adauga articolul pe factura — nu am
parcurs acele corpuri in detaliu (buget de cercetare).
### 4. Locuri de atins daca s-ar salva `pret_cu_tva`/`valoare_tva` per linie real (nu calculat)
Enumerare pe baza punctelor de consum gasite mai sus:
1. **DDL**: `ALTER TABLE VANZARI_DETALII ADD (valoare_tva, pret_fara_tva_calculat, ...)` — coloane
noi + migrare date istorice.
2. **`PACK_FACTURARE`** (Oracle, `ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql`):
- `adauga_articol_factura` (spec 529, body 4972) — punctul unde se insereaza linia in
`VANZARI_DETALII_TEMP`; ar trebui sa scrie valoarea (eventual editata de user) in loc s-o
lase doar pe `pret`/`pret_cu_tva`/`proc_tvav`.
- `calculeaza_sume` (14631) — daca valoarea e editabila, aceasta procedura ar trebui sa
citeasca valoarea salvata in loc s-o recalculeze, sau sa fie ocolita.
- `scrie_in_vanzari` (13468) si `finalizeaza_avize_lucrare` (14807) — subquery-urile care insumeaza
`calculeaza_total_fara_tva_fact`/`calculeaza_total_tva_fact` pe toate liniile
(13716-13786, 14965-15008) ar trebui sa insumeze coloana noua in loc s-o recalculeze.
- `verifica_total_document` (16009) — logica de reconciliere total-vs-note-contabile ar trebui
ajustata (vezi punct 5) daca totalul nu se mai deriva strict din formula.
3. **Views Oracle**: `fact_vrap_fact_articole`, `fact_vrap_articole_vandute`
(`ff_2026_07_27_01_FACTURARE.sql:10-257`), `fact_vfacturi`/`fact_vfacturi2` (vezi Subiect B #11)
— toate ar trebui sa citeasca noua coloana in loc de `calculeaza_total_*`.
4. **VFP**: `COMUN\programe\oproceduri_rapoarte_fact.prg:581-590` — SQL-ul de raport care apeleaza
direct `pack_sesiune.calculeaza_pret_cu_tva`/`calculeaza_total_cu_tva`.
5. **VFP grid formular**: `D:\ROA\ROAFACTURARE\Clase\ofundal_facturare.vc2` (coloana
`cPret_cu_tva` + coloanele de pret/valoare din grid — nu identificate exhaustiv, cautare
punctuala doar pe flag).
6. **Rapoarte `.frx`** care afiseaza TVA pe linie de factura (ex. `usr_factura*.fr2` — 25 de
fisiere gasite cu referinta la `PACK_FACTURARE`, listate la cautarea initiala; nu au fost
deschise individual).
Estimare: minim **6 zone distincte** (DDL, pachet Oracle ~4 proceduri, 3-4 views, 1 program raport
VFP, grid formular, rapoarte `.frx`) — consistent cu observatia ca e o schimbare "de volum", nu
locala.
### 5. Mecanism existent de ajustare/rotunjire
**Da, exista, dar la nivel contabil, nu la nivel de linie facturata / vizibil userului.**
`PACK_FACTURARE.verifica_total_document` (linia 16009-16188+) compara totalul FTVA/TVA asteptat
(`pack_facturare.ntotftva`, populat din VFP la `pnTotalFtva`/`Thisform.nbazaron`) cu suma reala din
notele contabile generate (`ACT_TEMP`, grupate pe conturi `4111`/`4427`/`418`/`4428`). Daca difera
(16082-16083: `NVL(pack_facturare.ntotftva,0) <> V_TOTFTVA_VER`), calculeaza diferenta
`pack_facturare.ndifftva := pack_facturare.ntotftva - V_TOTFTVA_VER` (16085) si **insereaza automat
o linie de corectie in `ACT_TEMP`** (16086-16188, INSERT cu `suma => pack_facturare.ndifftva`) —
adica ajustarea de rotunjire se absoarbe silentios in nota contabila, nu apare ca linie editabila
pe factura si nu se reflecta in `VANZARI_DETALII`. Aceasta e probabil exact mecanismul care face ca
utilizatorul sa nu poata corecta manual TVA-ul afisat: rotunjirea se "repara" doar in contabilitate,
dupa fapt.
---
## SUBIECT B — Denormalizare VANZARI, bug facturi din avize + numerar (#8)
### 6. Locatia `PACK_FACTURARE`
Nu exista fisier `.pck`/`.sql` cu acest pachet in working copy `ROAFACTURARE` (nici in `COMUN/`
local) — **e in afara working copy-ului VFP**, in arhiva DDL/PL-SQL Oracle
`D:\ROA\DATABASE\SCRIPTURI_CLAR\`. Cea mai recenta versiune completa (16948 linii):
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql`
(exista si un diff mai nou, doar pe view-uri, `2026\07\ff_2026_07_27_01_FACTURARE.sql` — vezi #11).
Istoricul complet de modificari e in `SCRIPTURI_CLAR\<an>\<luna>\ff_..._COMUN_PACK_FACTURARE.sql`
respectiv `..._FACTURARE.sql` (zeci de fisiere, 2006-2026).
### 7. Procedura care scrie in VANZARI valorile denormalizate
**`PACK_FACTURARE.scrie_in_vanzari`** (spec linia 894, body **linia 13468-13908**) — apelata din
`finalizeaza_factura` (linia **14740**). Face `UPDATE VANZARI SET ...` cu (13886-13898):
```
total_fara_tva = lnTotalFaraTVA,
...
total_cu_tva = lnTotalCuTVA,
...
serie_incasat = lnSerieIncasat,
nr_incasat = lnNrIncasat,
suma_incasat = lnSumaIncasat,
tip_incasat = lnTipIncasat
```
unde `lnSerieIncasat`/`lnNrIncasat`/`lnSumaIncasat`/`lnTipIncasat` sunt populate (13727-13730) din
variabilele **de pachet** `pack_facturare.cserie_act_incasare`, `.nnumar_act_incasare`,
`.nsuma_incasare`, `.ntip_doc_incasare` (declarate 179-182).
O a doua ramura echivalenta exista in **`finalizeaza_avize_lucrare`** (spec 1011, body
**14807-15176**), care face acelasi UPDATE (15124-15130) — pentru ramura "avize pe lucrare".
Variabilele de pachet `cserie_act_incasare`/`nnumar_act_incasare`/`ntip_doc_incasare`/
`nsuma_incasare` sunt setate **doar** de **`PACK_FACTURARE.scrie_incasari`** (spec 864, body
**13070-13139**), apelata condiționat (`IF V_LISTA_INCASARE IS NOT NULL`) din:
- `scrie_factura2` — linia **6178** (ramura factura normala / comanda / contract)
- `scrie_factura_avize` — linia **7008** (ramura **factura din aviz**)
Sunt resetate la `NULL` in `initializeaza_date_factura` (comentariu 1384-1386, cod la
**1876-1880**) — fix explicit din 03.07.2020: *"ramaneau completate pe facturile urmatoare de la o
factura anterioara"*.
`VANZARI.AVIZE` (seria/numarul avizelor facturate) e scris de
**`scrie_corespondente_vanzari`** (spec 1057, body **15421-15457**, comentariu la linia **15445**:
*"Completez VANZARI.AVIZE redundant, pentru a nu face mai rapid fact_vfacturi"*) — nu am confirmat
in acest buget de cercetare din ce apeleaza `finalizeaza_factura` daca `scrie_corespondente_vanzari`
ruleaza necondiționat pe toate tipurile sau doar pe unele (`V_TIP` e parametru) — merita verificat
punctual daca se investigheaza bug-ul mai departe.
### 8. Coloanele denormalizate din VANZARI si ramura care le populeaza
Toate adaugate prin `2017\03\ff_2017_03_28_01_FACTURARE.sql:9-38` (comentariu fisier, linia 1-4:
*"adaugare coloane in vanzari pentru denormalizarea join-urilor din fact_vfacturi"*):
| Coloana | Comentariu DB (linia 44-54 din script) | Populata de |
|---|---|---|
| `DISCOUNT_TVA` | TVA DISCOUNT (DISCOUNT * MAX(PROC_TVA) ARTICOLE) | `scrie_in_vanzari` |
| `VALOARE_ACHIZITIE` | Valoare la pret achizitie articole | `scrie_in_vanzari` |
| `TOTAL_FARA_TVA` | Total fara TVA lei | `scrie_in_vanzari` (13886), `finalizeaza_avize_lucrare` (15124) |
| `TOTAL_TVA` | Total TVA lei | idem |
| `TOTAL_CU_TVA` | Total cu TVA lei | `scrie_in_vanzari` (13888), `finalizeaza_avize_lucrare` (15126) |
| `SERIE_INCASAT` | Seria chitanta/bon fiscal | `scrie_in_vanzari` (13895), din `pack_facturare.cserie_act_incasare` (setat de `scrie_incasari`) |
| `NR_INCASAT` | Nr chitanta/bon fiscal | idem (13896) |
| `SUMA_INCASAT` | Suma chitanta/bon fiscal | idem (13897) |
| `TIP_INCASAT` | 11=CHITANTA, 2=BON FISCAL | idem (13898); vezi si `nTipIncasareCardBancar`=3, `nTipIncasareTichete`=5 |
| `AVIZE` | Serie/numar avize facturate (max 1000 caractere, comentariu la linia 1490) | `scrie_corespondente_vanzari` (15421) |
### 9. Tipurile de factura/aviz si ramificarea codului
Din `VANZARI.TIP` (CASE explicit in view `fact_vfacturi2`,
`ff_2017_03_28_01_FACTURARE.sql:89-171`) — cateva valori cheie:
`1`=POLITICA PRETURI, `2`=CONTRACT, `3`=COMANDA, **`4`=FACT. DIN AVIZ**, `21`=AVIZ PE BAZA DE
COMANDA, `24`=AVIZ DE RETUR, `43`=BON FISCAL MAGAZIN, etc. (lista completa la liniile citate).
Ramificare in VFP, `D:\ROA\ROAFACTURARE\COMUN\clase\ofacturare.vc2`, metoda
**`do_scrie_factura`** — exista **doua copii aproape identice** ale acestei logici, in doua clase
diferite (confirmat via `vfp_symbols.ps1 -Where`):
- `frm_facturare_articole.do_scrie_factura` — **liniile 13981-14339**
- `frm_facturare_articole2.do_scrie_factura` — **liniile 18004-18331**
Structura `DO CASE` (identica in ambele, ex. clasa 1 la liniile 14067-14174):
- `poDate.eProforma = 1` → `{call pack_facturare.scrie_proforma(...)}` (14071)
- `poDate.Tip = 4` → **`{call pack_facturare.scrie_factura_avize(...)}`** (14103) — "facturare din
aviz" (comentariu 14086-14087)
- `poDate.Tip IN (3,21,25,28,42,47)` → `{call pack_facturare.scrie_factura2(...)}` (14130) —
"facturare pe baza de comanda / avize pe baza de comanda"
- `Otherwise` → `{call pack_facturare.scrie_factura2(...)}` (14158) — politica de preturi/contract
Inainte de asta, lista de incasare `lcListaIncasare` se construieste (14012-14038) din
`poDate.ntip_incasare` (11=chitanta, 2=bon fiscal, 3=POS/card), comun tuturor ramurilor.
### 10. Ramura "factura din aviz" + "achitata numerar" — ce ar trebui sa scrie si ipoteza de cauza
**Ce se intampla, pas cu pas** (`Tip = 4`, `ntip_incasare` in (11,2,3)):
1. VFP (`ofacturare.vc2:14012-14038`) construieste `lcListaIncasare` de forma
`'11|<suma>|<id_casa>;'` (chitanta) sau `'2|...'`/`'3|...'` (bon fiscal/card) — **daca**
`ntip_incasare` nu e in (11,2,3), `lcListaIncasare = [NULL]` (literal SQL NULL).
2. VFP construieste `lcSql = {call pack_facturare.scrie_factura_avize(pnDiscount, serie_chit,
nr_incasare, lcListaIncasare, id_delegat, id_masina, id_facturare, listare_detaliata,
dataora_exp, id_agent, text_aditional, discount_evidentiat, param_aditional, ?@nid_vanzare)}`
(14103-14115) — semnatura corespunde exact cu procedura Oracle activa
`scrie_factura_avize` (linia **6675-7041**, care NU are `V_TOTFTVA`/`V_TOTTVA` ca prime
argumente, spre deosebire de `scrie_factura2` — asta e corect, nu e discrepanta de parametri).
3. In Oracle, `scrie_factura_avize` (7007-7012): `IF V_LISTA_INCASARE IS NOT NULL THEN
pack_facturare.scrie_incasari(...)` — deci **doar daca** `lcListaIncasare` nu e literalul
`NULL` se seteaza variabilele de pachet `cserie_act_incasare`/etc.
4. `scrie_factura_avize` seteaza `pack_facturare.clistaid_avize := ...V_LISTAID` (7020) — lista de
ID-uri de avize facturate, folosita ulterior de `scrie_corespondente_vanzari` pentru
`VANZARI.AVIZE`.
5. `scrie_factura_avize` cheama `finalizeaza_factura` (7026-7034), care cheama `scrie_in_vanzari`
(14740) → scrie `serie_incasat`/`nr_incasat`/`suma_incasat`/`tip_incasat` din variabilele de
pachet setate la pasul 3.
**La nivel de cod citit, lantul pare corect cablat** — parametrii trec prin, semnaturile se
potrivesc, iar cele doua clase VFP (`frm_facturare_articole` si `frm_facturare_articole2`) au
logica identica pentru aceasta ramura.
**IPOTEZA (cauza posibila a bug-ului, nedemonstrata prin citire de cod — necesita investigatie
suplimentara/testare)**:
- Daca ordinea reala de operatii difera de `ordine_operatii_facturare.txt` (ex. daca intre pasul 3
si pasul 5 se mai apeleaza `initializeaza_date_factura` pentru alt document/lucru din aceeasi
sesiune, inainte ca `finalizeaza_factura` sa apuce sa citeasca variabilele de pachet), fix-ul din
03.07.2020 (linia 1876-1880, reset la NULL) ar putea sterge datele de incasare **inainte** ca
`scrie_in_vanzari` sa le foloseasca — dar nu am gasit in codul citit un asemenea apel intercalat.
- Alternativ: daca pe ramura aviz `scrie_corespondente_vanzari` (care scrie `VANZARI.AVIZE`) nu e
apelata necondiționat din `finalizeaza_factura` pentru `TIP=4` (nu am verificat corpul complet al
`finalizeaza_factura`, liniile 14723-14807, dincolo de apelul la `scrie_in_vanzari`) — merita
verificat explicit daca acel apel exista si e neconditionat de tip.
- Nu am verificat daca exista vreo diferenta intre `scrie_factura_avize` si
`scrie_factura_avize_retur` (spec 667, alta ramura pentru tip retur din aviz) in privinta
apelului `scrie_incasari`/`scrie_in_vanzari` — posibil ca bug-ul sa fie specific ramurii de retur,
nu celei simple.
Recomandare pentru pasul urmator (daca se investigheaza mai departe): instrumentare/breakpoint pe
`scrie_in_vanzari` (13468) intr-un mediu de test, pentru o factura Tip=4 platita numerar, verificand
valorile efective ale `pack_facturare.cserie_act_incasare`/`nnumar_act_incasare`/`nsuma_incasare`/
`ntip_doc_incasare` chiar inainte de UPDATE (13886-13898).
### 11. Cele doua view-uri de facturi
- **`fact_vfacturi`** — view-ul "original" (pe model relational, cu join-uri catre `VANZARI_DETALII`
/ `ACT` / etc., fara denormalizare). Redefinit de multe ori de-a lungul timpului; cea mai recenta
gasita: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2023\11\ff_2023_11_17_01_COMUN.sql` (si
`2023\02\ff_2023_02_08_01_COMUN.sql`) — nu am deschis continutul exact in acest buget.
- **`fact_vfacturi2`** — view-ul cu totaluri **denormalizate din VANZARI** (`total_fara_tva`,
`total_tva`, `total_cu_tva`, `serie_incasat`, `nr_incasat`, `suma_incasat`, `tip_incasat`,
`avize` citite direct din coloanele `VANZARI`, nu recalculate din `VANZARI_DETALII`/`ACT`).
Definit initial in **`D:\ROA\DATABASE\SCRIPTURI_CLAR\2017\03\ff_2017_03_28_01_FACTURARE.sql:59-236`**,
cu comentariul explicit (linia 3): *"View fact_vfacturi2 - temporar, urmand a inlocui view-ul
fact_vfacturi, dupa completarea coloanelor din vanzari pentru datele existente deja"*.
Separat, exista si o a doua pereche de view-uri, mai recenta si mai granulara (pe linie de
articol, nu pe factura): **`fact_vrap_fact_articole`** / **`fact_vrap_articole_vandute`**, definite
in `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\07\ff_2026_07_27_01_FACTURARE.sql:10-257` — acestea NU
citesc din coloane denormalizate, ci calculeaza TVA live prin `pack_facturare.calculeaza_total_*`
(vezi Subiect A #2). Nu sunt aceleasi cu perechea mentionata in cerinta (care pare sa se refere la
`fact_vfacturi`/`fact_vfacturi2`), dar sunt relevante daca se cauta "view-ul cu totaluri din
vanzari" generic.
---
## Note metodologice
- `PACK_SESIUNE` (motorul de rotunjire per-pret, apelat de `PACK_FACTURARE`) nu a fost gasit
definit ca fisier separat in cautarile punctuale facute (cateva luni din 2025-2026); daca se
continua investigatia pe rotunjire, merita o cautare dedicata `create or replace package
pack_sesiune` in `D:\ROA\DATABASE\SCRIPTURI_CLAR`.
- Arhiva `D:\ROA\DATABASE\SCRIPTURI_CLAR` e foarte mare (mii de fisiere, 2009-2026); cautarile de
mai sus au fost tintite (nume de coloane/proceduri cunoscute), nu exhaustive — un `grep` complet
pe intreg arhivul repetat timeout la 20s in unele incercari initiale.
- Nu am gasit apeluri catre `PACK_FACTURARE` din `D:\ROA\ROAFACTURARE` propriu-zis (in afara
`COMUN\clase\ofacturare.vc2`) — pachetul e consumat exclusiv prin acea clasa si prin
`COMUN\programe\oproceduri_rapoarte_fact.prg`.

View File

@@ -1,164 +0,0 @@
# Proiectare view Oracle pentru liniile de articole ale unei vanzari (VVANZARI_ARTICOLE)
Cercetare + proiectare, read-only pe baza. Decizia lui Marius (08.08.2026): view dedicat, varianta B
din `rec_review_ancorare_s4.md` (respinsa atunci doar pentru ca insemna migrare de schema - acum
aprobata). Inlocuieste lista de 20 coloane + join pe 4 tabele din `IncarcaArticoleFactura`
(`COMUN\programe\ofacturare_editare.prg:201-208`).
## A. Precoditia VERSIUNE
`MARIUSM_AUTO` e la zi **pentru schema firmei (`ff_`)** pe orice ar putea atinge `VANZARI_DETALII`/
facturare: toate scripturile `ff_` din 2015 incoace apar in `VERSIUNE`, inclusiv cele mai recente
patru (`ff_2026_08_06_09/10/11/12`, comanda/contract, `PACK_FACTURARE`, `FACT_VFACTURI`,
`VANZARI_BACKFILL`). Diferenta gasita fata de `SCRIPTURI_CLAR` (452 de fisiere, din care 14 `ff_`)
e integral din 2009-2014 (dinainte de generalizarea `UpdateVersiune`) plus scripturi de diagnostic
fara prefix de tracking (`DIAG_SPATIU_*`, ad-hoc-uri fara nume standard) - niciunul din ele nu
atinge `VANZARI`/`VANZARI_DETALII`/facturare. Verdict: **precoditia trece**, sursa `MARIUSM_AUTO` e
de incredere pentru acest DDL.
## B. Ce exista deja - niciun candidat direct refolosibil, dar un precedent util
Cautat in `all_views` (MARIUSM_AUTO) orice view pe `VANZARI_DETALII`/liniile unei vanzari:
`VVANZARI_DETALII`, `VVANZARI_DETALII_TOT`, `FACT_VFACTURI_DETALII` sunt cele relevante.
- **`FACT_VFACTURI_DETALII`** (exportat integral) e cel mai apropiat candidat structural - selecteaza
direct din `vanzari_detalii`, cu join-uri catre `nom_articole`/`nom_gestiuni`/`nom_valute` ca in
proiectarea de mai jos. **Nu e reutilizabil ca atare**: `pret` si `discount_unitar` sunt
RECALCULATE la cursul valutar curent (`ROUND(NVL(g.curs,1)*NVL(a.pret,0)/NVL(g.multiplicator,1),
pack_sesiune.getoptiunefirma('PPRETV'))`, apel de functie PL/SQL per coloana per rand), construit
pentru **afisare/tiparire** facturi, nu pentru editare. Pagina de editare (#6) trebuie sa lucreze
pe valorile RAW stocate, ca la salvare (S5) sa scrie inapoi exact ce a citit - un `pret` deja
convertit ar strica exact acest contract. Confirma insa tiparul de join corect (articol/gestiune/
valuta) si ca genul asta de view exista deja in familia `FACT_*` pentru alt scop.
- **`VVANZARI_DETALII`/`VVANZARI_DETALII_TOT`**: alt scop (afisare generica vanzari + utilizatori +
politici de pret), nu au `pret_cu_tva`, `cont`, `id_valuta`, `id_gestiune`, `taxcode`, `lot` -
nepotrivite.
Niciunul nu inlocuieste nevoia unui view nou - se continua cu proiectarea.
## C. Numele: `VVANZARI_ARTICOLE`
Verificat liber in `all_objects` (MARIUSM_AUTO). 17 caractere, sub limita de 30 (Oracle 10.2).
**Criteriul lui Marius (08.08.2026)**: numele trebuie sa pastreze prefixul familiei de vanzari,
`vvanzari_*`, pentru ca el se uita la view-uri **alfabetic** si vrea sa vada dintr-o privire ca tine
de vanzari. La o listare alfabetica: `VVANZARI_ARTICOLE`, `VVANZARI_DETALII`,
`VVANZARI_DETALII_TOT`, `VVANZARI_TOT`.
Numele analog conventiei surorilor de pe acelasi formular (`vact_tot`, `vrul_tot`,
`vrul_obinv_tot`) ar fi fost `vvanzari_detalii_tot`, dar e **deja ocupat** (alt view, B mai sus).
Numele de lucru din prima varianta a fost `VVD_TOT` (`v` + abreviere + `_tot`, aliniat cu aliasul
VFP `tvd`), respins de Marius pe criteriul de mai sus: nu se citea ca facand parte din familie si
cadea in alta parte a listei alfabetice.
## D. Coloanele - RAW, fara filtru STERS in view
Cele 20 de coloane consumate azi + **`id_vanzare` adaugat**: lista din
`ofacturare_editare.prg:201-203` filtreaza pe `vd.id_vanzare` dar nu-l intoarce niciodata ca si
coloana - omisiune reala, semnalata in misiune, acum corectata in view.
- **Fara conversie valutara, fara valori calculate** (spre deosebire de `FACT_VFACTURI_DETALII`) -
editarea scrie inapoi exact ce citeste.
- **`STERS` ramane in view ca si coloana, dar FARA filtru `WHERE sters=0` in definitie** - acelasi
tipar ca `VACT_TOT`/`VRUL_TOT`/`VRUL_OBINV_TOT` (niciunul nu filtreaza `sters` in view, apelantul
o face explicit). Apelantul de azi (`IncarcaArticoleFactura`) deja are `WHERE ... vd.sters = 0` -
ramane neschimbat, doar `FROM vanzari_detalii vd ... WHERE vd.id_vanzare=... AND vd.sters=0` devine
`FROM vvanzari_articole vd WHERE vd.id_vanzare=... AND vd.sters=0`.
## E. Ce s-a respins: valorile calculate `CALCULEAZA_TOTAL_FARA_TVA_FACT`/`_TVA_FACT`
Ambele sunt functii **in `PACK_FACTURARE`**, semnatura `(V_PRET, V_DIFERENTA, V_CURS,
V_DISCOUNT_UNITAR, V_DISCOUNT_EVIDENTIAT, V_CANTITATE, V_PRET_CU_TVA, V_PROC_TVAV) RETURN NUMBER` -
strict `NUMBER`, deci **apelabile din SQL** (confirmat prin `all_arguments`, fara tip PL/SQL-only).
Exista precedent local pentru functii de pachet apelate per-rand intr-un view din aceeasi familie
(`VRUL_TOT` cheama `PACK_SESIUNE.SUMA_RON` pe aproape fiecare coloana numerica), deci performanta nu
e un argument respingator prin ea insasi pe un view filtrat pe `id_vanzare` (cateva linii/factura).
**Respins totusi, pentru acum**:
1. `V_DISCOUNT_EVIDENTIAT` **nu e coloana pe `VANZARI_DETALII`** - e pe antet (`VANZARI.
DISCOUNT_EVIDENTIAT`, confirmat in `all_tab_columns`). A include totalul calculat per linie ar
cere fie un join suplimentar la `VANZARI` (umfla view-ul cu o dependenta noua doar pentru un
parametru), fie parametrul trimis din VFP - oricum, in afara scopului Rundei 1 (doar afisare).
2. Runda 1 (deja implementata si testata, `docs\progres.md`) **nu consuma** aceste valori - grid-ul
e readonly, fara subtotal calculat.
3. Nevoia reala apare la S4b/Runda 4 (`plan_06_s4_proiectare.md`, C.1-C.3) - dar acolo e vorba de
**totalul pe DOCUMENT** (suma peste toate liniile), comparat cu `ACT`/`RUL`, nu de o coloana pe
fiecare rand din grid. O interogare de agregare separata (sau o functie Oracle dedicata) e o
potrivire mai buna pentru "totalul de control" decat 2 coloane calculate in view-ul de grid.
4. **Costul amanarii e mic**: extinderea unui VIEW (`CREATE OR REPLACE`) nu e o migrare de schema in
sensul de risc/coordonare al unei modificari de tabela - se poate adauga oricand printr-un script
nou, fara sa afecteze datele sau consumatorii existenti ai coloanelor deja definite. Deci nu e
nevoie sa se "prevada" acum ca sa se evite un al doilea script peste o saptamana.
**Recomandare pentru Runda 4**: cand S4b ajunge la implementare, se adauga fie doua coloane noi in
`VVANZARI_ARTICOLE` (dupa un join la `VANZARI` pentru `DISCOUNT_EVIDENTIAT`), fie - preferabil - o interogare
de agregare separata in Oracle care calculeaza direct SUMA pe document, fara sa treaca prin grid.
Decizia ramane a lui Marius/sesiunii care implementeaza S4b, pe baza planului deja scris in
`plan_06_s4_proiectare.md` C.1.
## F. Validare pe cele doua cazuri de regresie
Rulat direct ca `SELECT` (fara `CREATE VIEW`), corpul propus vs. interogarea de azi din
`IncarcaArticoleFactura`, pe `MARIUSM_AUTO`:
- **`id_vanzare = 1050`** (`cod=1140888`, `tip=1`): **4 randuri**, valori identice rand-cu-rand intre
interogarea veche si corpul noului view (`id_vanzare_det` 1584-1587). Coincide cu baza de regresie
din `docs\progres.md`.
- **`id_vanzare = 1047`** (`cod=1140885`, `tip=-12`): **2 randuri** (1578, 1579), identice intre cele
doua interogari.
Ambele cazuri: zero divergenta, inclusiv pe coloanele cu `NULL` (ex. `id_gestiune`/`nume_gestiune`
pe liniile nestocate din `id_vanzare=1047`).
## G. Numele coloanelor la iesire
Fara alias-uri noi - toate coloanele pastreaza numele lor de baza din tabelele sursa (Oracle
foloseste automat numele coloanei cand nu exista `AS`):
```
ID_VANZARE, ID_VANZARE_DET, ID_ARTICOL, CANTITATE, PRET, PRET_CU_TVA, PROC_TVAV, DISCOUNT_UNITAR,
ID_GESTIUNE, CONT, ID_VALUTA, ID_JTVA_COLOANA, SERIE, EXPLICATIE, TAXCODE, LOT, STERS,
DENUMIRE, CODMAT, NUME_GESTIUNE, NUME_VAL
```
**Zero schimbari fata de azi** pentru `ControlSource`-urile existente ale `grdArticoleFactura`
(`tvd.denumire`, `tvd.codmat`, etc.) - toate numele coincid cu ce se foloseste azi. Singura
schimbare vizibila e coloana noua `tvd.id_vanzare`, disponibila dar neconsumata inca de grid.
## H. Numerotare script
`SCRIPTURI_CLAR\2026\08\` exista deja, ultimul numar folosit azi (08.08.2026, la momentul
verificarii) e **niciunul** - nu exista fisiere `_2026_08_08_` in director (ultimele sunt din
06.08.2026, `NN` pana la 12). **`NN=01` e liber pentru 08.08.2026**, comun tuturor prefixelor -
de reverificat la momentul aplicarii, pentru ca sesiunea are mai multi agenti activi in paralel azi
care ar putea consuma acelasi numar inaintea acestui script.
Nume final propus: **`ff_2026_08_08_01_COMUN_VVANZARI_ARTICOLE.sql`** - scriptul livrat foloseste deja acest
nume in `exec pack_migrare.UpdateVersiune(...)`; daca sesiunea principala aloca alt `NN`, fisierul
**si** acel apel trebuie schimbate impreuna (altfel `VERSIUNE` inregistreaza un nume care nu exista
pe disc).
## I. Format script
`CREATE OR REPLACE VIEW` (fara `FORCE`) - verificat pe modelul cel mai recent din `SCRIPTURI_CLAR`
(`ff_2026_08_06_11_COMUN_FACT_VFACTURI.sql`, care creeaza doua view-uri fara `FORCE`); `FORCE` nu e
necesar oricum, toate tabelele sursa (`VANZARI_DETALII`, `NOM_ARTICOLE`, `NOM_GESTIUNI`,
`NOM_VALUTE`) exista deja. CRLF verificat byte-safe dupa scriere (44 CRLF, 0 LF singur). Fara `;` in
comentarii inaintea instructiunii. Se incheie cu `UpdateVersiune` + `commit`.
## Livrabil
`D:\ROA\ROAFACTURARE\docs\cercetare\ff_view_articole_vanzare.sql` - scriptul complet, **neaplicat**.
## Ce trebuie schimbat in VFP ca urmare (doar cand se aplica scriptul)
1. `COMUN\programe\ofacturare_editare.prg:201-208` (`IncarcaArticoleFactura`): inlocuieste
`FROM vanzari_detalii vd LEFT JOIN nom_articole na ... LEFT JOIN nom_gestiuni ng ... LEFT JOIN
nom_valute nv ...` cu `FROM vvanzari_articole vd`, pastrand neschimbat `WHERE vd.id_vanzare = ... AND
vd.sters = 0` si toata lista de coloane din `SELECT` (numele raman identice).
2. Fallback-ul `CREATE CURSOR tvd (...)` (`:214-216`) si duplicatul din `omodificari.vc2` (~14076,
semnalate deja ca duplicare in `rec_review_ancorare_s4.md`) **nu se ating** de aceasta schimbare -
raman neschimbate structural, doar sursa `SELECT`-ului se simplifica.
3. **Opional**, daca se doreste sa se profite de coloana noua `id_vanzare`: nu e necesar niciun
consum imediat in VFP - grid-ul nu are nevoie de ea (id-ul e deja cunoscut din parametrul functiei).

View File

@@ -1,207 +0,0 @@
# Watchdog VFP + diagnostic blocaj "View Parameter" (test_page3_articole.prg)
## 1. Utilitarul: `COMUN\utile\Teste\watchdog_vfp.ps1`
Lanseaza `vfp9.exe -A -T "<script>"`, polleaza la ~700ms ferestrele TOP-LEVEL ale procesului
(`EnumWindows`+`GetWindowThreadProcessId`, filtrate pe PID). Fereastra principala VFP se identifica
prin `Process.MainWindowHandle` (.NET) - **nu** dupa numele clasei: VFP inregistreaza clase diferite
prefixate `vfp9...` atat pentru shell-ul principal (`vfp99400000`) cat si pentru dialogurile lui
proprii (`vfp994000002` pentru "View Parameter") - o clasificare pe clasa a lasat "View Parameter"
nedetectat la prima incercare (corectat).
Pentru fiecare fereastra noua (diferita de `MainWindowHandle`): captura PNG (`PrintWindow`, fallback
`CopyFromScreen` daca iese neagra) + dump text (titlu, clasa, si textul/clasa fiecarui control copil
via `WM_GETTEXT`, cross-proces). Cu `-AutoDismiss`: cauta un buton copil "Cancel"/"Anulare" si
trimite `BM_CLICK`; altfel incearca, in ordine, `WM_COMMAND IDCANCEL` -> ESCAPE ca MESAJ
(`WM_KEYDOWN`/`WM_KEYUP`, tintit pe handle) -> `WM_CLOSE`.
**REGULA OBLIGATORIE, incalcata initial si corectata**: watchdog-ul NU are voie sa foloseasca INPUT
REAL de tastatura/mouse (`keybd_event`, `SetForegroundWindow`, `SendInput`, `mouse_event`) - masina e
PARTAJATA cu utilizatorul. Prima versiune folosea `SetForegroundWindow`+`keybd_event(ESCAPE)` ca
fallback pentru dialogurile proprii VFP owner-drawn (fara controale copil reale) - **acest input NU
are tinta, ajunge in orice fereastra are focus pe masina in acel moment, indiferent al cui proces
e**. **Fapt clarificat de team-lead, dupa investigare**: in acest caz concret, ESC-ul a aterizat de
fapt in PROPRIUL NOSTRU proces de test (eroarea "Variable 'GNAN' is not found" vazuta imediat inainte
de "Execution was canceled by the user" e chiar semnatura testului nostru) - **nu in sesiunea lui
Marius**, deci de fapt nu s-a intrerupt munca nimanui de data asta. Asta NU schimba regula: mecanismul
tot nu are tinta si putea la fel de usor sa ajunga in aplicatia de productie (`roafacturare.exe`/
`roacont.exe`) daca utilizatorul avea focus acolo in acea clipa - o formulare anterioara aici spunea
gresit ca ar fi afectat sesiunea utilizatorului, corectata acum. **Scos complet** din cod (nu mai
exista nicio linie `keybd_event`/`SetForegroundWindow` in `watchdog_vfp.ps1`). Consecinta: pentru
dialogurile owner-drawn care nu raspund la mesaje tintite, `-AutoDismiss` **esueaza cinstit** (dialogul
ramane deschis pana la `-TimeoutSec`, apoi procesul e omorat) - captura (PNG+dump text) ramane de incredere,
dismiss-ul nu e garantat pentru acest tip de dialog. Procesul e omorat mereu la iesire (`finally`),
nu ramane niciodata viu.
Validat intai pe caz banal: `COMUN\utile\Teste\watchdog_selftest.prg` (`MESSAGEBOX` cu OK/Cancel) -
detectie, captura, dump text si auto-dismiss confirmate corecte inainte de a-l rula pe cazul real.
Utilizare: `powershell -ExecutionPolicy Bypass -File watchdog_vfp.ps1 -Script "<test.prg>" -AutoDismiss [-TimeoutSec 90] [-MaxDialogs 10] [-OutDir <cale>]`.
## 2. Dialogurile capturate pe `test_page3_articole.prg`
**Dialog 0** - nativ VFP, clasa `vfp994000002`, titlu **"View Parameter"**, text **"Enter the value
for gnAn:"** (fara controale copil reale - owner-drawn). Screenshot:
`COMUN\utile\Teste\editare_factura\watchdog_out\test_page3_articole_dialog0.png`.
**Dialog 1** (apare doar cand dialog 0 e inchis prin ESCAPE real, care functioneaza) - "Open" Win32
standard, filtru "Table/DBF (*.dbf)", folder implicit `ROACONT` (working directory-ul mediului de
test, mostenit din `test_init_env_auto.prg`). Screenshot:
`COMUN\utile\Teste\editare_factura\watchdog_out\test_page3_articole_dialog1.png`.
## 3. PROGRAM()/LINENO() din log (dupa Cancel pe dialog 0)
Din `test_page3_articole_log.txt`, PROGRAM()=`VERIFICA_PAGECOUNT_FORM` (procedura de test) pe
liniile din jurul apelului `loForm = Createobject([frm_modific2024], lnIdSet)`:
```
EROARE 1 [VERIFICA_PAGECOUNT_FORM:165] File 'crsjtvatemp.dbf' does not exist.
EROARE 1924 [VERIFICA_PAGECOUNT_FORM:166..173] LOFORM is not an object. (cascada, zgomot)
```
## 4. Experimente de izolare (cerute de team-lead) - **INFIRMA ipoteza initiala**
Ipoteza initiala din aceasta sectiune ("`SQLEXEC` din `update_jtva_coloane` nu rezolva `?gnAn`") era
o **deductie**, nu o masuratoare - team-lead a cerut-o verificata direct, corect. Trei experimente
ieftine, in ordine:
**Experiment A - "chiar exista in acel moment?"** `TYPE('gnAn')`/`TRANSFORM(gnAn)` puse imediat
**INAINTE** de apelul `update_jtva_coloane` (linia 161 curenta, nu inainte de `Createobject` cum
fusese verificat prima data):
```
EROARE 12 [VERIFICA_PAGECOUNT_FORM:161] Variable 'GNAN' is not found.
```
- Eroare aparuta DOAR la primul apel al `verifica_pagecount_form` (`cod=1140888`), inainte sa se
ajunga la `update_jtva_coloane`. **Rezultat: `gnAn` e deja invizibila INAINTE ca `update_jtva_coloane`
sa fie apelata** - markerele `?gnAn`/`?gnLuna` din `updateserver.prg:597` nu pot fi (macar nu
singure) cauza, contrazice ipoteza initiala.
**Experiment B - "se reproduce izolat, fara nimic din S4?"** Script nou,
`COMUN\utile\Teste\editare_factura\test_repro_izolat_gnan.prg`: DOAR `test_init_env_auto` +
`update_jtva_coloane("", "crsJtvaTemp", 6)`, fara `IncarcaCursoareModificareNota`, fara
`frm_modific2024`, fara nimic din PAGE3. Rezultat:
```
TYPE(gnAn)=N TRANSFORM(gnAn)=2026 TYPE(gnLuna)=N TRANSFORM(gnLuna)=8
dupa update_jtva_coloane: Used(crsJtvaTemp)=.T. Reccount=120
done
```
**NU reproduce.** Zero dialog, exit curat, cursorul se creeaza corect cu 120 randuri.
`update_jtva_coloane` singura, chemata imediat dupa initul mediului, functioneaza perfect -
**nu e o capcana preexistenta a harness-ului si nici o vina proprie a functiei in izolare**.
Rerulat identic dupa scoaterea input-ului real din watchdog (vezi sectiunea 1) - acelasi rezultat,
deci reconfirmat, nu era un artefact al mecanismului de dismiss.
**Experiment C - oprit inainte de a-l rula.** Premisa lui ("copiaza corpul lui `update_jtva_coloane`
cu concatenare in loc de `?param`, ca sa confirmi mecanismul") presupune ca vina e in legarea
`SQLEXEC` a functiei - exact ce B tocmai a infirmat. Nu are sens sa continue in forma ceruta initial
fara o noua directie.
## 5. Cauza CONFIRMATA prin bisectie (nu doar deductie)
Bisectie ceruta de team-lead: `TYPE('gnAn')`/`TRANSFORM(gnAn)` logat in **doua straturi** - (a) in
programul principal, intre fiecare apel de nivel superior, si (b) ca **prima linie** in interiorul
fiecarei proceduri (`verifica_vanzare_nota`, `verifica_coliziune_cod`, `verifica_pagecount_form`).
Helper `bisect_log_gnan` (nou, la coada `test_page3_articole.prg`) - TYPE() e sigur necoditionat,
TRANSFORM() doar daca TYPE()<>'U', ca sa nu produca o eroare noua care ar intrerupe bisectia.
Rezultat brut (`test_page3_articole_log.txt`):
```
[BISECT] main: dupa test_init_env_auto :: TYPE(gnAn)=N gnAn=2026
[BISECT] verifica_vanzare_nota ENTRY cod=1140888 :: TYPE(gnAn)=U gnAn=(U)
[BISECT] main: dupa verifica_vanzare_nota #1 (cod=1140888) :: TYPE(gnAn)=N gnAn=2026
[BISECT] verifica_vanzare_nota ENTRY cod=1140885 :: TYPE(gnAn)=U gnAn=(U)
[BISECT] main: dupa verifica_vanzare_nota #2 (cod=1140885) :: TYPE(gnAn)=N gnAn=2026
[BISECT] verifica_vanzare_nota ENTRY cod=1125486 :: TYPE(gnAn)=N gnAn=2026 <- diferit!
[BISECT] main: dupa verifica_vanzare_nota #3 (cod=1125486) :: TYPE(gnAn)=N gnAn=2026
[BISECT] verifica_coliziune_cod ENTRY :: TYPE(gnAn)=N gnAn=2026
[BISECT] main: dupa verifica_coliziune_cod :: TYPE(gnAn)=N gnAn=2026
[BISECT] main: inainte de verifica_pagecount_form :: TYPE(gnAn)=N gnAn=2026
[BISECT] verifica_pagecount_form ENTRY cod=1140888 :: TYPE(gnAn)=U gnAn=(U)
[BISECT] verifica_pagecount_form inainte de update_jtva_coloane :: TYPE(gnAn)=U gnAn=(U)
```
**Tiparul e limpede si consecvent**: `gnAn` e INTOTDEAUNA valid (`N`, `2026`) in scope-ul PRINCIPAL,
la fiecare checkpoint, fara exceptie - deci **NU e "eliberata"** (nu e `CLEAR ALL`/`CLEAR MEMORY`/
`RELEASE ALL EXTENDED` pe undeva). E **`'U'` STRICT la intrarea in proceduri apelate cu `DO ... WITH`
in care `gnAn`/`gnLuna` sunt trecute NEPARANTEZATE ca argumente**, si redevine valid imediat ce
procedura respectiva se termina si controlul revine in principal. Corelatia e exacta cu sintaxa
apelului, nu cu ce face procedura pe dinauntru:
- `verifica_vanzare_nota` apelul #1/#2 (`gnAn` -> `U`): call-site-urile trec `gnAn, gnLuna` DIRECT -
`test_page3_articole.prg:34` (`DO verifica_vanzare_nota WITH 1140888, gnAn, gnLuna, ...`) si
`test_page3_articole.prg:36` (`... WITH 1140885, gnAn, gnLuna, ...`).
- `verifica_vanzare_nota` apelul #3 (`gnAn` ramane `N`): `test_page3_articole.prg:38` trece
`2008, 2` LITERAL, nu `gnAn`/`gnLuna`.
- `verifica_coliziune_cod` (`gnAn` ramane `N`): `test_page3_articole.prg:42` nu trece deloc
`gnAn`/`gnLuna` (doar `lcLog`).
- `verifica_pagecount_form` primul apel (`gnAn` -> `U`, **exact scenariul blocat**):
**`test_page3_articole.prg:47`** - `DO verifica_pagecount_form WITH 1140888, gnAn, gnLuna, 'A (factura reala)', lcLog, 3, .T.`.
**Mecanismul**: `DO <procedura> WITH <arg1>, <arg2>, ...` (stilul vechi, folosit peste tot in acest
script) trece variabilele de memorie **BY REFERENCE** implicit (`SET UDFPARMS` e `REFERENCE` in mod
implicit VFP) - `LPARAMETERS tnAn, tnLuna` din procedura primitoare devin ALIAS-uri directe pe
storage-ul lui `gnAn`/`gnLuna`, iar numele ORIGINAL devine inaccesibil (`TYPE()='U'`) **pe toata
durata apelului**, exact cat tine executia procedurii - confirmat empiric de simetria perfecta
"intra U, revine N" la fiecare din cele 3 perechi de apeluri afectate.
**Clasificare in termenii cerutii de team-lead**: e **"umbrire de scope"** (categoria 2), NU
"eliberare" (categoria 1) - dar mecanismul exact nu e o coliziune de nume `PRIVATE`/`LOCAL` in corpul
procedurii (team-lead avea deja dreptate: `verifica_pagecount_form` nu are `gnAn` in `LOCAL`, si nu
exista `PRIVATE gnAn`/`LOCAL gnAn` nicaieri in `COMUN\programe`) - **umbrirea vine din SINTAXA
APELULUI** (`DO...WITH` fara paranteze in jurul lui `gnAn`/`gnLuna`), nu din declaratiile procedurii
apelate.
**Statement-ul vinovat exact, cu fisier:linie**: `COMUN\utile\Teste\editare_factura\test_page3_articole.prg:47`.
**IMPLICATIE IMPORTANTA**: acesta e un tipar din **SCRIPTUL DE TEST**, nu din fluxul real al
aplicatiei - `do_editare_factura` (codul de productie) nu trece prin `verifica_pagecount_form`
(helper propriu testului). Team-lead a confirmat verdictul: **e strict un defect de harness** -
`updateserver.prg`, `omodificari.*` si codul S4 sunt toate nevinovate.
**Remediu APLICAT de team-lead** (3 linii, sub pragul lui de editare directa): argumentele
`gnAn`/`gnLuna` sunt acum parantezate - `(gnAn)`, `(gnLuna)` - la liniile 37, 39 si 50 din
`test_page3_articole.prg` (parantezele forteaza trecere PRIN VALOARE in loc de PRIN REFERINTA),
cu un comentariu explicativ deasupra primei aparitii. Nerulat inca de mine (interzis explicit -
suita o ruleaza team-lead-ul dupa eliberarea `.fxp`-ului).
**Remediul din rundele anterioare ale acestui raport (concatenare in loc de `?gnAn`/`?gnLuna` in
`updateserver.prg:597`) ramane infirmat** - nu era cauza. `updateserver.prg` nu a fost si nu e atins.
## 6. Fisiere atinse
- **Nou**: `COMUN\utile\Teste\watchdog_vfp.ps1`, `COMUN\utile\Teste\watchdog_selftest.prg`,
`COMUN\utile\Teste\editare_factura\test_repro_izolat_gnan.prg` (experimentul B, izolat).
- **Modificat**: `COMUN\utile\Teste\editare_factura\test_page3_articole.prg`
- linia 176 (`update_jtva_coloane(..., 6)`, ramane - fix necesar pt. indexul `id_jtva`, independent
de defectul de mai jos);
- `PROCEDURE bisect_log_gnan` (noua, la coada fisierului) + apeluri `DO bisect_log_gnan WITH ...`
inserate in principal (intre apelurile de nivel superior) si ca prima linie in fiecare procedura
- ramase in cod, sunt dovada bisectiei;
- **liniile 37, 39, 50 - remediul APLICAT de team-lead**: `gnAn`/`gnLuna` parantezate (`(gnAn)`,
`(gnLuna)`), forteaza trecere prin valoare in loc de prin referinta in `DO...WITH`.
- **Neatins**: `COMUN\clase\omodificari.vc2/.vcx/.vct`, `COMUN\programe\updateserver.prg` (ambele
infirmate ca posibila cauza, vezi sectiunea 5).
- Artefacte de rulare (`watchdog_out\*.png/.log`, `*_log.txt`) raman pe disc ca dovada; se pot sterge
cu `curatenie.ps1` la finalul lucrarii.
## 7. Stare la data acestui raport
**Cauza confirmata prin bisectie (sectiunea 5) si remediul APLICAT de team-lead** (paranteze la
liniile 37/39/50). **Nerulat inca** de nimeni dupa aplicarea remediului - team-lead ruleaza suita
separat, dupa eliberarea `.fxp`-ului (nu s-a mai relansat testul in aceasta sesiune, per interdictia
primita). Ramane deschis, pentru cine continua:
1. Confirma cu o rulare ca remediul chiar elimina dialogul si `verifica_pagecount_form` trece PASS
pe `PageCount=3`/`lAreArticoleVanzari=.T.` pentru cod=1140888.
2. Optional: verifica daca fluxul REAL de productie (`do_editare_factura` in `ofacturare_comun.vc2`)
are undeva acelasi tipar `DO...WITH <variabila PUBLIC>` NEPARANTEZAT inainte de un `?param` in
SQLEXEC - team-lead a verdictuit "defect de harness", dar asta ramane neverificat exhaustiv pe
codul de productie.
3. Watchdog-ul (`watchdog_vfp.ps1`) ramane instrumentul de verificat orice ipoteza noua fara sa se
agate procesul si FARA input real (regula obligatorie, sectiunea 1) - reutilizabil pentru orice
alt blocaj similar in suita.

View File

@@ -76,9 +76,9 @@ tipar `Createobject("oDateFactura", tip1, tip2)`).
**`tip = -12` e deja cunoscut in ROAFACTURARE** — nu ca un cod nou, ci ca ceva deja intalnit si
documentat in cercetarea recenta de regresie a editarii facturii (proiectul S4,
`docs\progres.md:339`, `:1142`; `docs\cercetare\rec_datoria6_baza_regresie.md:93`;
`docs\cercetare\rec_s4_runda1.md:38`; `docs\cercetare\rec_view_articole_vanzare.md:108`), pe un rand
`docs\cercetare\rec_s4_runda1.md:38`; `COMUN\docs\cercetare\rec_view_articole_vanzare.md:108`), pe un rand
real din baza de test `MARIUSM_AUTO`: `cod=1140885` -> `id_vanzare=1047`, `tip=-12`. Acolo e descris
explicit: **"nu e factura, e alt tip de document"** (`handoff_s4_runda1.md:77`) si decizia produsului
explicit: **"nu e factura, e alt tip de document"** (handoff intermediar (sters)) si decizia produsului
(decizia 19) e ca detectia liniilor de articole "merge pe orice tip, nu doar facturi" — adica
`IncarcaArticoleFactura`/`IncarcaVanzareNota` din `COMUN\programe\ofacturare_editare.prg` (mentionate
in `rec_datoria6_baza_regresie.md:83-84`) nu filtreaza dupa `tip=1`, deci **vad si randurile
@@ -100,7 +100,7 @@ in `rec_datoria6_baza_regresie.md:83-84`) nu filtreaza dupa `tip=1`, deci **vad
(`:1026-1027`), `-100007`/`-100008` INSPECTIE TEHNICA / SPALARE AUTO (`:979-982`). Optional, daca
`gnAUTOIdArticolReparatii` e setat, toate liniile de mai sus se **cumuleaza intr-o singura linie**
cu un articol real din nomenclator ("REPARATII AUTO", `:989-1004`). Confirmat pe date reale in
`docs\cercetare\rec_view_articole_vanzare.md:108-109`: `id_vanzare=1047` (`tip=-12`) are doar
`COMUN\docs\cercetare\rec_view_articole_vanzare.md:108-109`: `id_vanzare=1047` (`tip=-12`) are doar
**2 randuri** in `VANZARI_DETALII`, cu `id_gestiune`/`nume_gestiune` NULL (linii nestocate,
netinute in gestiune). Deci pe factura nu apar piesele individual — apar totaluri
MATERIALE/MANOPERA (cu exceptia cazului cumulat, unde apare un singur articol generic).

View File

@@ -1,55 +0,0 @@
-- S10 - curatare istoric TABELA VERSIUNE, MARIUSM_AUTO/ROA_CENTRAL
-- Scop: cele 5 scripturi ff_2026_08_06_* au fiecare mai multe inregistrari in VERSIUNE,
-- din aplicari succesive pe masura ce au fost extinse in cursul zilei de 06.08.2026.
-- Fara impact functional (versiune_db.txt si aplicarea DDL nu depind de numarul de randuri),
-- doar istoric zgomotos. Pastreaza UN singur rand per script (cel cu ID_VERSIUNE maxim, adica
-- ultima aplicare - starea finala reala a scriptului), sterge restul.
--
-- NU S-A RULAT. Propunere pentru aprobare - stergerea de istoric e decizie de om, iar
-- MARIUSM_AUTO e schema de dezvoltare partajata.
-- 1) Verificare inainte de stergere: cate randuri per script, azi
select script_final, count(*) as nr_inregistrari
from versiune
where script_final in (
'ff_2026_08_06_02_COMUN_PACK_FACTURARE.sql',
'ff_2026_08_06_03_COMUN_PACK_FACTURARE.sql',
'ff_2026_08_06_04_COMUN_VANZARI_COMANDA_CONTRACT.sql',
'ff_2026_08_06_05_COMUN_FACT_VFACTURI.sql',
'ff_2026_08_06_06_COMUN_VANZARI_BACKFILL.sql'
)
group by script_final
order by script_final;
-- Stare masurata 06.08.2026: _02=2, _03=1 (nimic de sters), _04=2, _05=4, _06=5 (14 randuri total,
-- 9 de sters, ramanand 5 - unul per script).
-- 2) Stergere: pastreaza doar randul cu ID_VERSIUNE maxim per script (ultima aplicare)
delete from versiune v
where v.script_final in (
'ff_2026_08_06_02_COMUN_PACK_FACTURARE.sql',
'ff_2026_08_06_03_COMUN_PACK_FACTURARE.sql',
'ff_2026_08_06_04_COMUN_VANZARI_COMANDA_CONTRACT.sql',
'ff_2026_08_06_05_COMUN_FACT_VFACTURI.sql',
'ff_2026_08_06_06_COMUN_VANZARI_BACKFILL.sql'
)
and v.id_versiune < (
select max(v2.id_versiune)
from versiune v2
where v2.script_final = v.script_final
);
-- 3) Verificare dupa stergere: fiecare script din lista trebuie sa aiba exact 1 rand
select script_final, count(*) as nr_inregistrari
from versiune
where script_final in (
'ff_2026_08_06_02_COMUN_PACK_FACTURARE.sql',
'ff_2026_08_06_03_COMUN_PACK_FACTURARE.sql',
'ff_2026_08_06_04_COMUN_VANZARI_COMANDA_CONTRACT.sql',
'ff_2026_08_06_05_COMUN_FACT_VFACTURI.sql',
'ff_2026_08_06_06_COMUN_VANZARI_BACKFILL.sql'
)
group by script_final
order by script_final;
-- commit; -- de dat manual, dupa verificarea pasului 3

View File

@@ -16,7 +16,7 @@ schimbare, clasificate (A) trebuie remigrat / (B) trebuie sters-refacut / (C) nu
- `docs\plan_13_unificare_formular_facturare.md` — sectiunea `#### S11` (linia ~3024)
- `docs\cercetare\idfact_refolosire_si_documente.md`
- `docs\cercetare\rec_cale_vanzari_detalii.md`
- `docs\cercetare\rec_consumatori_vanzari.md`
- `COMUN\docs\cercetare\rec_consumatori_vanzari.md`
- `docs\cercetare\cont_venit_corespondente.md`
- `docs\cercetare\legatura_linie_retur.md`
- `docs\cercetare\rec_d42_efactura.md`

View File

@@ -357,7 +357,7 @@ pe proza handoff-ului**: `docs\diff_s4_valuta_dialog*.patch` (trei fisiere) atin
`COMUN\clase\omodificari.vc2`, `COMUN\programe\ofacturare_editare.prg` si un fisier de test —
**niciunul nu atinge `ofacturare.vc2` (unde traiesc `frm_date_factura`, `do_schimba_tipdoc`,
`clb_serie_act`) sau `ofacturare.prg` (unde traieste bucla `factureaza`)**. Confirmat si de continutul
lui `docs\handoff_decizia35_valuta_dialog.md`: intreaga lui cercetare e despre `frm_articol_factura`
lui handoff intermediar (sters): intreaga lui cercetare e despre `frm_articol_factura`
(dialogul de adaugare articol pe linie, alt fisier/clasa) si `frm_modific2024.cmdAdaugaArticol.Click`
— un mecanism de valuta **pe linie de articol**, fara nicio legatura cu antetul sau cu bucla de
emitere. **#6 nu a atins deloc lantul lui #16. Bug-ul e in intregime valabil si neschimbat.**
@@ -418,7 +418,7 @@ Specific pentru S3 (antet):
interactiunea reala de selectare dintr-o lista si `Show(1)` modal nu se poate simula headless; se
pot testa doar efectele **dupa** ce `poCauta`/rezultatul e construit manual (tiparul deja folosit in
`test_pret_cu_tva_dialog.prg`/`test_adauga_linie_valuta.prg` mentionat in
`docs\handoff_decizia35_valuta_dialog.md`, punctul 7) — apel direct al metodei cu un obiect
handoff intermediar (sters), punctul 7) — apel direct al metodei cu un obiect
simulat, fara `Show()`.
- **`Init`-ul complet** (redimensionare, `RemoveObject` in cascada, repozitionare containere) e
verificabil pe proprietati (`.Visible`, `.Height`, existenta obiectului dupa `Type(...)`) fara UI

View File

@@ -283,7 +283,7 @@ formular — vezi mai jos).
### 4.1 Nu porni de la `frm_tranzit` (RORIS) — porneste de la `cauta_alfa`
Raportul de referinta (`docs\cercetare\import_roris_roaacnpro.md`) descrie corect **arhitectura
Raportul de referinta (`COMUN\docs\cercetare\import_roris_roaacnpro.md`) descrie corect **arhitectura
generala** (buton conditionat -> metoda unica -> dialog cu bifare si criterii -> populare aditiva prin
`INSERT`, fara scriere Oracle pana la salvare) — dar `frm_tranzit` insusi e un formular **specific
ROAACNPRO**, care nu exista in ROAFACTURARE si n-ar trebui portat ca formular.

View File

@@ -2,7 +2,7 @@
Poveste: `docs\plan_13_unificare_formular_facturare.md`, `#### S4d` (decizia 15, proiectata in
sectiunea M). Cercetare preliminara deja facuta si citata ca sursa de adevar:
`docs\cercetare\zi_curs_validare.md`, `docs\cercetare\valuta_si_curs.md`,
`docs\cercetare\zi_curs_validare.md`, `COMUN\docs\cercetare\valuta_si_curs.md`,
`docs\cercetare\rec_dec42_proiectare.md`/`rec_d42_efactura.md` (decizia 42),
`docs\cercetare\s3_portare_antet.md` (bug #16), `docs\cercetare\s4_cautare_articole_server.md`/
`s4_puncte_deschise.md` (decizia 42, mecanismul ei exact). Read-only: nicio editare de cod, niciun

View File

@@ -1,296 +0,0 @@
# Cercetare: `poDate.in_valuta`, `Clb_zi_curs` si cele doua concepte de valuta
Investigatie read-only (fara editari, fara `git_sync.ps1`/`txt2vcx.ps1`, fara commit). Sursa: cache
text `.vc2`/`.prg` din `COMUN\clase\ofacturare.vc2`, `COMUN\programe\ofacturare.prg`,
`COMUN\programe\ofacturare_comun.prg`, `COMUN\programe\ofacturare_stoc.prg`,
`COMUN\programe\oproceduri_curs.prg`, plus pachetul Oracle
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql` (copie pe disc,
alta numerotare decat baza). Reutilizeaza si confirma cercetari anterioare din
`docs\cercetare\rec_cale_vanzari_detalii.md` si `docs\cercetare\rec_consumatori_vanzari.md`.
---
## 1. `poDate.in_valuta` — unde se seteaza si din ce
**Concluzie**: `in_valuta` e determinat **o singura data**, la `Init`, exclusiv din **tipul
documentului** (`tnTip`) plus o lista fixa de `id_set` — niciodata din alegerea manuala a unei
valute in antet si niciodata resetat ulterior. E o proprietate a *tipului de factura* (Invoice /
credit note / retur valuta / factura fiscala valuta pe contract), nu a faptului ca articolele au
preturi in valuta.
**Dovezi**:
- Valoare implicita `0`: `COMUN\programe\ofacturare_comun.prg:165` (`in_valuta = 0`, in blocul de
proprietati al obiectului `poDate`).
- Singurul loc care il seteaza pe `1`, in `Procedure Init`:
```
ofacturare_comun.prg:248-250
If Inlist(tnIdSet,223,225,226,227,271) OR INLIST(m.tnTip, 5,6,7,9,10,52)
.in_valuta = 1
Endif
```
- Legenda tipurilor (comentariu din `frm_date_factura.Init`), `ofacturare.vc2:9571-9582`:
`1`=lista preturi, `2`=contract, `3`=comanda, `4`=aviz, `5`=Invoice lista preturi, `6`=Invoice
contract, `7`=credit note, `8`=retur lei, `9`=retur valuta, `48`=avize valoric, `52`=Factura
fiscala valuta contract. Tipul `10` nu are comentariu explicit in acest bloc (adaugat separat,
v2.0.56, ca variatie de tip 1/5).
- Nicio alta cale de scriere pe `in_valuta` in `.vc2`/`.prg` din COMUN — verificat cu grep
(`\.in_valuta\s*=\s*[01]`) pe intreg `ofacturare.vc2` si `ofacturare.prg`: restul potrivirilor
sunt toate **citiri** (`If poDate.in_valuta = 1 ...`), nu atribuiri. `ofacturare_stoc.prg:549`
(`poDate.in_valuta = in_valuta`) e o cale alternativa (facturare "din stoc") care primeste
parametrul `in_valuta` deja calculat in amonte, cu aceeasi semantica.
- Consecinta directa, confirmata de cod: alegerea manuala a unei valute pentru document (control
`ct_clb_valuta`) nu poate schimba `in_valuta` — controlul insusi e eliminat din formular cand
`in_valuta = 0` (`ofacturare.vc2:9725-9728`), deci userul nu are cum sa-l "aleaga" pe o factura
care nu e deja de tip valuta.
---
## 2. Campul „Data curs valutar" (`Clb_zi_curs`) — unde e definit si cand e eliminat azi
**Concluzie**: campul e eliminat **doar** pentru facturi de retur (`tip` 8 sau 9), niciodata pe
baza de `in_valuta`. **Da, azi campul apare si pe facturile in lei** (`in_valuta=0`) de orice alt
tip — comportament confirmat explicit prin simetrie de cod: imediat dupa blocul de retur, exista un
bloc separat care elimina `ct_clb_valuta` cand `in_valuta=0`, dar echivalentul lipseste pentru
`clb_zi_curs`.
**Dovezi** (identificarea claselor facuta cu `vfp_symbols.ps1 -Where`):
| Clasa | Interval | `Clb_zi_curs` definit | Eliminat azi? |
|---|---|---|---|
| `frm_date_aviz` | `ofacturare.vc2:6566-7618` | `:6727-6740` (caption "Data cursului valutar") | Niciodata — zero `RemoveObject`/conditionare pe `in_valuta` in toata clasa (verificat exhaustiv) |
| `frm_date_aviz_lucrare` | `:7620-8201` | `:7787-7801` | Niciodata; in plus, validare **necondiționata**: `:8076` `Case Empty(Nvl(poDate.zi_curs,{}))` fara nicio garda pe `in_valuta` (spre deosebire de `frm_date_factura`, vezi mai jos) |
| `frm_date_factura` | `:8482-9869` | `:8701-8714` (caption "Data curs valutar") | **Doar** pentru `tip` 8/9, in `Init`: |
```
ofacturare.vc2:9717-9722 (frm_date_factura.Init)
*!* modificare v 2.0.56
If Inlist(poDate.tip, 8, 9)
lnHeight = lnHeight - .clb_zi_curs.Height
laPozitii(.clb_zi_curs.TabIndex, 2) = 1
.RemoveObject('clb_zi_curs')
Endif
*!* modificare v 2.0.56 ^
ofacturare.vc2:9725-9728 (imediat dupa, in ACEEASI metoda)
If poDate.in_valuta = 0
lnHeight = lnHeight - .ct_clb_valuta.Height
laPozitii(.ct_clb_valuta.TabIndex, 2) = 1
.RemoveObject('ct_clb_valuta')
```
Cele doua blocuri sunt adiacente si scrise dupa acelasi tipar (inaltime, `laPozitii`,
`RemoveObject`) — dovada ca autorul original a tratat `ct_clb_valuta` (selectorul de valuta) ca
dependent de `in_valuta`, dar **nu** a facut acelasi lucru pentru `clb_zi_curs`. Validarea de
completare e de asemenea asimetrica: `ofacturare.vc2:9484`
(`Case poDate.in_valuta = 1 And Empty(Nvl(poDate.zi_curs,{})) And ...`) cere data curs **doar** cand
`in_valuta=1`, in timp ce `frm_date_aviz_lucrare` (`:8076`) o cere mereu — inconsistenta intre cele
doua forme, de retinut daca regula noua trebuie aplicata uniform.
Nota: `frm_facturare_articole2` (clasa separata, `:15741-19355`) are propriul label "Curs valutar"
(control diferit, `:16285-16299`), tratat la punctul 3/5 — nu e acelasi camp cu `Clb_zi_curs` din
antet, dar citeste aceeasi `poDate.zi_curs`.
---
## 3. Cele doua concepte, in cod — confirmate distinct
**Concluzie**: da, distinctia exista clar in cod, pe doua axe independente:
- **(a) valuta de document**: `poDate.in_valuta` / `poDate.Curs` / `poDate.multiplicator` /
`poDate.id_valuta` — un singur curs, al documentului intreg, folosit cand tot documentul e emis
in valuta.
- **(b) articol cu pret in valuta pe document in lei**: `poArticol.tip_valuta = 1` (proprietate a
politicii de pret a articolului, independenta de `poDate.in_valuta`), cu preturile brute in
valuta pastrate in `poArticol.pretftva_val`/`pretctva_val`/`pretd` + `id_valuta_d`, convertite in
lei **client-side, in VFP**, folosind cursul zilei `poDate.zi_curs`.
**Dovezi — conversia in lei pentru cazul (b)**:
```
ofacturare.vc2:1989 poArticol.pretftva = Round(poArticol.pretftva_val * poArticol.Curs / poArticol.multiplicator, gnPPretV)
ofacturare.vc2:2953 poArticol.pretftva = Round(poArticol.pretftva_val * poArticol.Curs / poArticol.multiplicator, gnPPretV)
ofacturare.vc2:2017 poArticol.pretctva = Round(poArticol.pretctva_val * poArticol.Curs / poArticol.multiplicator, gnPPretV)
```
`poArticol.Curs`/`multiplicator` (nu e alt curs decat cel al zilei documentului) provin din cursorul
`crscursuri`, incarcat explicit **cand documentul e in lei** — exact pentru articolele cu preturi in
valuta:
```
ofacturare.prg:407-418 (identic si la :941-947)
If poDate.in_valuta = 1
Select Distinct Curs, nume_val, id_valuta, multiplicator From (lcCursor) ... Where tip_valuta = 1 ... Into Cursor crscursuri
Select crscursuri
poDate.Curs = Curs
poDate.multiplicator = multiplicator
Else
citeste_cursuri_zi(poDate.zi_curs)
If Reccount('crscursuri') = 0
Use In crscursuri
Endif
Endif
```
`citeste_cursuri_zi` (`COMUN\programe\oproceduri_curs.prg:113-124`) construieste `crscursuri` cu
**toate** cursurile valabile la `tdDataCurs` (`= poDate.zi_curs`):
```
oproceduri_curs.prg:117-118
lcSql = [select nume_val,curs,id_valuta,multiplicator from ] + gcS + [.vcurs where data <= ... and data2 >= ...]
```
Cursorul e apoi afisat direct pe grila de selectie a articolelor, cu eticheta construita din
`poDate.zi_curs`, **indiferent de `in_valuta`**:
```
ofacturare.vc2:15097-15098 si 19004-19005 (frm_facturare_articole2)
If !Empty(Nvl(poDate.zi_curs, {}))
Thisform.lb_cursuri.Caption = "Curs valutar " + Iif(!Inlist(poDate.tip, 8, 9), "(" + Dtoc(poDate.zi_curs) + ")", "")
```
Grila/eticheta apar doar daca `crscursuri` are randuri (`ofacturare.vc2:15092`/`19000`), ceea ce se
intampla si pe un document in lei, daca exista macar un articol cu politica in valuta.
**`VANZARI` vs `VANZARI_DETALII` — ce se stocheaza**:
- `VANZARI` (document): coloane proprii `CURS`/`ID_VALUTA`/`MULTIPLICATOR` — cursul/valuta **doar
ale documentului**, populate din `poDate.Curs`/`id_valuta`/`multiplicator` (relevante cand
`in_valuta=1`).
- `VANZARI_DETALII` (linie): **nu are coloana `CURS`** — confirmat din `all_tab_columns`
(`docs\cercetare\rec_cale_vanzari_detalii.md:171-175`) si din SQL-ul live al pachetului, care
reface cursul liniei prin JOIN, nu dintr-o coloana proprie:
```
PACK_FACTURARE.sql:3773-3778 (identic la :4034-4036, :6393-6396, :6571-6573)
LEFT JOIN VANZARI_CURSURI B1 ON A1.ID_VANZARE = B1.ID_VANZARE AND A1.ID_VALUTA = B1.ID_VALUTA
```
Linia stocheaza insa `PRET` (pretul efectiv, in lei, folosit pe factura) **si** `PRETD` +
`ID_VALUTAD` (pretul brut in valuta si valuta originii, pastrate ca referinta/audit) — vezi
INSERT-ul din `adauga_articol_factura`
(`docs\cercetare\rec_cale_vanzari_detalii.md:59-65`, coloanele `PRET`, `PRETD`, `ID_VALUTAD`,
`ID_VALUTA` alaturi). Deci **da**, se pastreaza si urma valutei originale pe linie, dar valoarea
de facturare efectiva e mereu in lei pe `VANZARI_DETALII.PRET`.
**La ce se foloseste `VANZARI_CURSURI`**: e un instantaneu al cursurilor pentru **orice valuta
straina aparuta printre liniile documentului** (nu doar valuta proprie a documentului), scris o
singura data la emitere, indiferent de `in_valuta`:
```
PACK_FACTURARE.sql:14491-14501
PROCEDURE scrie_cursuri(V_ID_VANZARE IN NUMBER) IS
BEGIN
INSERT INTO VANZARI_CURSURI (ID_VANZARE, ID_VALUTA, CURS, MULTIPLICATOR)
SELECT DISTINCT V_ID_VANZARE, ID_VALUTA, CURS, MULTIPLICATOR
FROM VANZARI_DETALII_TEMP
WHERE ID_VALUTA <> pack_facturare.nid_moneda_nationala;
END scrie_cursuri;
```
Rulat necondiționat la fiecare emitere (apelat din `scrie_in_vanzari`, vezi
`docs\cercetare\rec_cale_vanzari_detalii.md:98-102`) — deci **si pe o factura in lei** cu articole
in valuta se scrie cate un rand `VANZARI_CURSURI` pentru fiecare valuta straina aparuta pe linii,
cu cursul citit la `poDate.zi_curs`. Tabela e folosita ulterior la reafisare/reprint/retur, ca sursa
a cursului per-linie (JOIN-urile de mai sus).
---
## 4. Ce se strica daca ascundem campul cand "nu are sens"
**Concluzie**: nu exista risc de "factura fara curs deloc" — `poDate.zi_curs` primeste mereu o
valoare implicita la `Init` (data documentului) si nu poate ramane `NULL`. Riscul real e altul:
**userul pierde controlul asupra datei de curs pentru cazul (b)** — o factura in lei cu articole in
valuta ar folosi mereu cursul zilei curente/implicite, fara sa poata fi corectat manual, exact in
situatia in care lipseste cursul pentru acea data (eroarea Oracle 20005, punctul 5) sau cand userul
vrea sa aliniaze cursul cu data unui document sursa (aviz, contract).
**Consumatori confirmati ai `poDate.zi_curs`** (grep exhaustiv `poDate\.zi_curs`, fisiere
`ofacturare.vc2`, `ofacturare.prg`, `ofacturare_stoc.prg` — singurele 3 din COMUN):
| Loc | Ce primeste | Conditionat de `in_valuta`? |
|---|---|---|
| `ofacturare.vc2:6105-6107`, `:13994-13996`, `:18030-18032` | parametru `to_date(...)` catre `pack_facturare.initializeaza_date_factura(...)` la fiecare finalizare de antet | **Nu** — trimis pentru orice tip |
| `ofacturare.prg:272,276,281,297,303` | primul parametru al `pack_facturare.cursor_articole_k` / `cursor_preturi` / `cursor_gestiune` / `cursor_lucrare` — SQL-ul care aduce lista de articole/preturi afisata userului | **Nu** — inclusiv pentru `tip=1` (lista de preturi, lei) |
| `ofacturare_stoc.prg:79,335` | acelasi rol, pe calea alternativa "facturare din stoc" | Nu |
| `ofacturare.vc2:15097-15098`, `:19004-19005` | eticheta grilei "Curs valutar (data)" din `frm_facturare_articole2` | Nu — apare oricand `crscursuri` are randuri |
| `ofacturare.vc2:9484` | validare "Nu ati completat ziua cursului valutar" | **Da**, doar `in_valuta=1` (`frm_date_factura`) |
| `ofacturare.vc2:8076` | aceeasi validare | **Nu**, necondiționata (`frm_date_aviz_lucrare`) |
**Riscul concret**: daca regula noua ascunde/dezactiveaza campul strict cand `poDate.in_valuta=0`,
pe `frm_date_factura` (tip 1, lista de preturi) userul nu va mai putea edita `zi_curs` inainte de a
deschide grila de articole — dar `ofacturare.prg:279-282` tot va trimite acel `poDate.zi_curs`
(neschimbat, ramas pe data initializata la `Init`) catre `cursor_preturi`, iar daca acolo Oracle
ridica eroarea 20005 (curs lipsa pentru acea data/valuta), fluxul de recuperare
(`vizualizeaza_curs`, punctul 5) va porni oricum, dar userul nu va (mai) avea camp pe antet ca sa
retina/corecteze data dupa ce inchide formularul de curs. Pe `frm_date_aviz_lucrare`, ascunderea ar
intra chiar in conflict cu validarea necondiționata de la `:8076`, care ar bloca finalizarea
antetului cerand un camp care nu mai exista pe ecran — de reparat impreuna, nu doar ascuns.
---
## 5. Formularul de curs valutar din antet — localizare si traseu
**Concluzie**: nu exista niciun buton/dblclick pe `Clb_zi_curs` care sa deschida formularul de curs
(verificat exhaustiv — zero hit pentru `Clb_zi_curs.DblClick/RightClick/Click` sau `but_curs` in
`ofacturare.vc2`). Formularul se deschide **automat**, ca recuperare de eroare, dupa ce antetul
(`frm_date_factura`/`frm_date_aviz`) s-a inchis deja si codul incearca sa incarce lista de articole.
**Traseu**:
1. `ofacturare.prg:228-235` — `ofrmceredate = Createobject(lcObiect, toFactura)` (`lcObiect` =
`frm_date_factura` sau `frm_date_aviz`), `.Show()` modal; la inchidere, `Release ofrmceredate`
(`:248`).
2. `ofacturare.prg:266-308` — pe baza tipului, se construieste apelul catre
`pack_facturare.cursor_preturi(?poDate.zi_curs, ...)` (sau `cursor_articole_k`/`cursor_gestiune`/
`cursor_lucrare`) si se executa (`:311` `goExecutor.oExecute(lcSqlCursor, lcCursor)`).
3. Daca esueaza cu eroarea Oracle **20005** (curs lipsa pentru data/valuta ceruta):
```
ofacturare.prg:313-317 (identic la :828-832)
If lnSucces < 0
AMESSAGEBOX(goExecutor.oPrelucrareEroare(), 16, "Eroare")
If goExecutor.nEroare = 20005
vizualizeaza_curs(poDate.zi_curs)
ENDIF
```
4. `vizualizeaza_curs(tdDataCurs)` — `COMUN\programe\oproceduri_curs.prg:8-42` — construieste
cursorul `crscurs` si deschide `loFrmCurs = Createobject("frm_curs", tdDataCurs)` /
`.Show(1)` (modal).
5. Clasa `frm_curs` e definita in **`COMUN\clase\onom_curs.vc2:537`** (`DEFINE CLASS frm_curs AS
_frmbase ...`), cu formulare-satelit pentru adaugare curs: `frm_curs_nou`
(`onom_curs.vc2:1066`) si `frm_curs_nou_multiplu` (`onom_curs.vc2:1330`, apelat de la
`onom_curs.vc2:941`).
6. A doua cale catre acelasi formular: `citeste_cursuri_stoc` (`oproceduri_curs.prg:45-110`, folosit
pe fluxul de facturare din stoc) cheama `vizualizeaza_curs()` **fara parametru de data**
(`oproceduri_curs.prg:94`) cand gaseste valute fara curs pentru ziua ceruta, in bucla `Do While
llVerificare` (retry pana userul completeaza sau renunta).
Aceasta e exact situatia din `COMUN\docs\todos.txt:45` (punctul 16): "la finalizare se verifica
cursul valutar necesar pentru politicile de preturi care se factureaza [...] la revenire din
formularul de curs valutar, focusul revine [...] pe TIP DOCUMENT, si la iesire din serie se
regenereaza numar act" — confirmat ca fenomenul are loc **dupa** ce antetul (`frm_date_factura`) e
deja inchis si eliberat (`Release ofrmceredate`, pasul 1), deci orice regenerare de numar/focus
vizibila dupa inchiderea `frm_curs` tine de ecranul/starea care ramane activa in spate (nu s-a
localizat mai departe — cere depanare separata, in afara scopului "doar localizare" cerut aici).
---
## Cand are sens campul „Data curs valutar" — propunere de regula
Campul are sens de aratat/editabil pe antet exact cand exista **vreo** sansa ca cursul zilei sa fie
folosit la facturare — nu doar cand documentul insusi e in valuta:
> Arata (si activeaza) `Clb_zi_curs` cand `poDate.tip` NU e retur (`!Inlist(poDate.tip,8,9)`) **SI**
> (`poDate.in_valuta = 1` **SAU** exista macar o politica de pret in valuta accesibila tipului
> curent de document — adica exact conditia care astazi populeaza `crscursuri` cu randuri, verificata
> deja empiric la `ofacturare.vc2:15092`/`:19000`: `Used('crscursuri') And Reccount('crscursuri') > 0`
> dupa incarcarea listei de articole). Pe retur (8/9) ramane ascuns ca azi.
Pe `frm_date_aviz`/`frm_date_aviz_lucrare`, unde `crscursuri` nu e inca disponibil la momentul
antetului (se incarca dupa, la fel ca la factura), regula echivalenta practicabila **pe antet** (nu
dupa) ar fi: arata campul daca tipul documentului admite politici de pret in valuta pentru
sucursala/gestiunea curenta (verificare care azi nu exista pe antet, doar mai tarziu pe grila de
articole) — necesita fie mutarea verificarii mai devreme, fie acceptarea ca antetul nu poate sti cu
certitudine inainte de a incarca articolele, caz in care campul ramane vizibil implicit si doar
eticheta/relevanta lui se clarifica ulterior (ca azi, in `frm_facturare_articole2`).
---
## Necunoscute ramase
- Nu s-a confirmat daca exista si alte politici (`CRM_POLITICI_PRET*`) sau reguli de sucursala care
determina *inainte* de deschiderea grilei de articole daca vor exista linii `tip_valuta=1` — utile
pentru a decide vizibilitatea campului chiar pe antet, nu doar reactiv dupa incarcarea articolelor.
- Nu s-a urmarit complet "focusul sare pe tip document / regenerare numar act" (punctul 5/todos #16)
dupa inchiderea `frm_curs` — s-a localizat doar traseul de deschidere, nu si ecranul/handler-ul
care ramane activ in spate si cauzeaza simptomul; cere sesiune separata de depanare (posibil in
`poGeneratorNumere`/`clb_serie_act`, cf. `ofacturare.vc2:9735-9737`, needatate aici).
- Layout-urile `.frx` (neconvertite) care afiseaza `poDate.Curs`/`cValuta` pe hartie nu au fost
verificate — gap deja semnalat in `rec_consumatori_vanzari.md` (risc posibil #3), ramane valabil.
- Nu s-a confirmat empiric (interogare Oracle) daca exista azi in productie facturi `tip=1` (lei) cu
linii `ID_VALUTA <> moneda_nationala` in `VANZARI_DETALII` — dovada ar intari direct concluzia
punctului 3, dar cercetarea a fost strict pe cod (fara conexiuni DB, conform mandatului).

View File

@@ -3,7 +3,7 @@
Bloc #6 / S5, parte din "editare factura emisa". Stare la 10.08.2026. Scop: Marius decide
commit / push / SVN pe baza acestui fisier, fara sa recititeasca cele zece rapoarte de mai jos.
Surse: `docs\progres.md` (sectiunea #6/S5), `docs\handoff_s5.md` (deciziile 38-41),
Surse: `docs\progres.md` (sectiunea #6/S5), handoff intermediar (sters) (deciziile 38-41),
`docs\cercetare\rec_s5_scriere_reala.md`, `docs\cercetare\rec_s5_discount_valuta.md`,
`docs\cercetare\rec_s5_teste.md`, `docs\cercetare\rec_s5_grid_articole.md`.
@@ -32,17 +32,17 @@ reeditare.
| Fisier | Repo | Ce s-a schimbat | Patch |
|---|---|---|---|
| `clase\omodificari.vc2` | COMUN | Coloana `pret_achizitie` in grid, editabilitate per rand (linii de set needitabile, marcaj albastru), 5 validari noi in `inainte_de_do_termin` | `docs\diff_s5_grid_articole.patch` |
| `clase\ofacturare_comun.vc2` | COMUN | Agatarea apelului `ScrieArticoleFacturaEditate` dupa `finalizeaza_modificare_nota` (primul punct de intrare, `do_editare_factura`) | `docs\diff_s5_agatare.patch` |
| `clase\comun.vc2` | COMUN | Aceeasi agatare, al doilea punct de intrare (`:2491`) | `docs\diff_s5_agatare.patch` |
| `programe\ofacturare_editare.prg` | COMUN | Helper nou `ScrieArticoleFacturaEditate` (marcheaza tot sters / invie ce ramane / insereaza linii noi / apeleaza recalculul Oracle) | `docs\diff_s5_helper_scriere.patch` |
| `utile\Teste\editare_factura\test_page3_articole.prg` | COMUN | Asteptari actualizate: `ColumnCount=15`, tip si editabilitate pe coloanele noi | `docs\diff_s5_teste.patch` |
| `utile\Teste\editare_factura\test_s5_validari_articole.prg` (nou) | COMUN | Suita headless: validari + SQL generat de helper, cu mock pe `goExecutor` | `docs\diff_s5_teste.patch` |
| `utile\Teste\editare_factura\test_ui_s5_grid_pret_achizitie.prg` (nou) | COMUN | Suita UI vizibila: coloana noua, needitabilitate pe linii de set, focus pe linie noua | `docs\diff_s5_teste.patch` |
| `utile\Teste\editare_factura\test_s5_scriere_reala.prg` (nou) | COMUN | Test cu scriere reala in Oracle, doua treceri, COMMIT real | `docs\diff_s5_test_scriere_reala.patch` |
| `utile\Teste\editare_factura\test_s5_discount_valuta.prg` (nou) | COMUN | Test parametru discount (NULL vs 0 vs valoare) + documente reale in valuta | `docs\diff_s5_discount_valuta.patch` |
| `utile\Teste\editare_factura\test_s5_rollback_real.prg` (nou) | COMUN | Calea de ROLLBACK la esec partial, cu eroare Oracle provocata deliberat | `docs\diff_s5_goluri_test.patch` |
| `utile\Teste\editare_factura\test_s5_al_doilea_intrare.prg` (nou) | COMUN | Al doilea punct de intrare (`comun.vc2:2491`) parcurs real | `docs\diff_s5_goluri_test.patch` |
| `clase\omodificari.vc2` | COMUN | Coloana `pret_achizitie` in grid, editabilitate per rand (linii de set needitabile, marcaj albastru), 5 validari noi in `inainte_de_do_termin` | diff aplicat (sters) |
| `clase\ofacturare_comun.vc2` | COMUN | Agatarea apelului `ScrieArticoleFacturaEditate` dupa `finalizeaza_modificare_nota` (primul punct de intrare, `do_editare_factura`) | diff aplicat (sters) |
| `clase\comun.vc2` | COMUN | Aceeasi agatare, al doilea punct de intrare (`:2491`) | diff aplicat (sters) |
| `programe\ofacturare_editare.prg` | COMUN | Helper nou `ScrieArticoleFacturaEditate` (marcheaza tot sters / invie ce ramane / insereaza linii noi / apeleaza recalculul Oracle) | diff aplicat (sters) |
| `utile\Teste\editare_factura\test_page3_articole.prg` | COMUN | Asteptari actualizate: `ColumnCount=15`, tip si editabilitate pe coloanele noi | diff aplicat (sters) |
| `utile\Teste\editare_factura\test_s5_validari_articole.prg` (nou) | COMUN | Suita headless: validari + SQL generat de helper, cu mock pe `goExecutor` | diff aplicat (sters) |
| `utile\Teste\editare_factura\test_ui_s5_grid_pret_achizitie.prg` (nou) | COMUN | Suita UI vizibila: coloana noua, needitabilitate pe linii de set, focus pe linie noua | diff aplicat (sters) |
| `utile\Teste\editare_factura\test_s5_scriere_reala.prg` (nou) | COMUN | Test cu scriere reala in Oracle, doua treceri, COMMIT real | diff aplicat (sters) |
| `utile\Teste\editare_factura\test_s5_discount_valuta.prg` (nou) | COMUN | Test parametru discount (NULL vs 0 vs valoare) + documente reale in valuta | diff aplicat (sters) |
| `utile\Teste\editare_factura\test_s5_rollback_real.prg` (nou) | COMUN | Calea de ROLLBACK la esec partial, cu eroare Oracle provocata deliberat | diff aplicat (sters) |
| `utile\Teste\editare_factura\test_s5_al_doilea_intrare.prg` (nou) | COMUN | Al doilea punct de intrare (`comun.vc2:2491`) parcurs real | diff aplicat (sters) |
| `docs\oracle_export.md` | COMUN | Corectie documentatie: `linesize 32767` in loc de 400 (cauza incidentului de export, vezi sectiunea 3) | fara patch dedicat |
| `docs\scripturi-migrare-db.md` | COMUN | Corectie documentatie: `UpdateVersiune` nu primeste extensia `.sql` in argument | fara patch dedicat |
| `versiune_db.txt` | ROAFACTURARE | `2026_08_08_01` -> `2026_08_09_02` | fara patch (fisier text, un rand) |

View File

@@ -3517,6 +3517,34 @@ luna inchisa, referentiate, sau care au urmasi (retur, factura din aviz, factura
> il inchide** — cele doua se unifica, nu se aleg. Din intrebarea 7 ramane deschisa **numai** partea de
> tipuri 48/49.
> **CERINTA DE EXECUTIE ADAUGATA IN RUNDA 17 — `IN_STOC` se incarca din document, nu din nomenclator.**
> Vine din consecinta 1 a deciziei 54 (vezi S10, „Trei consecinte"), si se prinde **aici**, nu la S12.
> Cu flag-ul de regenerare pornit, `IN_STOC` nu mai e re-derivat de `adauga_articol_factura`, ci **vine
> din formular** — deci valoarea pe care o incarca S8 devine valoarea care decide **descarcarea de
> gestiune la reemitere**. Azi loader-ul lui #6 o citeste din nomenclatorul curent
> (`ofacturare_editare.prg:302-303`), deci un articol devenit intre timp gestionabil (sau invers) ar
> face reemiterea sa atinga **alt stoc decat documentul initial**, tacut.
>
> Trei consecinte concrete pentru canalul de citire (intrebarea 1 din §8.2, *recomandat* (B),
> `cursor_editare_document`):
> - canalul trebuie sa intoarca `IN_STOC` **asa cum a fost la emitere**, nu `GESTIONABIL = B.IN_STOC`
> din nomenclatorul de azi, cum face `cursor_retur_document` (`PACK:3993-4000`). E un **al treilea
> argument** pentru procedura noua, langa `ID_VANZARE_DET` / `TAXCODE` si langa `ID_POL` / `ID_CTR`
> lipsa din `VVANZARI_ARTICOLE`;
> - **valoarea istorica nu e stocata nicaieri**: `IN_STOC` nu e coloana pe `VANZARI_DETALII` (verificat
> pe DB, vezi S10), traieste doar in temp. Deci primul pas al lui S8 pe aceasta cerinta e sa
> stabileasca **de unde se reconstituie** — fie din urma lasata in rulaje / gestiune pentru documentul
> respectiv, fie se accepta nomenclatorul curent ca aproximatie **declarata explicit**, fie se adauga
> coloana (migrare DB, deci **DB inainte de EXE**, ca la S10). **Nu se presupune niciuna dintre
> variante**; e o **preconditie de proiectare a lui S8**, nu un detaliu de implementare;
> - pe tipurile **48/49** cerinta se intalneste cu decizia 60: acolo invariantul e `IN_STOC = 0` prin
> constructie, deci valoarea incarcata trebuie sa fie `0` indiferent ce zice nomenclatorul azi.
>
> *Criteriu de test (intra in „gata cand" al lui S8):* un document emis cu un articol caruia i s-a
> schimbat intre timp `IN_STOC` in nomenclator, deschis in formular, poarta **valoarea de la emitere**;
> iar reemiterea lui lasa **stocul agregat neschimbat** (masurat inainte / dupa, nu prin inspectia
> codului).
> **Cerinta noua din S8b e mai blanda decat se credea:** lookup-ul „ultimul delegat / ultima masina"
> **are deja o garda** — `Empty(id_delegat) And Empty(id_masina)` (`ferestre_cere_date.vc2:3111`).
> Riscul ramane real, dar **numai** pe documentele fara delegat si fara masina. Raportul da inventarul
@@ -3537,7 +3565,8 @@ Formularul arata **identic** cu cel de introducere: fara banda de avertizare, fa
valorile initiale, fara panou de diferente (decizia 5). Se schimba titlul ferestrei si **butonul
principal** (decizia 9, vezi S8c).
*Gata cand:* formularul deschis pe un document existent arata exact documentul, pe fiecare tip de
sursa, si nu se distinge vizual de formularul de introducere.
sursa, si nu se distinge vizual de formularul de introducere; **si** liniile incarcate poarta `IN_STOC`
de la emitere, nu din nomenclatorul de azi (cerinta rundei 17, mai sus).
*Depinde de:* S7.
#### S8b — Rutarea scrierii dupa ce s-a schimbat
@@ -3878,6 +3907,9 @@ comportament nou:
**comportamentul de stoc** al reemiterii. Ca reemiterea sa fie identica, **S8 trebuie sa incarce
valoarea cu care s-a scris documentul initial** — si **azi nu o incarca**: loader-ul lui #6 o citeste
din nomenclatorul curent (`ofacturare_editare.prg:302-303`). **Flag-ul singur nu rezolva asta.**
**PRELUAT (runda 17) ca cerinta de executie in S8**, cu cele trei consecinte pentru canalul de citire
si criteriul de test — vezi caseta „CERINTA DE EXECUTIE ADAUGATA IN RUNDA 17" din S8. Aici nu mai e
nimic de decis.
2. **Se pierde o validare pe ramura comenzi.** Azi, `A.PRET = V_PRET_TEMP` + lipsa lui `EXCEPTION` fac
ca o linie care nu se mai potriveste cu comanda sa **opreasca** scrierea. Cu flag-ul pornit,
reemiterea unei facturi din comanda nu mai verifica linia fata de comanda. Decizia 54 pare sa vrea

View File

@@ -9,7 +9,7 @@ si verificari proprii, ca sa nu se amestece.
| — | #8 — denormalizare VANZARI | **mediu** (scop extins 06.08) | `PACK_FACTURARE` + ambele view-uri (COMUN) + reparare date | **TERMINAT si COMIS** 07.08.2026 (r17990-r17993). Planul a fost sters la curatenie; istoricul e in `progres.md` |
| — | [#7 — pret cu TVA pe linie](plan_07_pret_cu_tva_pe_linie.md) | mic-mediu | doar VFP, gridul de articole din `frm_facturare_articole` | **TERMINAT** 08.08.2026 (changelog 2.11.14). Editarea flagului pe o factura **deja salvata** a fost mutata explicit in #6 |
| 1 | [#6 — editare factura emisa](plan_06_editare_factura.md) | mediu | `omodificari.vc2` (COMUN) + `PACK_FACTURARE` | **IN LUCRU, aproape gata** — S1-S7 si S9 comise (S4b incheiat 11.08.2026). Ramane **S8**: 2 esecuri reale pe „factura din aviz" (rulajele nu se refac pe nota noua) + 3 tipuri de sursa neacoperite. Stare: antetul planului |
| 2 | [#13 — formular unificat + editare prin regenerare](plan_13_unificare_formular_facturare.md) | **mare** | `ofacturare.vc2` + `ofacturare.prg` + `PACK_FACTURARE` (COMUN) | propunere, 09.08.2026. Mockup: [`mockup_13_formular_unificat.html`](mockup_13_formular_unificat.html). **Perimetru comun cu #6** — de transat inainte de start |
| 2 | [#13 — formular unificat + editare prin regenerare](plan_13_unificare_formular_facturare.md) | **mare** | `ofacturare.vc2` + `ofacturare.prg` + `PACK_FACTURARE` (COMUN) | **PROIECTAT INTEGRAL, cod neatins** (17 runde de proiectare, 11.08.2026). Etapele I si II sunt proiectate story cu story (S1-S14); raman testele (S6, S12) si inchiderea (S13). **65 de decizii luate**, niciuna deschisa. Perimetrul cu #6 e transat: **#13 incepe dupa terminarea lui #6** (decizia 30). Mockup: [`mockup_13_formular_unificat.html`](mockup_13_formular_unificat.html). Stare curenta: `handoff_13_formular_unificat.md` |
| — | [#12 — nomenclator ca sursa de pret](plan_12_nomenclator_ca_lista_preturi.md) | mediu | depinde de varianta | valabil, **amanat** |
| — | [#11 — integrare politici de preturi](plan_11_integrare_politici_preturi.md) | mare | COMUN + ROAPRETURI | valabil, **amanat** |
| — | [#10 — integrare contracte](plan_10_integrare_contracte.md) | mare | COMUN + ROACONTRACTE | valabil, **amanat** |

View File

@@ -4,33 +4,63 @@
incheie. Planurile (`plan_0*.md`) spun *ce* e de facut; acesta spune *unde s-a ajuns*. Istoricul
sesiunilor nu se pastreaza aici — doar starea la zi, deciziile, faptele stabilite si datoriile.
Ultima actualizare: **10.08.2026, dupa-amiaza**. **S5 e TERMINAT, LIVRAT SI COMIS in git.**
**Decizia 42 (inclusiv discountul de antet) e IMPLEMENTATA si VERIFICATA, necomisa.** **S8 are acum
toate cele patru tipuri de sursa** — mai ramane matricea de editare.
Ultima actualizare: **11.08.2026, seara**. **Punctul #6 e practic terminat: S1-S7 si S9 sunt gata si
comise.** Ramane **S8** — si nu ca lipsa de acoperire, ci cu doua esecuri reale.
**PREDAREA CURENTA, pentru sesiunea noua: `docs\handoff_punct6_10082026_pm.md`** — se citeste
**prima**. Primul lucru de facut de acolo: **stergerea celor sase documente parazite** (`1051`, `1056`,
`1057`, `1058`, `1059`, `1060`) prin aplicatie.
**PREDAREA CURENTA e chiar acest fisier.** Handoff-urile intermediare intre sesiuni au fost
desfiintate (11.08.2026, decizia lui Marius) impreuna cu diff-urile deja aplicate; ce era durabil in
ele a intrat in antetele fisierelor de test sau in mesajele de commit. Nu mai cauta `handoff_*.md`.
Predarea anterioara, tot valabila pe reguli si comenzi: `docs\handoff_punct6_dupa_s5.md`. Dosarul de
livrare al lui S5: `docs\livrare_s5.md`. Jurnalul blocului (decizii 38-41, incidente):
`docs\handoff_s5.md`.
**De facut, in ordine:**
**Comis in git, pe ramura `punct6-s4-runda3`**: `COMUN` `1c42ae0` (13 fisiere), `ROAFACTURARE`
`316b6f7` (changelog **2.11.15** + `versiune_db.txt` pe `2026_08_09_02`). **Nefacute deliberat**:
`git push` si `svn commit` — publicare pe server, decizia lui Marius. Cele doua scripturi Oracle sunt
mutate in `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08` cu `svn add` (status `A`, necomis).
1. **Stergerea celor sase documente parazite** (`1051`, `1056`, `1057`, `1058`, `1059`, `1060`) prin
aplicatie — ramasa din blocul de creare documente pentru S8.
2. **S8 — doua esecuri reale.** Pe „factura din aviz" (tip 4), din **ambele** puncte de intrare,
rulajele nu se refac pe nota noua (`Reccount(trul)=0`): `test_s8_matrice_surse.prg` da
**42 PASS / 2 FAIL**. Tot acolo, trei tipuri de sursa au fost sarite la ultima rulare (lista de
preturi `1048`, aviz `1052`, factura din contract `1055`), iar harnessul
`COMUN\utile\Teste\editare_factura\creeaza_documente_s8.prg` **nu a scris inca niciun document** —
capcanele de mediu (plaja de serii care chiar prinde, ordinea lui `mock_amessagebox`) sunt scrise
in antetul lui.
3. **Rebuild `roafacturare.exe`** din IDE si verificarea pe ecran, pe `1140895` / `1140921` — ambele
contin `IV93900901` (`id_articol = 3598545102`), adica exact cazul corectat pe 11.08.
4. **Punctele A si B** din `docs\rec_s4b_etapa2.md` — **deja implementate**, asteapta doar
confirmarea lui Marius. Nu sunt lucru ramas.
5. **`git push` nefacut** in ambele repo-uri (remote `romfast`) — decizia lui Marius.
**Starea la incheierea sesiunii — nimic periculos, verificat nu presupus**: zero procese `vfp9.exe`,
zero tranzactii Oracle deschise, write-back dovedit prin **reconversie si diff** pe toate cele trei
`.vc2` (nu pe mtime — `txt2vcx.ps1:300` il rescrie), `docs\verificare_s5_writeback.md`. Toti agentii
inchisi.
**Comis pe ramura `punct6-s4-runda3`, 11.08.2026**: `COMUN` `40a112a` (S4b etapa 2 — butonul,
dialogul `frm_sincronizare_articole`, `id_articol` de la `I` la `N(20)` in toate cele 6 locuri, si
doua `This.` -> `Thisform.` care faceau butonul „Adauga articol" sa dea eroare la orice click real) si
`93a2718` (harnessul S8 intra in versionare); `ROAFACTURARE` `40933df` (changelog 2.11.15) si
`d9f5ca4` (`docs\` intra in git). In SVN: **r18011** si **r18012**.
**Ce ramane din planul #6**: **S8** (matricea pe tipuri de sursa — se creeaza in dev documentele
lipsa) si **implementarea deciziei 42** (articolele raman vizibile, dar needitabile, cand documentul e
in eFactura). **S4b, S7 si S9 sunt GATA** (10.08.2026 — S4b inchis prin decizia 43, fara enumerarea
vechi -> nou). Plus verificarea pe ecran de Marius.
Detaliu si ordinea recomandata: `docs\handoff_punct6_dupa_s5.md`.
**Cifre de test, citite din log, nu din rapoarte**: `test_s4b_sincronizare` **42/0** (include cazul de
regresie `id_articol = 3598545102`, dovedit cu control negativ — cu campul `I` iese perechea
`Adaugare`+`Semnalare` in loc de `Modificare`), `test_s4b_dialog` **35/0**, `test_s7_rotunjire` **6/0**,
`test_s8_matrice_surse` **42 PASS / 2 FAIL**.
**Doua capcane de mediu platite pe 11.08, valabile pentru orice sesiune viitoare:**
- **`.FXP` vechi.** `vfp9.exe -A -T test.prg` poate executa **bytecode vechi** si „reusi" degeaba — o
rulare a reprodus identic logul dinainte de o editare deja scrisa pe disc. **Sterge `.FXP`-ul suitei
ca parte din comanda de rulare.** `SET PROCEDURE TO ...prg ADDITIVE` recompileaza corect, deci
suspiciunea priveste `.FXP`-ul suitei, nu al modulelor.
- **`GETFONT()`.** Un formular instantiat headless fara `goApp` ajunge in `_frmbase.Init` la
`goApp.ReadIni`; eroarea e doar logata, parametrul cade pe `.F.` si `accessibility` deschide un
dialog modal care atarna procesul si apare pe ecranul lui Marius. Fixul e **in harness**
(`PUBLIC goApp, gcAcces` + `Createobject("wzApplication")`), **nu** in `_frm_base.vc2` — clasa e
partajata de toata suita, iar in productie `goApp` exista mereu. Ruleaza mereu cu garda de timp.
**Documentatia, dupa curatenia din 11.08.2026**: `docs\` e acum versionat in **git si SVN** — era in
afara oricarui control de versiuni. In `docs\cercetare\` au ramas **91** de rapoarte: sunt baza de
dovezi a planului #13 (85 de trimiteri din `plan_13`), **nu le sterge**. Alte **14** cercetari
trans-proiect au trecut in `COMUN\docs\cercetare\` (valuta si curs, TVA/VANZARI, consumatorii
`VANZARI` in suita, integrarile #10/#11/#12, watchdog VFP, proiectarea Oracle a lui S5, view-ul
`VVANZARI_ARTICOLE`), iar 20 de rapoarte de executie ale lui #6 au fost sterse.
**Starea la incheierea sesiunii — verificat, nu presupus**: zero procese `vfp9.exe`, zero tranzactii
Oracle deschise (in acest bloc nu s-a atins Oracle), niciun fisier binar editat fara write-back,
ambii arbori git curati fata de commituri.
## S8 — VERIFICAT PE VENDING PRODUCTIE, 10.08.2026: nu deblocheaza avizul
@@ -173,7 +203,7 @@ Mecanismul de editabilitate per rand exista deja din S5 in `omodificari.vc2` —
conditie la nivel de formular.
**IMPLEMENTATA SI VERIFICATA, 10.08.2026** (agent `d42-efactura`, din alta sesiune; verificata pe disc de
orchestratorul acestei sesiuni). **Necomisa.** Diff: `docs\diff_d42_efactura_readonly.patch`. Raport:
orchestratorul acestei sesiuni). **Necomisa.** Diff: diff aplicat (sters). Raport:
`docs\cercetare\rec_d42_efactura.md`. Forma implementata: flag `lArticoleReadOnly` pus in
`frm_modific2024.Show` (`:14789-14813`), impins peste `.When`-urile existente din S5
(`:16550`, `:16557`, `:16571`, `:16588`), `cmdAdaugaArticol`/`cmdStergeArticol.Enabled` plus garda
@@ -329,7 +359,7 @@ editare factura de vanzare" + 2 puncte in „Implicatii practice". Acopera condi
puncte de intrare cu garzile lor, secventa de scriere in tranzactia manuala unica, cei 4 pasi din
`ScrieArticoleFacturaEditate`, `recalculeaza_totaluri_vanzari`, view-ul `VVANZARI_ARTICOLE` si
comportamentul gridului. Regula deciziei 38 e scrisa **ca regula**, fara numarul deciziei, conform
conventiei de comentarii. Diff: `docs\diff_s9_flux_nota_jurnal.patch`. Raport:
conventiei de comentarii. Diff: diff aplicat (sters). Raport:
`docs\cercetare\rec_s9_documentatie.md`.
**Verificat de orchestrator pe disc**, nu din raport: modificat **doar** fisierul de documentatie
@@ -347,7 +377,7 @@ documentatie e corect. **Tipar de retinut**: constatarea „nu exista X in metod
## #6 / S5 — scrierea sumelor editate in Oracle, TERMINAT SI COMIS 10.08.2026
**Starea completa a blocului e in `docs\handoff_s5.md`** — se citeste inaintea acestei sectiuni.
**Starea completa a blocului e in handoff intermediar (sters)** — se citeste inaintea acestei sectiuni.
Aici doar ce trebuie sa stie o sesiune noua din prima:
- **Codul e scris integral si write-back-ul e facut** pe toate cele patru fisiere atinse:
@@ -359,19 +389,19 @@ Aici doar ce trebuie sa stie o sesiune noua din prima:
(view-ul, cu `ID_VANZARE_SET` si `PRET_ACHIZITIE`). Pachetul e `VALID`, zero erori.
`versiune_db.txt` = **`2026_08_09_02`**. Scripturile sunt in `docs\`, **nu** in `SCRIPTURI_CLAR`.
- **Deciziile 38-41** (ordonarea scrierii, liniile de set, `PRET_ACHIZITIE`, discountul ca parametru)
sunt in `handoff_s5.md`. **Decizia 38 corecteaza planul S5**: recalculul se apeleaza din VFP, nu
sunt in handoff intermediar (sters). **Decizia 38 corecteaza planul S5**: recalculul se apeleaza din VFP, nu
din `finalizeaza_modificare_nota`, altfel ar calcula totalurile pe liniile dinainte de editare.
- **Runda 2 pe grid, INCHISA** (`s5-grid`, 09.08.2026 tarziu): cele trei corectii de code-review sunt
in binar. **Write-back verificat prin reconversie si diff, nu pe mtime** — textul regenerat din
binar e identic octet cu octet cu `.vc2` (`txt2vcx.ps1:300` rescrie mtime-ul textului, deci mtime
nu dovedeste nimic). O a patra constatare s-a dovedit **nerealizabila** pe codul de acum si nu se
repara — detalii si conditia care ar activa-o, in `handoff_s5.md`.
repara — detalii si conditia care ar activa-o, in handoff intermediar (sters).
- **Regresia e la baseline pe toate cele sase suite**, cifre numarate din loguri de orchestrator,
toate rulate **dupa** write-back (binar 23:15:50): `test_page3_articole` **14/2** (23:19:52),
`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** (23:27:52).
- **Acoperirea cu teste, LIVRATA** (`s5-teste`, `docs\cercetare\rec_s5_teste.md`,
`docs\diff_s5_teste.patch`): suita noua headless `test_s5_validari_articole.prg` **35 PASS / 0 FAIL**
diff aplicat (sters)): suita noua headless `test_s5_validari_articole.prg` **35 PASS / 0 FAIL**
(validarile din `inainte_de_do_termin`, garda de no-op, SQL-ul din `ScrieArticoleFacturaEditate` cu
mock pe `goExecutor`, fara Oracle) si suita noua pe formular vizibil
`test_ui_s5_grid_pret_achizitie.prg` **14 PASS / 0 FAIL** (15 coloane, linie de set needitabila cu
@@ -427,7 +457,7 @@ Aici doar ce trebuie sa stie o sesiune noua din prima:
- **Capcana platita, sa nu se repete**: exportul `all_source` cu `linesize` prea mic **rupe linii
lungi prin mijlocul identificatorilor** si corupe tacut orice script construit din el. Un script
de pachet se face de la **ultimul script aplicat din `SCRIPTURI_CLAR`**, nu de la un export.
Detalii in `handoff_s5.md`; `COMUN\docs\oracle_export.md` a fost corectat.
Detalii in handoff intermediar (sters); `COMUN\docs\oracle_export.md` a fost corectat.
## COMIS PE BRANCH `punct6-s4-runda3` — 09.08.2026, NEIMPINS, NEINTRAT IN SVN
@@ -458,7 +488,7 @@ Cand documentul e in valuta (`tvanz.in_valuta = 1`), dialogul `frm_articol_factu
`frm_facturare_articole2` folosesc **activ, in productie**, aceeasi ramura `tip_valuta = 1`, deci
orice atingere a codului dialogului ar fi fost o regresie potentiala pe formularul de compunere.
Premisa initiala a deciziei 35 (ca ar fi nevoie de `poDate.in_valuta`/`zi_curs`/`id_valuta`) era
gresita — vezi corectia de la decizia 35 si `docs\handoff_decizia35_valuta_dialog.md`.
gresita — vezi corectia de la decizia 35 si handoff intermediar (sters).
**Verificat de orchestrator pe disc** (cifre numarate din loguri): `test_adauga_linie_valuta.prg`
extins la **16 PASS / 0 FAIL** — acopera **ambele** ramuri, scenariul A (intrare in RON, conversie la
@@ -470,8 +500,8 @@ headless de la datoria 7), `test_incarca_vanzare_din_nota` **5/0**, `test_adauga
**20/0**, `test_ui_sterge_linie` **8/0**, `test_verdict_act_rul` **26/0**. Rulari 18:57-18:59, toate
**dupa** ultima editare de cod (`omodificari.vc2` 18:53:21, `ofacturare_editare.prg` 18:52:59).
Cens de octeti `2 aa / 2 e3 / 2 fe`, zero `EF BF BD`. Text si binar sincrone, **necomis**.
Diff: `docs\diff_s4_valuta_dialog.patch` + `docs\diff_s4_valuta_dialog_prg.patch` +
`docs\diff_s4_valuta_dialog_test.patch`. Raport: `docs\cercetare\rec_s4_valuta_dialog.md`.
Diff: diff aplicat (sters) + diff aplicat (sters) +
diff aplicat (sters). Raport: `docs\cercetare\rec_s4_valuta_dialog.md`.
**Ramas de verificat pe ecran de Marius** (netestabil headless, dialogul e modal `Show(1)`): tastarea
reala in caseta de pret pe un document in valuta, eticheta de valuta afisata, si interactiunea cu
@@ -508,7 +538,7 @@ aplica", ascundere pe transfer/custodie, alegere cont pe grupa de tip, corectie
nestocata). Cens de octeti: stricat si reparat (acelasi tipar cunoscut), identic cu baseline la
final. **Scris in binar** (write-back OK dupa un fidelity-check picat pe formatarea liniilor goale,
rezolvat prin adoptarea textului regenerat), **necomis**. Diff:
`docs\diff_s4_runda3c2_verdict.patch` + `docs\diff_s4_runda3c2_ofacturare_editare.patch`.
diff aplicat (sters) + diff aplicat (sters).
**Reverificat de orchestrator pe starea de pe disc** (nu din raportul agentului): cifrele numarate
din loguri, nu citite din raport — toate se confirma, inclusiv cele 18/0 ale suitei noi. Rularile
@@ -535,7 +565,7 @@ valoare. Pe `cod=1140895`: `Total ACT` = `Total RUL` = **1924.59**, verdict **si
(asertia veche care astepta "divergent" a fost inversata, cu verificare explicita a cifrei).
Regresie neschimbata + suita dedicata **26 PASS / 0 FAIL** (18 vechi + 8 noi: excludere
`id_tip_rulaj=3`, includere `id_tip_rulaj=0`, cele trei conturi rate/contract). Scris in binar,
necomis. Diff: `docs\diff_s4_runda3c3_decizii_36_37.patch` + `docs\diff_s4_runda3c3_test.patch`.
necomis. Diff: diff aplicat (sters) + diff aplicat (sters).
**Reverificat de orchestrator pe disc**: cifre numarate din loguri (26/0 pe suita dedicata, regresie
`14/2 · 5/0 · 20/0 · 6/0 · 8/0`), rulari 18:40-18:42 **dupa** ultima editare (18:34:03); filtrul din
cod e `SUM (Nvl(cant,0)+Nvl(cante,0))*Nvl(pretvtva,0) FOR Nvl(sters,0)=0 AND Nvl(id_tip_rulaj,0)=0`
@@ -549,7 +579,7 @@ inchide capcana prefixului `411`/`4111` mai bine decat un `==` repetat; (3) exis
**Ce urmeaza** (stabilit de Marius, 09.08.2026): **intrarea directa in valuta in
`frm_articol_factura`** — decizia 35. **Premisa deciziei a fost corectata** intre timp: nu cere
atins `ofacturare.vc2` (vezi decizia 35 mai jos si `docs\handoff_decizia35_valuta_dialog.md`).
atins `ofacturare.vc2` (vezi decizia 35 mai jos si handoff intermediar (sters)).
Ultima actualizare anterioara: **09.08.2026**, dupa **cele doua defecte de pe pagina de articole
(culoare + valuta), REZOLVATE**.
@@ -585,8 +615,8 @@ din log, nu din raport**, si dovada ca rularea a ajuns la capat e linia de `REZU
Raportate dupa livrarea sub-blocului B partea 2 (mai jos). Ambele in `COMUN\clase\omodificari.vc2`
(+ `ofacturare_editare.prg` pentru al doilea). Write-back facut (fidelity check OK), text si binar
sincrone, **necomise**. Backup dinaintea fixului: `omodificari.vc2.pre_fix_culoare.bak`,
`ofacturare_editare.prg.pre_fix_culoare.bak`. Diff: `docs\diff_s4_fix_culoare_valuta.patch` +
`docs\diff_s4_fix_culoare_valuta_ofacturare_editare.patch`.
`ofacturare_editare.prg.pre_fix_culoare.bak`. Diff: diff aplicat (sters) +
diff aplicat (sters).
**Reverificat de orchestrator pe starea finala de pe disc**: `ofacturare_editare.prg` fusese modificat
la 17:08:48, adica **la 40 de secunde dupa ultima rulare de test** (17:08:08), deci starea livrata nu
era acoperita de nicio suita. Rerulat `test_page3_articole.prg` pe starea de pe disc: **14 PASS /
@@ -675,7 +705,7 @@ anterioare** (stergerea logica, sub-blocul B partea 1) — nereparat, predat mai
octeti stricat si reparat de 2 ori in sesiune (acelasi tipar cunoscut), identic cu baseline la
final: `2 aa/2 e3/2 fe`, zero `EF BF BD`. **Scris in binar (write-back OK dupa 2 fidelity-check-uri
picate pe ordine, rezolvate prin adoptarea textului regenerat), necomis.** Diff:
`docs\diff_s4_runda3b2_adaugare.patch` (+ `docs\diff_s4_runda3b2_ofacturare_editare.patch`).
diff aplicat (sters) (+ diff aplicat (sters)).
Raport: `docs\cercetare\rec_s4_runda3b2.md`.
Inaintea acesteia, in aceeasi zi: **sub-blocul C, PARTIAL — bara de totaluri + discount de
@@ -702,7 +732,7 @@ acelasi tipar de infrastructura documentat mai jos, nu problema de cod). Cens de
2 fe`, zero `EF BF BD`, identic inainte/dupa (stricat si reparat de mai multe ori in timpul editarii,
capcana deja cunoscuta). **Scris in binar (write-back OK dupa 3 rulari, fidelity-check picat pe
ordine de fiecare data, rezolvat prin adoptarea textului regenerat), necomis.** Diff:
`docs\diff_s4_runda3c_totaluri.patch` (+ `docs\diff_s4_runda3c_ofacturare_editare.patch`, izolat).
diff aplicat (sters) (+ diff aplicat (sters), izolat).
Raport: `docs\cercetare\rec_s4_runda3c.md`. **Verdictul de corelatie cu `ACT`/`RUL` NU e facut** —
formulele sunt deja stabilite si verificate pe date in `rec_suma_act.md`, predat ca partea 2 a
sub-blocului C (contul pe tip, filtrul `cod+an+luna`, indicatorul cu 3 stari, threading `an`/`luna`
@@ -714,7 +744,7 @@ Inaintea acesteia, in aceeasi zi: **sub-blocul B, PARTIAL — doar stergerea de
e facuta** — sub-blocul s-a dovedit prea mare pentru un context si a fost impartit, cu aprobarea
briefingului. Cercetarea de contract pentru adaugare (proprietati `poArticol`/`poDate` citite de
dialog, cum se ocoleste `gnScadereStoc`, ce lipseste inca — picker de articol) e completa si
predata in `docs\handoff_s4_runda3b_adaugare.md`. Testat: regresie neschimbata (`14/2`, `5/5`),
predata in handoff intermediar (sters). Testat: regresie neschimbata (`14/2`, `5/5`),
plus test UI nou dedicat (`test_ui_sterge_linie.prg`). **Atentie la cifra**: logul are **6 PASS /
0 FAIL**, nu 7/7 cum s-a raportat initial — rularea s-a **taiat la `READY`**, adica exact la
handshake-ul de captura, si n-a ajuns la linia de `REZULTAT`. Dovedit: butonul exista si e vizibil,
@@ -724,13 +754,13 @@ dupa handshake si n-a mai rulat. **Captura de ecran n-a putut fi obtinuta** (`vf
desi procesul chiar a rulat testul complet pana la capat de fiecare data — problema de
infrastructura/masina ocupata, nu de cod; detalii in raport). **Scris in binar (write-back
FACUT dupa un fidelity-check picat pe ordine, rezolvat prin adoptarea textului regenerat),
necomis.** Diff: `docs\diff_s4_runda3b_linii.patch`. Raport: `docs\cercetare\rec_s4_runda3b.md`.
necomis.** Diff: diff aplicat (sters). Raport: `docs\cercetare\rec_s4_runda3b.md`.
Inaintea acesteia, in aceeasi zi: **extinderea la cei 5 apelanti `frm_modific2024` + linia din
`roagest.prg`** — helper nou `PregatesteArticoleFacturaEditare` in `ofacturare_editare.prg`, apelat
gardat inainte de `Createobject` la `afisjurcom.do_modifica` (registrul jurnal, viu in ROACONT),
`anaf_efactura.importmodifica` si cele doua `.sc2` de import; linia `SET PROCEDURE TO
ofacturare_editare.prg` adaugata in `roagest.prg`. Detalii: `docs\cercetare\rec_s4_apelanti.md`,
diff `docs\diff_s4_apelanti_frm_modific2024.patch`. Mai devreme: **rezolvarea datoriei 6** — baza
diff diff aplicat (sters). Mai devreme: **rezolvarea datoriei 6** — baza
de regresie #6/S4 e din nou solida, iar suitele nu mai hardcodeaza documente: si-l descopera
singure, deci nu mai mor la urmatoarea realocare de `cod`. Mai devreme inca: doua defecte de
editare pe pagina de articole (coloanele cantitate/pret needitabile, valoare defazata la bifa
@@ -774,7 +804,7 @@ nevoie de alta sursa pentru plafon.
## #6, runda 1 (S1-S3) — implementat 08.08.2026, corectii 08.08.2026
Diff: `docs\diff_consolidat_runda1_3.patch` + `docs\diff_runda4_scoate_garda.patch` (netrimise inca
Diff: diff aplicat (sters) + diff aplicat (sters) (netrimise inca
la commit, asteapta review). Patch-urile per runda raman pe disc pentru istoric.
- **`COMUN\clase\ofacturare_comun.vc2`**, clasa `frm_facturi`: metoda `do_editare_factura`
@@ -792,7 +822,7 @@ la commit, asteapta review). Patch-urile per runda raman pe disc pentru istoric.
`Createobject('frm_modific2024')` pica cu "Class definition not found" chiar si in productie):
`SET CLASSLIB TO omodificari.vcx additive`. ROAFACTURARE nu incarcase niciodata aceasta clasa —
se foloseste azi doar din ROACONT/ROAGEST (registrul jurnal).
- **Corectii de review aplicate 08.08.2026** (`docs\diff_runda2_corectii.patch`):
- **Corectii de review aplicate 08.08.2026** (diff aplicat (sters)):
- `IncarcaCursoareModificareNota` propaga acum esecul: pe eroare Oracle la interogarea `vrul_tot` sau
`vrul_obinv_tot` face `RETURN .F.` (curatand cursoarele deschise pana atunci), nu mai continua pana la
`RETURN .T.` final ca si cum ar fi reusit. **Corectie de premisa fata de constatarea initiala**:
@@ -805,7 +835,7 @@ la commit, asteapta review). Patch-urile per runda raman pe disc pentru istoric.
in `afisjurcom.do_modifica` la `buton=1`) — corect prin constructie, pentru ca acum ajunge acolo doar
daca incarcarea a reusit integral.
- **Garda pe `id_set`: adaugata in runda 2, rafinata in runda 3, SCOASA DE TOT in runda 4**
(`docs\diff_runda4_scoate_garda.patch`, decizia 24). Istoric, ca sa nu se reia: premisa ei era ca
(diff aplicat (sters), decizia 24). Istoric, ca sa nu se reia: premisa ei era ca
`PACK_FACTURARE.scrie_discount` scrie randurile `DISCOUNT`/`TVA DISCOUNT` cu `id_set + 5`, deci o
nota poate avea 2 `id_set`. **Fals la destinatie**: `cumuleaza_note_act_temp` normalizeaza inainte
de `ACT`, offsetul e tranzitoriu. Pe date: 558 de note legate de `VANZARI` cu un singur `id_set`,
@@ -895,7 +925,7 @@ sincronizate**, dar **fara diff livrat si fara raport** — runda nu e inchisa.
inofensiv; zero `CREATE SQL VIEW` / `USE ... VIA` in toata ierarhia de clase.
- **B.2 (marcaje stare linii) nu e in scope runda 1** — grid-ul e strict readonly; marcajele sunt runda 2.
- **Runda 1 e INCHISA pe cod si testata**, asteapta doar review-ul lui Marius. Diff:
`docs\diff_s4_runda1_page3.patch` (2 fisiere, fata de backup-urile de dinainte de S4). Raport:
diff aplicat (sters) (2 fisiere, fata de backup-urile de dinainte de S4). Raport:
`docs\cercetare\rec_s4_runda1.md`. Instrumentarea de depanare a fost scoasa din suita si suita
rerulata dupa curatare — 7 PASS, zero erori. `test_baseline_isolation.prg` sters (temporar prin
design, si cu concluzie nula: testa copia ROACONT). **Fara commit — se asteapta aprobarea.**
@@ -935,14 +965,14 @@ sincronizate**, dar **fara diff livrat si fara raport** — runda nu e inchisa.
`cod=1139934`->`id_vanzare=882` si un test de garda care scoate `ofacturare_editare.prg` din
`SET PROCEDURE` si verifica `PageCount=2`). Verificat separat (test dedicat) ca `SCAN...ENDSCAN` din
`IncarcaVanzareDinNota` continua corect chiar daca IncarcaVanzareNota schimba workarea in interiorul
buclei. Write-back `.vc2`->binar OK (fidelity check trecut). Diff: `docs\diff_s4_runda2_view_pozitionare.patch`.
buclei. Write-back `.vc2`->binar OK (fidelity check trecut). Diff: diff aplicat (sters).
Raport: `docs\cercetare\rec_s4_runda2.md`. **Fara commit — asteapta review.**
- **ANCORAREA COLOANELOR — REZOLVATA prin view Oracle dedicat** (decizia 26, 08.08.2026).
`VVANZARI_ARTICOLE` e **creat si validat** pe `MARIUSM_AUTO` (`VALID`, 21 de coloane, verificat independent prin
`sqlplus` dupa aplicare): `id_vanzare` + cele 20 consumate azi, valori **RAW**, fara conversie
valutara, fara filtru `sters` (apelantul filtreaza, ca la `vact_tot`/`vrul_tot`). Script:
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_08_01_COMUN_VVANZARI_ARTICOLE.sql` (CRLF pur, idempotent,
**necomis in SVN**). Proiectarea: `docs\cercetare\rec_view_articole_vanzare.md`.
**necomis in SVN**). Proiectarea: `COMUN\docs\cercetare\rec_view_articole_vanzare.md`.
- **`id_vanzare` era omis** din `SELECT`-ul vechi desi e cheia de filtrare — omisiune reala, corectata.
- **`FACT_VFACTURI_DETALII` exista si a fost respins motivat**: recalculeaza `pret`/`discount_unitar`
la cursul curent, pentru tiparire. Editarea are nevoie de valorile stocate, ca S5 sa scrie inapoi
@@ -994,7 +1024,7 @@ sub-blocuri mici, cu cate un agent proaspat, ca review-ul sa ramana mic.
**Sub-blocul A e SCRIS IN BINAR** (08.08.2026). Contrar a ce scria aici, write-back-ul s-a facut:
`omodificari.vct` contine `cSubtotalArt`, `lmodificat`, `cPretCuTvaArt`, iar textul are
`ColumnCount = 14`. Fidelity-check-ul picat descris in `docs\handoff_s4_runda3a.md` a fost depasit
`ColumnCount = 14`. Fidelity-check-ul picat descris in handoff intermediar (sters) a fost depasit
(remediul era ordinea `Header1` dupa `_checkbox1` la `cPretCuTvaArt`). Ramane necomis, ca tot restul.
Doua rezultate stabilite in runda 3A, de nu mai reluat:
@@ -1019,7 +1049,7 @@ Ultimul camp se numeste **`valoare`** (fost `subtotal`), vezi sectiunea de defec
## #6, doua defecte de AFISARE pe pagina de articole — REZOLVATE 08.08.2026, dovedite pe ecran
Raportate de Marius dupa testarea pe ecran. Ambele in `frm_modific2024`. Write-back facut, text si
binar sincrone, **necomise**. Diff: `docs\diff_fix_grid_tvd_blank.patch`. Raport:
binar sincrone, **necomise**. Diff: diff aplicat (sters). Raport:
`docs\cercetare\rec_fix_grid_tvd_blank.md`.
- **Grid-ul de articole aparea COMPLET GOL** (nici macar coloane), desi `tvd` avea randuri. Cauza:
@@ -1078,7 +1108,7 @@ totaluri (deciziile 20 si 25).
Raportate de Marius dupa testarea pe ecran a rundei 3A, in `COMUN\clase\omodificari.vc2`
(`frm_modific2024`) si `COMUN\programe\ofacturare_editare.prg`. Write-back facut (fidelity check
trecut), text si binar sincrone, **necomise**. Diff: `docs\diff_fix_grid_editabil_subtotal.patch`.
trecut), text si binar sincrone, **necomise**. Diff: diff aplicat (sters).
Backup-uri dinaintea fixului: `COMUN\clase\omodificari.vc2.pre_fix3a.bak`,
`COMUN\programe\ofacturare_editare.prg.pre_valoare.bak`.
@@ -1128,7 +1158,7 @@ recreeaza cursorul.
## #6, S4 runda 3 sub-blocul B — stergerea de linii GATA, adaugarea predata mai departe, 09.08.2026
Detalii complete: `docs\cercetare\rec_s4_runda3b.md` (implementare + testare) si
`docs\handoff_s4_runda3b_adaugare.md` (cercetarea de contract pentru partea neinceputa).
handoff intermediar (sters) (cercetarea de contract pentru partea neinceputa).
- **Stergere logica** — buton nou `cmdStergeArticol` pe `pgfArticole.PAGE3`
(`omodificari.vc2:12260-12274`), `Click` comuta `tvd.sters` intre 0/1 si seteaza
@@ -1171,7 +1201,7 @@ Detalii complete: `docs\cercetare\rec_s4_runda3b.md` (implementare + testare) si
activ al lui Marius: RustDesk, VS Code, PL/SQL Developer, Explorer), nu de cod. Recomandare:
o trecere de confirmare vizuala cand masina e libera, inainte de commit — nu blocheaza
livrarea.
- Diff: `docs\diff_s4_runda3b_linii.patch` (162 linii, scopat strict pe aceasta lucrare —
- Diff: diff aplicat (sters) (162 linii, scopat strict pe aceasta lucrare —
reconstruit dintr-un backup `.pre_runda3b.bak` obtinut prin reversul exact al editarilor,
pentru ca nu s-a luat backup INAINTE de prima editare).
@@ -1273,9 +1303,9 @@ s-a facut cu `COMUN\utile\curatenie.ps1` (47 de intrari: patch-uri, handoff-uri,
`utile/Teste/editare_factura/test_page3_articole.prg`, plus cele 3 fisiere `.md` din `docs\`
(encoding). `svn status` arata in plus binarele `clase\ofacturare_comun.vcx`/`.vct` si
`clase\omodificari.vcx`/`.VCT` ca `M`. Arborele ROAFACTURARE principal e curat. Diff-urile de review:
`docs\diff_s4_fix_butoane_crsjtva.patch`, `docs\diff_reguli_encoding.patch`,
`docs\raport_sweep_encoding.md`, `docs\diff_fix_grid_tvd_blank.patch`,
`docs\diff_fix_grid_editabil_subtotal.patch`.
diff aplicat (sters), diff aplicat (sters),
`docs\raport_sweep_encoding.md`, diff aplicat (sters),
diff aplicat (sters).
### Copiile de `COMUN` din ROACONT si ROAGEST: aduse la r18010 (08.08.2026)
@@ -1290,12 +1320,12 @@ pierdut; cer `svn resolve`, decizia e a lui Marius. Au ramas modificate local do
## #6, S4 runda 2 — ce contine, pe scurt
Starea completa, inventarul si ce ramane: **`docs\handoff_sesiune_08082026_e.md`**. Pe scurt: view-ul
Starea completa, inventarul si ce ramane: **handoff intermediar (sters)**. Pe scurt: view-ul
`VVANZARI_ARTICOLE` consumat cu `select *`, pozitionarea pe triplete (decizia 27), garda pentru ROACONT/ROAGEST,
`AMESSAGEBOX` pe erorile Oracle, structura unica pentru cursorul `tvd`. Validata pe starea curenta,
dupa redenumirea view-ului si taierea comentariilor: fidelity check trecut, suita **10/10** si
**5/5** la data validarii (cifrele nu mai sunt valabile azi — vezi datoria 6), exit 0, zero
dialoguri. Diff: `docs\diff_s4_runda2_view_pozitionare.patch`.
dialoguri. Diff: diff aplicat (sters).
`vvanzari_detalii` / `vvanzari_detalii_tot` **nu se extind** — motivele pe date, in handoff: 11 coloane
lipsa, cost de 3.7x fata de `VVANZARI_ARTICOLE`, si `select * from vvanzari_detalii_tot` in `oproceduri_listari.prg`
@@ -1313,10 +1343,10 @@ din ~10 produse.
2. **Build ROAAUTO, la Marius**: rebuild din IDE + test UI pe un deviz real — fara el corectia S7 din
#8 n-are efect. Partea ROAFACTURARE e inchisa (build + deploy 2.11.14, 08.08.2026).
**Agentul nu atinge `.PJX`/`.PJT`/`.exe`.**
3. **Changelog ROAAUTO** — textul propus e in `docs\cercetare\rec_s10_s12.md`, neaplicat in
3. **Changelog ROAAUTO** — textul propus e in `COMUN\docs\cercetare\rec_s10_s12.md`, neaplicat in
`changelog_roaauto.txt`.
4. **Curatarea tabelei `VERSIUNE`** de numele vechi de scripturi (`_02`..`_06`), cu inregistrari
multiple din aplicarile succesive. `docs\cercetare\s10_curata_versiune.sql`, de extins cu numele
multiple din aplicarile succesive. `COMUN\docs\cercetare\s10_curata_versiune.sql`, de extins cu numele
vechi. Fara impact functional, doar istoric zgomotos.
5. **Puncte nedecise de la #8, niciunul blocant**:
- `tip=1` cu `id_comanda` — 16 facturi pe productie care n-ar trebui sa aiba;
@@ -1324,7 +1354,7 @@ din ~10 produse.
afisa un `/` singur. Zero documente azi in ambele scheme;
- cele 620 de randuri cu `ID_VALUTA` NULL — normalizarea la `0`/`1`;
- **propagarea corectiei `xmlefactura.prg`** in cele ~16 cai ramase din alte produse ROA.
Inventarul: `docs\cercetare\rec_consumatori_vanzari.md`. Grup A (byte-identice, acelasi patch):
Inventarul: `COMUN\docs\cercetare\rec_consumatori_vanzari.md`. Grup A (byte-identice, acelasi patch):
ROAACNPRO, ROAAUTO, ROACONT, ROACONTRACTE, ROADEF, ROAGEST, ROAIMOB, ROAREGISTRATURA, ROARES,
ROASTART. Grup B (fisier divergent, acelasi tipar la alta linie): OUTPUT/ROACONT `:350`,
ROACONIMPORT / ROAEFACTURA / ROAPRINT / ROASITFIN `:356`, ROAPRODUCTIE `:326`. Grup C (fara
@@ -1346,7 +1376,7 @@ din ~10 produse.
acoperite pe ecran de `test_ui_fix_editabil_subtotal.prg` (11/11). O asertie s-a **intarit**
(cazul B verifica acum numarul real de linii, nu `-1`), niciuna nu s-a slabit. Cifra veche
`7 PASS / 3 FAIL` din acest fisier era stale — numara doar cele 10 asertii de la runda 2.
Raport: `docs\cercetare\rec_datoria6_baza_regresie.md`. Diff: `docs\diff_datoria6_suite_regresie.patch`.
Raport: `docs\cercetare\rec_datoria6_baza_regresie.md`. Diff: diff aplicat (sters).
**Necomis.** Neprobat pe alta schema decat `MARIUSM_AUTO`.
7. **REZOLVATA 08.08.2026 — se verifica pe ecran, cu formular vizibil.** Harness nou:
`COMUN\utile\Teste\editare_factura\vfp_ui_harness.ps1` (formular vizibil off-screen, `PrintWindow`,
@@ -1507,7 +1537,7 @@ din ~10 produse.
`poDate.in_valuta = 1` cere in plus `zi_curs` si `id_valuta`, validate intern de dialog, iar calea
**nu e testabila headless** (dialogul e modal, `Show(1)`) — verificarea trece prin
`vfp_ui_harness.ps1`, cu `-SyncDir` explicit.
**CORECTIE DE PREMISA, 09.08.2026** (`docs\handoff_decizia35_valuta_dialog.md`, verificat si de
**CORECTIE DE PREMISA, 09.08.2026** (handoff intermediar (sters), verificat si de
orchestrator pe cod): **`frm_articol_factura` nu citeste deloc `poDate.in_valuta` / `zi_curs` /
`id_valuta`** — singurele aparitii din intervalul clasei sunt **comentate** (`ofacturare.vc2:2088`,
`:2136`, ramura scoasa la v2.0.56). Ramura de valuta a dialogului e condusa integral de
@@ -1801,29 +1831,29 @@ Sursa `PACK_FACTURARE` se exporta din `MARIUSM_AUTO` (`all_source`), conform
| `plan_10` / `plan_11` / `plan_12` | amanate |
| `verificare_vfacturi.sql` | harnessul de regresie pentru cele doua view-uri |
| `plan_06_s4_proiectare.md` | proiectarea S4/S4b; C.1 rescrisa 08.08.2026, A.3 aliniata la decizia 19 |
| `diff_s4_runda1_page3.patch` | **diff-ul S4 runda 1, de revizuit** (`omodificari.vc2` + `ofacturare_editare.prg`) |
| diff aplicat (sters) | **diff-ul S4 runda 1, de revizuit** (`omodificari.vc2` + `ofacturare_editare.prg`) |
| `cercetare\rec_s4_runda1.md` | raportul rundei 1: ce s-a implementat, ce s-a testat, ce NU e acoperit |
| `cercetare\rec_review_ancorare_s4.md` | review-ul de ancorare a coloanelor (sursa deciziei 26) |
| `cercetare\rec_gotop_tact_s4.md` | blocantul `Go Top In tact`, confirmat pe date (sursa deciziei 27) |
| `cercetare\rec_view_articole_vanzare.md` | proiectarea `VVANZARI_ARTICOLE` + ce s-a respins |
| `cercetare\ff_view_articole_vanzare.sql` | copia de lucru a scriptului (originalul e in `SCRIPTURI_CLAR`) |
| `COMUN\docs\cercetare\rec_view_articole_vanzare.md` | proiectarea `VVANZARI_ARTICOLE` + ce s-a respins |
| `COMUN\docs\cercetare\ff_view_articole_vanzare.sql` | copia de lucru a scriptului (originalul e in `SCRIPTURI_CLAR`) |
| `cercetare\handoff_s4_runda1.md` | predarea agentului `s4-runda1`; detaliile blocajului „View Parameter" |
| `cercetare\rec_watchdog_vfp.md`, `handoff_propr_custom.md` | watchdog-ul VFP si regula `*p:` pentru proprietati noi |
| `COMUN\docs\cercetare\rec_watchdog_vfp.md`, handoff intermediar (sters) | watchdog-ul VFP si regula `*p:` pentru proprietati noi |
| `cercetare\rec_editare_factura.md`, `rec_modific2024.md` | #6 |
| `cercetare\rec_suma_act.md` | regula sumei din `ACT` pe tip de document (sursa lui C.1) |
| `cercetare\rec_pozitionare_actactan.md` | de unde se citesc `id_set`/`id_fact`/`id_factd` (runda 4) |
| `cercetare\rec_datoria6_baza_regresie.md` | realocarea de `cod` 1140888->1140895 si re-ancorarea suitelor pe descoperire |
| `diff_datoria6_suite_regresie.patch` | diff-ul celor doua suite + `descopera_caz_test.prg` |
| diff aplicat (sters) | diff-ul celor doua suite + `descopera_caz_test.prg` |
| `cercetare\rec_cele_41_facturi.md` | cine sunt cele 41 de la decizia 9; `cod=1138989` = nota dublata |
| `cercetare\rec_tva_vanzari.md`, `rec_pret_lazy.md` | #7 (fond) si #12 |
| `cercetare\rec_integrari.md` | #10, #11, #12 |
| `cercetare\rec_consumatori_vanzari.md` | inventarul celor ~16 cai `xmlefactura` (datoria 5) |
| `cercetare\rec_s10_s12.md` | textul propus pentru `changelog_roaauto.txt` (datoria 3) |
| `COMUN\docs\cercetare\rec_tva_vanzari.md`, `rec_pret_lazy.md` | #7 (fond) si #12 |
| `COMUN\docs\cercetare\rec_integrari.md` | #10, #11, #12 |
| `COMUN\docs\cercetare\rec_consumatori_vanzari.md` | inventarul celor ~16 cai `xmlefactura` (datoria 5) |
| `COMUN\docs\cercetare\rec_s10_s12.md` | textul propus pentru `changelog_roaauto.txt` (datoria 3) |
| `cercetare\rec_todos_done.md` | starea punctelor din `todos.txt` |
| `cercetare\rec_s4_runda3b.md` | sub-blocul B: stergerea de linii (implementare + testare) |
| `handoff_s4_runda3b_adaugare.md` | contractul `frm_articol_factura`/`poArticol`/`poDate`/`gnScadereStoc` pentru adaugarea de linii (neinceputa) |
| `diff_s4_runda3b_linii.patch` | diff-ul stergerii de linii |
| `cercetare\s10_curata_versiune.sql` | curatarea tabelei `VERSIUNE` (datoria 4) |
| handoff intermediar (sters) | contractul `frm_articol_factura`/`poArticol`/`poDate`/`gnScadereStoc` pentru adaugarea de linii (neinceputa) |
| diff aplicat (sters) | diff-ul stergerii de linii |
| `COMUN\docs\cercetare\s10_curata_versiune.sql` | curatarea tabelei `VERSIUNE` (datoria 4) |
`docs\` **nu e urmarit nici de git, nici de SVN**, si `COMUN\utile\curatenie.ps1` l-ar sterge la
curatenia dinainte de commit. Ce trebuie pastrat, se muta sau se comite.

View File

@@ -1,8 +1,8 @@
# Propunere S4b — actiunea explicita de sincronizare RUL <-> articole factura
Document de **proiectare**, nu implementare. Niciun `.vc2`/`.prg` nu a fost modificat. Cerinta
sursa: `docs\plan_06_editare_factura.md:208-231`. Context: `docs\handoff_punct6_dupa_s5.md`
(sectiunea „S4b — ce e facut si ce lipseste"), `docs\handoff_punct6_10082026_seara.md`.
sursa: `docs\plan_06_editare_factura.md:208-231`. Context: handoff intermediar (sters)
(sectiunea „S4b — ce e facut si ce lipseste"), handoff intermediar (sters).
## Corectie fata de predarea anterioara — nu e nevoie de cursor de instantaneu
@@ -200,7 +200,7 @@ actionat manual dupa ce utilizatorul a vazut divergenta.
| **Total** | **~5-6.5 zile** |
Confirma caracterizarea din plan: „cea mai mare ramasa, nu blocheaza pe nimeni"
(`docs\handoff_punct6_10082026_seara.md:120`).
(handoff intermediar (sters)).
## Ce ramane deschis, de decis cu Marius inainte de implementare

View File

@@ -1,7 +1,7 @@
# S4b etapa 2 — butonul, dialogul si verificarea la salvare
Continuarea lui `docs\handoff_punct6_10082026_seara.md`, sectiunea „S4b etapa 2". Diff-ul complet:
**`docs\diff_s4b_etapa2.patch`** (342 randuri adaugate, 0 sterse, un singur fisier atins:
Continuarea lui handoff intermediar (sters), sectiunea „S4b etapa 2". Diff-ul complet:
**diff aplicat (sters)** (342 randuri adaugate, 0 sterse, un singur fisier atins:
`COMUN\clase\omodificari.vc2`).
**STARE: WRITE-BACK FACUT, NECOMIS.** `omodificari.vcx`/`.vct` sunt regenerate (11.08.2026 09:34),
@@ -37,7 +37,7 @@ TabIndex 6 e liber in PAGE3 (folosite: 3, 4, 5, 20 — verificat).
## Ce am schimbat fata de patch-ul partial al agentului mort
Patch-ul din `diff_s4b_etapa2_partial.patch` era mai complet decat il descria predarea (avea si
Patch-ul din diff aplicat (sters) era mai complet decat il descria predarea (avea si
verificarea la salvare, in metoda corecta). Cinci corectii:
**1. Lipsea `cmdSincronizeazaArticole.Click`** — butonul exista, dar nu facea nimic. Adaugat, cu

View File

@@ -1,10 +1,10 @@
# Review: diff_s5_grid_articole.patch (omodificari.vc2, frm_modific2024)
# Review: diff aplicat (sters) (omodificari.vc2, frm_modific2024)
Status: GATA. Review read-only, fara editari de cod. Nicio tranzactie/proces deschis.
## Scop verificat
`docs/diff_s5_grid_articole.patch` pe `COMUN/clase/omodificari.vc2`:
diff aplicat (sters) pe `COMUN/clase/omodificari.vc2`:
- insereaza coloana de grid `cPretAchizitieArt` (legata de `tvd.pret_achizitie`) intre
`cPretArt` (Column6) si fostul `cPretCuTvaArt` (Column7), renumeroteaza Column7..14 -> 8..15;
- adauga campul `id_vanzare_set` in cursorul `tvd`;