Files
roafacturare/docs/cercetare/s3b_alte_date_analitice.md
2026-09-09 22:19:22 +03:00

603 lines
42 KiB
Markdown

# S3b — Proiectare: sectiunea pliata "alte date + analitice"
Livrabilul povestii **S3b** din `docs\plan_13_unificare_formular_facturare.md:1838-1854` (deciziile 7,
8, 25, 26). Proiectare pe cod, fara nicio modificare — zero editari, zero
`git_sync.ps1`/`txt2vcx.ps1`, zero commit. `COMUN\clase\ofacturare_comun.vc2` si
`COMUN\programe\ofacturare_editare.prg` (perimetrul #6) doar citite, neatinse.
## Verdict (rezumat)
S3b nu e o simpla "mutare de controale" cum sugereaza textul din plan. **Descoperirea centrala,
negasita in materialele existente**: mecanismul de alocare a numarului de chitanta nu porneste doar
din clicul utilizatorului pe `opt_incasat` — porneste din **orice** atribuire programatica a
proprietatii `.Value`, pentru ca `opt_incasat.ProgrammaticChange` (`ferestre_cere_date.vc2:3351-3352`)
cheama exact acelasi `actualizeaza_tipincasare()` ca si `.Click` (`:3250-3251`). `Init`-ul de azi
(`:3150`) seteaza chiar el `Thisform.opt_incasat.Value = 2` cand documentul soseste cu
`poDate.incasat<>0` (caz real: copiere, confirmat la `ofacturare_stoc.prg:535`,
`oproceduri_facturare.prg:1186`, `ofacturare_comun.vc2:4066,4260`) — deci **azi, deschiderea
dialogului aloca deja un numar de chitanta fara ca userul sa atinga nimic**, de fiecare data cand
documentul soseste cu o incasare presetata. In formularul unificat, unde zona nu se mai deschide o
singura data modal ci se pliaza/depliaza repetat pe acelasi obiect `poDate` persistent, acelasi cod
rulat la fiecare depliere ar realoca/dealoca la fiecare toggle — exact opusul criteriului cerut de
decizia 25. Sectiunea 4 trateaza asta ca risc central, cu recomandare concreta.
A doua descoperire: **niciun mecanism de pliere reutilizabil nu exista** in prototipul
`frm_facturare_articole2` (cautare completa, zero potriviri pe "plia/colaps/accordion/expand" in
`ofacturare.vc2`) — cel mai apropiat tipar din suita e `frm_modific2024.afiseaza_rulaje`
(`omodificari.vc2:13169-13199`, perimetrul #6, citit dar neatins), care refoloseste **acelasi idiom
sus/jos** deja validat pentru `but_modifica`/`but_salveaza` (decizia 9), dar aplicat unui show/hide,
nu unei blocari. Sectiunea 6 detaliaza.
A treia: pentru analiticele read-only (decizia 26), mecanismul existent `ct_clb_cautare.do_dezactiveaza()`
(`caut_ora.vc2:800-806`) **ascunde doar lupa de cautare**, nu blocheaza si textbox-ul de afisare —
cineva tot poate scrie liber in camp. Sectiunea 2 detaliaza gap-ul si completarea minima necesara.
---
## 1. Inventarul exact al celor patru grupuri din `frm_alte_date`
Sursa primara a controalelor: `docs\cercetare\inventar_controale_formulare.md` §4 si
`docs\S1_inventar_campuri_formular_unificat.md` (randurile "Pliat — alte date"), reconfirmate aici
direct pe `COMUN\clase\ferestre_cere_date.vc2` (clasa `frm_alte_date`, `2219-3353`; garda de validare
`inainte_de_do_termin` la `3044-3103`, `Init` la `3105-3208`).
### 1.1 Delegat / transport
| Control | Caption real | `fisier:linie` (ADD OBJECT) | Vizibilitate | Ruta de scriere (din rute_scriere_antet.md / S1) |
|---|---|---|---|---|
| `Ct_clb_delegat` | "Delegat" | `ferestre_cere_date.vc2:2553` (container `ct_clb_cautare`-like, `caution=do_cauta_delegat`) | pliat, mereu editabil pe document nou; **eliminat cu totul** cand `poDate.eProforma=1` (`:3192`) | pe loc, `modifica_date_factura` (`V_ID_DELEGAT`), neconditionat — `modifica_date_factura_parametri.md:17` |
| `Ct_clb_masina` | "Masina" | `:2569` | idem, eliminat pe proforma (`:3193`) | `V_ID_MASINA`, neconditionat — `:18` |
| `Ct_clb_agent` | "Agent" | `:2537` | idem, **nu e eliminat pe proforma** (nu apare in cascada `RemoveObject` `:3192-3201`) | `V_ID_AGENT`, neconditionat — `:19` |
| `Clb_dataora_exp` | "Data si ora expedierii" | `:2443` | idem, nu eliminat pe proforma; **validat obligatoriu** in `inainte_de_do_termin` (`:3062-3067`, `Case Empty(Nvl(poDate.dataora_exp,{})) And poDate.eProforma = 0`) | `V_DATAORA_EXP`, neconditionat — `:20` |
| `But_modifica1` | (icon, `caction` implicit -> `do_modifica`) | `:2343` | actiune, nu camp — deschide `nom_parteneri_modifica` pe delegatul curent (`ferestre_cere_date.vc2:2925-2935`) | — |
**Validarea de grup** (`inainte_de_do_termin`, `:3055-3060`): delegatul e obligatoriu doar cand
`gcNumeProgram = [ROAFACTURARE]` **si** documentul nu e proforma sau bon fiscal
(`!(poDate.eProforma = 1 OR poDate.eBonFiscal = 1)`) — nuanta care trebuie pastrata identic in
formularul unificat, nu doar copiata "delegat obligatoriu".
### 1.2 Incasare (grupul cel mai mare, vezi si sectiunile 3-4)
| Control | Caption real / eticheta dinamica | `fisier:linie` | Vizibil cand |
|---|---|---|---|
| `opt_incasat` (radiogrup 4 optiuni) | "Fara incasare" / "Chitanta" / "Bon fiscal" / "POS Card" | `:2638-2685` (default `Value=1`) | mereu, dar **intreg containerul incasare** dispare pe proforma (`:3140-3143`, `Thisform.opt_incasat.Visible = .F.`, doar pe ramura non-proforma exista oricum) si pe `gcNumeProgram=[ROAGEST]` sau `!Between(poDate.tip,1,4)` |
| `Cb_casa` | "Casa" -> "Banca POS" pe POS (`:2967` `_lbbase1.Caption='Banca POS'`) | `:2362` | ascuns doar la `opt_incasat=1` |
| `Clb_serie_chit` | "Serie chitanta" | `:2503` | vizibil **doar** la Chitanta (`Value=2`) |
| `Clb_nrchit` | "Nr. chitanta" -> "Nr. bon" pe Bon fiscal/POS | `:2480` | ascuns doar la `Value=1` |
| `Clb_incasat` | "Incasat" | `:2461` | ascuns doar la `Value=1` |
| `cmdModificaBon` | icon, `caction=do_modifica_bon` | `:2526` | vizibil **doar** la Bon fiscal (`Value=3`) |
| `chkPOS` | "POS" | `:2409` | vizibil la Bon fiscal (`Value=3`, bifabil) **si** la POS (`Value=4`, fortat `.T.` si ascuns — `:2845` `thisform.chkPOS.Value=1` apoi `.Visible=.F.`) |
| `chkDetaliat` | "Detaliat" | `:2396` | vizibil doar la Bon fiscal |
| `cboTipFactura` | combo, langa "Tip factura" | `:2378` | mereu (langa incasare), scrie `poDate.tip_saft` |
Masina de stari completa e la sectiunea 3-4. **Eticheta "Casa"/"Banca POS" si vizibilitatea lui
`chkPOS`/`chkDetaliat` fac parte din aceeasi metoda unica** (`actualizeaza_tipincasare`) — nu sunt
conditii separate de refacut, sunt randuri din acelasi `Do Case`.
### 1.3 Adresa de facturare
| Control | Caption | `fisier:linie` | Vizibilitate |
|---|---|---|---|
| `clb_adresa_facturare` | "Adresa facturare" | `:2422` | pliat, mereu editabil; **nu** eliminat pe proforma (absent din cascada `:3192-3201`) |
| `do_cauta_adresa` (metoda, nu control separat) | — | `:2911-2926` | cauta pe `poDate.id_client`, seteaza `poDate.adresa_facturare`/`poDate.id_facturare` |
Ruta de scriere: `V_ID_FACTURARE`, neconditionat — `modifica_date_factura_parametri.md:21`.
### 1.4 Text aditional
| Control | Caption | `fisier:linie` | Vizibilitate |
|---|---|---|---|
| `Ed_tx_simplu1` | "Text aditional (max. 1000 caractere)" | `:2585` | pliat, mereu editabil; nu eliminat pe proforma — dimpotriva, **pe proforma ramane singurul grup activ**, formularul se redimensioneaza in jurul lui (`:3184-3207`) |
| `_checkbox1` ("Listare detaliata") | "Listare detaliata" | `:3002-3011` | ADD OBJECT separat, `ControlSource=poDate.nListareDetaliata` — **nu e in cascada celor patru grupuri din B**, e propriul lui control, langa text aditional in layout, dar conceptual apartine grupului de raportare (I-bis) alaturi de `tip_saft`/`efactura`, nu grupului "text aditional" |
Ruta: `V_TEXT_ADITIONAL`, neconditionat, **fara** `NVL` — `modifica_date_factura_parametri.md:23`.
**Observatie structurala pentru mockup**: `_checkbox1` (listare detaliata) e cablat separat de
`chkDetaliat` din grupul incasare (control diferit, aceeasi semantica probabila — ambiguitate deja
semnalata in S1, randul 57, neinchisa aici). Formularul unificat trebuie sa aleaga **unul singur**
dintre cele doua controale existente, nu sa le porteze pe amandoua.
---
## 2. Analiticele coborate din antet (decizia 8, nuantata de decizia 26)
Controale: `Ct_clb_venchelt` ("Venit / cheltuiala"), `Ct_clb_sectie` ("Sectie"), `Ct_clb_responsabil`
("Responsabil"), `Ct_clb_lucrare` ("Lucrare") — toate patru container `ct_clb_cautare` (subclasa
`caut_ora.vcx`), azi pe `frm_date_factura`/`frm_date_aviz`, **nu** pe `frm_alte_date`
(`inventar_controale_formulare.md` §3; S1 randurile 39-42). Live in sectiunea I a planului ca grup
"Pliat — analitice", distinct de cele patru grupuri ale lui `frm_alte_date` — dar aceeasi sectiune
pliata a formularului unificat, conform textului S3b ("peste ele coboara analiticele din antet").
### 2.1 Ce inseamna "afisare read-only" mecanic
Sursa: `docs\cercetare\rute_scriere_antet.md` §1 — verdict deja stabilit, **DA** pentru
`ID_SECTIE`/`ID_RESPONSABIL`/`ID_LUCRARE` printr-o cale noua (`frm_facturi.do_editare_factura` ->
`frm_modific2024`, perimetrul #6), **neconfirmat** pentru `ID_VENCHELT`. Pentru #13, indiferent de
raspunsul acelei rezerve, decizia 26 e explicita: **zero editare din formularul unificat**, oricare ar
fi ruta reala din Oracle.
**Mecanismul de blocare vizuala, verificat pe cod, cu un gap real**:
`ct_clb_cautare.do_dezactiveaza()` (`caut_ora.vc2:800-806`):
```
PROCEDURE do_dezactiveaza
This.lactiv = .F.
This.img_cautare.Visible = .F.
This.ctooltip = This.clb_tx_cautare.text_simplu1.ToolTipText
This.clb_tx_cautare.text_simplu1.ToolTipText = []
This.clb_tx_cautare.text_simplu1.Refresh()
ENDPROC
```
`This.lactiv` gateaza **doar** deschiderea dialogului de cautare — `DblClick` (`:822-826`),
`KeyPress` pe Enter/Tab/F7 (`:829-836`), `img_cautare.Click` (`:840-843`) — toate testeaza
`This.Parent(.Parent).lactiv` inainte sa cheme `do_apeleaza()`. **Nu seteaza `ReadOnly` pe
`clb_tx_cautare.text_simplu1`** — textbox-ul bindat (`ControlSource=This.cvar_afisata`, setat in
`Init`, `caut_ora.vc2:814-817`) ramane direct tastabil. Pentru un camp cu adevarat read-only (decizia
26 cere explicit "nu se editeaza"), `do_dezactiveaza()` trebuie **completat**, nu doar apelat: se
adauga `This.clb_tx_cautare.text_simplu1.ReadOnly = .T.` (si eventual `.TabStop = .F.`, ca sa nu
primeasca focus deloc) langa apelul existent — o linie noua, in tiparul deja recomandat de plan
(sectiunea I: "singura reteta completa e `clb_tx_data.dezactiveaza()`... se generalizeaza de la ea").
**Consecinta pentru "un singur buton deschide tot" (decizia 9)**: `do_dezactiveaza()` se apeleaza **o
singura data**, la constructia sectiunii, **si nu se mai cheama niciodata `do_activeaza()`** pentru
aceste patru controale — nici cand `but_modifica` deblocheaza restul antetului. E o exceptie
deliberata de la "un singur control comanda toata protectia antetului" (plan I:843-853), simetrica cu
exceptia deja acceptata pentru grupurile B/C la decizia 25 (sectiunea 5 de mai jos).
### 2.2 Eticheta / tooltip
Nicio propunere de text nu exista inca in materialele citite — de scris la implementare. Recomandare
minima, in stilul deja folosit in codebase (ex. `Ct_clb_gestiune_init.ToolTipText`, un citat complet
la `inventar_controale_formulare.md:93-95`, deci precedent de lungime/ton acceptat): eticheta ramane
neschimbata ("Venit / cheltuiala"/"Sectie"/"Responsabil"/"Lucrare"), `ToolTipText` nou de tipul
*"Se editeaza din Editare factura (articole, cantitati, preturi) — buton disponibil pe fiecare linie
a notei contabile"*, ca sa nu para camp stricat. Text exact — **de decis de Marius**, vezi sectiunea 9.
### 2.3 Nivel antet vs. nivel linie — de retinut la afisare
`rute_scriere_antet.md` §1.4: editarea reala prin #6 e **pe linie de nota**, nu pe antet — un
document poate ajunge cu sectii diferite pe linii diferite dupa editare (imposibil la emitere). Cand
formularul unificat afiseaza analiticele "cu valoarea de antet" (cum spune decizia 26), afiseaza de
fapt **o singura valoare reprezentativa** (probabil prima linie sau variabila de sesiune retinuta la
emitere), nu o agregare a liniilor — daca liniile diverg dupa o editare #6, afisarea din #13 devine
"aproximativa, nu autoritara". Nu e o contradictie de rezolvat aici (decizia 26 exista tocmai ca sa
evite ca #13 sa scrie peste diferentierea de linie), dar merita un rand explicit in criteriul de
"gata" (sectiunea 10): afisarea trebuie sa spuna clar ce valoare arata, nu sa pretinda ca e valoarea
unica a documentului daca liniile difera.
---
## 3. `actualizeaza_tipincasare`
Definita la `COMUN\clase\ferestre_cere_date.vc2:2698-2856`, metoda proprie a clasei `frm_alte_date`.
Comuta vizibilitatea intregului subgrup de incasare pe `This.opt_incasat.Value` (patru ramuri, tabel
complet la sectiunea 1.2 si in `inventar_controale_formulare.md:130-135`) **si**, in aceeasi metoda,
aloca/dezaloca numerele — cele doua responsabilitati (UI si alocare) sunt **impletite in acelasi
`Do Case`**, nu separate. Fiecare ramura incepe prin a dezaloca defensiv celelalte trei tipuri de
numar, apoi aloca pe cel curent daca e cazul:
| `opt_incasat.Value` | Dezaloca la intrare | Aloca | Alte efecte |
|---|---|---|---|
| 1 (Fara incasare) | 16, 3, 26 | — | `poDate.incasat=0`, `poDate.nr_incasare=0` |
| 2 (Chitanta) | 3, 16, 26 | `creeaza_cursor_serii(16)` + `clb_serie_chit.genereazaNumar()` (`:2783`) — doar daca `nRezultatSerii=0` (nu realoca daca seria era deja creata) | `poDate.incasat=poDate.totalctva` |
| 3 (Bon fiscal) | 3, 16, 26 | `do_aloca_nr_bon([CLICK])` (`:2807`) -> cod 3 | idem, plus `tip_saft` poate deveni 751 daca `gnEFactura_tip_saft_bf` e setat |
| 4 (POS/Card) | 3, 16, 26 | `do_aloca_nr_pos([CLICK])` (`:2844`) -> cod 26 | idem, `chkPOS.Value` fortat 1 si ascuns |
**Ce depinde de ea**: `opt_incasat.Click` (`:3250-3251`) **si** `opt_incasat.ProgrammaticChange`
(`:3351-3352`) — vezi sectiunea 4, e disjunctia care conteaza. Nu are alti apelanti directi in
`ferestre_cere_date.vc2` (cautare `vfp_symbols.ps1 -Grep actualizeaza_tipincasare -CodeOnly`
recomandata la implementare pentru confirmare exhaustiva pe tot proiectul — nu rulata aici din motive
de buget, dar apelantul extern deja cunoscut e citat mai jos, la 3.1).
### 3.1 Apel extern, cu context important
`COMUN\clase\ofacturare.vc2:14919-14926` (`frm_facturare_articole(2).inainte_de_do_termin`, inainte
de `ofrmdatesupl.Show(1)`):
```
ofrmdatesupl = Createobject("frm_alte_date")
ofrmdatesupl.nnrbon = poDate.nract
If (poDate.eBonFiscal = 1)
With ofrmdatesupl
.opt_incasat.Value = 3 && INCASARE CU BON FISCAL
.actualizeaza_tipincasare() && apel EXPLICIT, dupa .Value=
.opt_incasat.option1.TabStop = .F.
...
```
Apelantul seteaza `.Value=3` **si** cheama explicit `actualizeaza_tipincasare()` imediat dupa — ceea
ce, coroborat cu descoperirea de la sectiunea 4 (`.Value=` deja declanseaza `ProgrammaticChange` ->
aceeasi metoda), inseamna ca metoda ruleaza de doua ori la acest apel. Nu produce o eroare vizibila
(fiecare ramura e idempotenta: dezaloca ce era alocat, realoca acelasi tip), dar confirma ca autorul
codului nu s-a bazat exclusiv pe evenimentul `ProgrammaticChange` — semn ca mecanismul lui exact
(cand se declanseaza, cand nu) n-a fost niciodata documentat explicit, doar "acoperit din ambele
parti". **Portarea "ca atare" trebuie sa pastreze acest apel dublu identic**, nu sa-l "curete" ca
redundant — eliminarea unuia dintre cele doua declansatoare ar putea rupe o presupunere neverificata
in alta parte a codului.
### 3.2 "Se muta ca atare" — ce inseamna concret
Corpul metodei (`:2698-2856`) nu are nicio dependenta de fereastra-container (`Thisform.*` peste
tot, nu `This.Parent.*`) — se poate muta **byte-cu-byte** pe formularul unificat, cu conditia ca
toate cele noua controale referite (`opt_incasat`, `cb_casa`, `clb_serie_chit`, `clb_nrchit`,
`clb_incasat`, `_shape3`, `lb_simplu1`, `cmdModificaBon`, `chkPOS`, `chkDetaliat`, `cboTipFactura`)
sa existe cu **exact aceleasi nume** pe noul formular, in acelasi container logic (`Thisform`, nu un
subpanou cu alt scope) — altfel referintele nekvalificate `Thisform.xxx` pica silentios pe obiect
inexistent. Aceasta e o constrangere de implementare directa: **sectiunea pliata trebuie sa fie
container-transparenta** pentru aceasta metoda (fie pusa direct pe `Thisform`, fie metoda insasi
adaptata sa foloseasca `This.Parent`-ul corect) — nu poate fi mutata intr-un obiect-container separat
fara o trecere explicita de `Thisform.xxx -> This.Parent.xxx` pe toate liniile.
---
## 4. Alocarea si dezalocarea numerelor — evenimentele exacte
### 4.1 Evenimente de alocare (azi)
1. **`opt_incasat.Click`** (`:3250-3251`) — interactiune reala a utilizatorului pe radiogrup.
2. **`opt_incasat.ProgrammaticChange`** (`:3351-3352`) — **descoperire centrala a acestui raport**,
negasita in materialul de plan sau in cele patru rapoarte de referinta: in VFP, orice atribuire
`.Value = n` facuta din cod (nu de utilizator) declanseaza `ProgrammaticChange`, nu `Click`. Clasa
are ambele metode cablate pe **acelasi** apel (`actualizeaza_tipincasare()`), deci **orice loc din
cod care scrie `opt_incasat.Value = ...` aloca/dealoca numere**, indiferent de intentie.
3. **Chiar `Init`-ul clasei** foloseste acest canal: `:3150`, `Thisform.opt_incasat.Value = 2` — ruleaza
**doar daca** `poDate.incasat <> 0` la momentul deschiderii. Verificat pe cod (nu presupus) ca
`poDate.incasat` poate fi nenul **inainte** ca `frm_alte_date` sa se deschida, prin cel putin patru
cai reale: `ofacturare_stoc.prg:535`, `oproceduri_facturare.prg:1186`,
`ofacturare_comun.vc2:4066`, `ofacturare_comun.vc2:4260` (toate patru scriu `poDate.incasat =
incasat`, parametru primit de la apelant — flux de copiere/reluare a unui document cu incasare deja
stabilita). **Concluzie verificata**: azi, deschiderea dialogului `frm_alte_date` pe un astfel de
document **aloca deja un numar de chitanta la Init, inainte ca userul sa apese orice**. Nu e o
ipoteza — e mecanismul descris la sectiunea 3, declansat de linia 3150.
4. `do_modifica_bon`/`do_modifica_pos` (`:3001-3022`) — dezaloca explicit + realoca, la apasarea
butonului "Modifica bon"/echivalent POS.
5. `do_aloca_nr_bon`/`do_aloca_nr_pos` (`:2864-2907`) — chemate din interiorul lui
`actualizeaza_tipincasare` (ramurile 3 si 4), nu independent.
### 4.2 Evenimente de dezalocare (azi)
1. **In interiorul `actualizeaza_tipincasare`** — fiecare ramura dezaloca defensiv celelalte trei
tipuri **inainte** de a (re)aloca pe cel ales (tabelul de la sectiunea 3). Efect: comutarea intre
optiuni, in cadrul aceleiasi sesiuni de dialog, e curata — nu ramane niciun numar orfan din
optiunea anterioara.
2. **`inainte_de_do_renunt`** (`:3023-3043`) — la anulare (buton Renunt / ESC pe dialogul modal):
```
inainte_de_do_renunt (ferestre_cere_date.vc2:3025-3030)
If Type('poGeneratorNumere') = 'O'
poGeneratorNumere.dezaloca_numar(16) && chitanta
poGeneratorNumere.dezaloca_numar(3) && bon fiscal
...
```
**Gap real, preexistent, verificat pe cod**: acest bloc dezaloca 16 (chitanta) si 3 (bon fiscal),
dar **nu 26 (POS)** — nici direct, nici in blocul urmator (`:3033-3035`, care dezaloca doar 16 din
nou, conditionat). Daca utilizatorul alege POS/Card si apoi anuleaza dialogul, numarul POS alocat
**ramane alocat**, nedezalocat. Nu e introdus de S3b — exista deja in codul de azi — dar merita
semnalat explicit ca risc mostenit (sectiunea 9), pentru ca S3b il "muta ca atare" (plan, textul
povestii), deci il si multiplica pe orice cale noua prin care sectiunea pliata s-ar putea
"renunta" fara sa fie un dialog modal cu propriul buton Renunt.
3. **`Init` pe eroare Oracle** (`:3159`) — `poGeneratorNumere.dezaloca_numar(5)` (factura) daca
interogarea `v_nom_casa` esueaza, cu `Return` imediat dupa (linie explicita, spre deosebire de
bug-ul #16 din `s3_portare_antet.md` §6, unde nu exista `Return` echivalent). Semnalat, neurmarit
mai departe aici — acelasi risc de arhitectura ca #16, dar pe alt fisier.
### 4.3 Riscul central pentru formularul unificat, si recomandarea
**Problema mecanica exacta**: in fluxul de azi, `frm_alte_date` e un dialog modal, instantiat **o
singura data** per emitere (`ofacturare.vc2:14921`), asa ca `Init`-ul lui (si declansarea eventuala de
la linia 3150) ruleaza **o singura data**. In formularul unificat, grupul de incasare devine o
sub-sectiune a unui panou pliabil, pe **acelasi obiect de formular persistent** — daca implementarea
naiva re-populeaza `opt_incasat.Value` din `poDate` de fiecare data cand sectiunea se depliaza (ex.
"la fiecare `Show`/`Visible=.T.` al panoului, resincronizeaza controalele cu starea curenta a lui
`poDate`"), **fiecare depliere ar re-declansa `ProgrammaticChange` -> `actualizeaza_tipincasare()` ->
dezaloca tot + realoca pe optiunea curenta** — incalcand direct criteriul din S3b ("deschiderea si
inchiderea formularului fara a atinge zona de incasare nu aloca si nu dezaloca niciun numar").
**Recomandare concreta**: populeaza `opt_incasat.Value` din `poDate` **o singura data**, la
constructia sectiunii de antet a documentului (echivalentul lui `Init` de azi, care ruleaza o data per
sesiune de emitere/editare) — nu la fiecare toggle de pliere/depliere. Plierea/deplierea trebuie sa
fie **strict** un toggle de `Visible`/`Height` pe containerul vizual, fara nicio atingere a
proprietatii `.Value` a lui `opt_incasat` sau a oricarui alt control cu `ProgrammaticChange` cablat pe
alocare. Aceasta e exact genul de regula care trebuie verificata explicit la implementare (criteriu de
"gata" concret la sectiunea 10), nu presupusa.
---
## 5. Grupul de incasare pe document deja emis (decizia 25)
**Ce spune decizia**: orice camp schimbat din grupul C (incasare) pe un document deja emis
"marcheaza documentul pentru regenerare" — dar regenerarea nu exista in etapa I, deci **planul tine
campurile blocate**, cu explicatie la hover, pana la etapa II (plan `:192-201`, `:1847-1848`).
`rute_scriere_antet.md` §3 confirma independent ca nu exista nicio cale directa de scriere pentru
grupul C dupa emitere (verdict "NU" pentru toate controalele, "PARTIAL neconfirmat" doar pentru o
cale indirecta prin editarea notei — vezi §3.2 acolo, ramane deschisa).
### 5.1 Mecanic: pe ce proprietate, pe ce conditie
Decizia 9 stabileste ca `but_modifica` deblocheaza **tot** antetul, fara exceptie de camp — dar
decizia 25 taie o exceptie explicita peste asta pentru grupurile B si C. Nu exista inca (verificat,
`rute_scriere_antet.md` §2-3) un mecanism de blocare per-grup separat de `but_modifica`; trebuie
construit nou, dar dupa un tipar deja folosit in codebase pentru exact intrebarea "acest document are
deja un numar, sau e nou": `chkSerieAct.Enabled = !EMPTY(NVL(poRec.numar_act,0))`
(`ofacturare_comun.vc2:5736-5750`, citat deja in plan I:839 si S1 randul 60). Decizia 9 **abandoneaza**
acest test ca poarta pe cele patru bife de identitate (serie/numar/data/scadenta) — dar testul insusi
ramane exact instrumentul potrivit pentru o alta intrebare: "documentul e nou sau deja emis?", care e
tocmai conditia ceruta de decizia 25 pentru grupurile B/C.
**Recomandare mecanica**: la construirea antetului, se calculeaza o singura data un flag (ex.
`lDocumentExistent = !EMPTY(NVL(poRec.numar_act,0))` sau echivalentul lui pe obiectul `poDate`/`poRec`
folosit de formularul unificat — de confirmat la implementare care obiect poarta `numar_act` in noua
arhitectura, pentru ca `poRec` era specific lui `frm_modifica_factura`, perimetrul #6). Controalele
grupului C (`opt_incasat` si tot ce atarna de el din tabelul sectiunii 1.2) primesc `Enabled = .F.`
**neconditionat de starea lui `but_modifica`** cand `lDocumentExistent = .T.`, in etapa I. Cand
`but_modifica` deblocheaza restul antetului, acest grup **ramane** dezactivat — e o exceptie fixa, nu
una care se recalculeaza la fiecare click pe `but_modifica`.
**Grupul B** (tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi) are
aceeasi tratare — dar acele controale traiesc azi in `frm_date_factura`/`frm_date_aviz`
(sectiunea I a planului, nu sectiunea B de aici), deci blocarea lor nu e in perimetrul S3b propriu-zis;
se semnaleaza aici doar pentru consecventa mecanismului (acelasi flag, acelasi tipar de `Enabled=.F.`
peste orice stare a lui `but_modifica`).
### 5.2 La emitere, se comporta ca azi
Pentru un document **nou** (nu inca emis), `lDocumentExistent = .F.`, grupul C e activ normal — se
comporta identic cu `frm_alte_date` de azi, cu masina de stari intreaga din sectiunile 3-4. Nimic nu
se schimba pe calea de emitere initiala; blocarea se aplica **doar** cand formularul unificat deschide
un document deja scris in `VANZARI` (calea de editare, nu de creare).
### 5.3 Tooltip / explicatie la hover
Ca la sectiunea 2.2, textul exact nu exista inca — de propus la implementare, in tonul deja folosit in
codebase. Continut minim necesar: sa spuna ca modificarea incasarii pe un document emis nu e inca
posibila din acest formular ("disponibil dupa ce regenerarea documentului e implementata" sau
echivalent), nu doar "camp dezactivat" fara explicatie — plan `:198-200` cere explicit "cu explicatie
la hover".
---
## 6. Mecanismul de pliere — nu exista, se construieste nou dupa un tipar existent
**Cautare directa in prototip**: `vfp_symbols.ps1 -Grep` (si grep text simplu) pe "plia|colaps|
collapse|expand|acordeon|accordion" in `COMUN\clase\ofacturare.vc2` (unde traieste
`frm_facturare_articole2`, `:15741-19355`) — **zero potriviri**. Prototipul are controalele de antet
montate direct pe formular (confirmat deja de `s3_portare_antet.md` §3 si de
`inventar_controale_formulare.md` §2), dar **niciun mecanism de show/hide de sectiune** — nu exista
nici macar un buton candidat.
**Cel mai apropiat tipar real din suita**: `frm_modific2024.afiseaza_rulaje`
(`COMUN\clase\omodificari.vc2:13169-13199`, perimetrul #6, doar citit aici). Cod complet:
```
PROCEDURE afiseaza_rulaje
* COLAPSEAZA SAU MARESTE PAGEFRAME-UL RULAJE
lcPicture = this.but_afiseaza_rulaje.Picture
...
llAfiseazaRulaje = 'sus'$m.lcPicture
IF m.llAfiseazaRulaje
lcPicture2 = STRTRAN(m.lcPicture,'sus','jos') ...
ELSE
lcPicture2 = STRTRAN(m.lcPicture,'jos','sus') ...
ENDIF
this.but_afiseaza_rulaje.Picture = m.lcPicture2
...
this.pgfArticole.Visible = m.llAfiseazaRulaje
this.but_copiazaR.Visible = m.llAfiseazaRulaje
this.but_modificaR.Visible = m.llAfiseazaRulaje
this.but_stergeR.Visible = m.llAfiseazaRulaje
thisform.resize_grid1()
ENDPROC
```
Trei observatii directe:
1. **Foloseste exact acelasi idiom sus/jos** deja validat si documentat pentru `but_modifica`/
`but_salveaza` (decizia 9, `docs\cercetare\buton_comutator_picture.md`, citat in plan `:63-75`):
citeste starea curenta din numele fisierului `Picture` (contine "sus" sau "jos"), calculeaza
perechea opusa prin `STRTRAN`, rescrie **`Picture` + `cPictureDown` + `cPictureUp` impreuna** —
aceeasi precautie semnalata in plan ("numai `.Picture` nu ajunge: hover-ul standard din
`buton.MouseEnter`/`MouseLeave` rescrie `Picture` din `cPictureUp`/`cPictureDown`").
2. **Nu e o clasa reutilizabila, e cod ad-hoc per caz** — toggle direct pe `.Visible` al unei liste
fixe de controale, plus un apel manual de reflow (`resize_grid1()`, metoda proprie a formularului,
nu un mecanism generic). Nu exista in nicio biblioteca de clase din `COMUN` (`_baza.vcx`, etc.,
cautare separata, zero potriviri pentru o clasa "panou pliabil"/"expander"/"accordion") un
container gata facut de pliere. **S3b trebuie sa scrie cod nou**, dupa acest tipar, nu sa
instantieze o clasa existenta.
3. **E in perimetrul #6, doar citire** — poate fi copiat ca *idee*/tipar la implementare, dar
`omodificari.vc2` insusi nu se atinge cat timp #6 e in lucru (decizia 30).
### 6.1 Ce trebuie sa scrie S3b, concret
- **Un buton comutator per sectiune pliata** (sau unul singur pentru toata zona "alte date +
analitice", de decis la implementare — plan I nu specifica granularitatea), cu imaginile
sus/jos deja existente in `COMUN\grafice` (aceleasi perechi folosite pentru `but_afiseaza_rulaje`,
de identificat exact numele fisierelor la implementare — nu verificate aici, doar tiparul de
mecanism).
- **Toggle de `.Visible`/`.Height`** pe grupul de controale al sectiunii (delegat/transport, incasare,
adresa, text aditional, analitice), plus un apel de reflow echivalent lui `resize_grid1()` — pentru
ca restul formularului (butoane, alte sectiuni de mai jos) sa nu ramana cu goluri sau suprapuneri
cand sectiunea se pliaza/depliaza. VFP nu reflow-eaza automat un layout absolut-pozitionat (`Left`/
`Top` fixe pe fiecare control) — de asta si tiparul din `frm_date_factura.Init` (citat in
`s3_portare_antet.md` §5, "masoara inaltimile containerelor de antet intr-un array `laPozitii`") cat
si `afiseaza_rulaje` fac manual acest calcul; nu exista un layout manager automat de reutilizat.
- **Populare o singura data** a starii initiale (sectiunea 4.3) — separat de toggle-ul de vizibilitate,
ca sa nu retrigger-eze `ProgrammaticChange`.
- **Intrebare deschisa, semnalata deja in `s3_portare_antet.md` §5** (nu redusa aici): daca lookup-urile
Oracle ale lui `frm_alte_date.Init` (delegat/masina ultima factura, cursorul `v_nom_casa`) raman
**eager** (rulate la construirea formularului, ca azi) sau devin **lazy** (amanate pana la prima
depliere a sectiunii, ca sa nu incarce round-trip-uri Oracle inutile cand userul nu ajunge niciodata
acolo). Ambele optiuni sunt compatibile cu criteriul "deschiderea/inchiderea nu aloca numere" **doar
daca** populate keeping in mind sectiunea 4.3 (populare o singura data, indiferent de varianta
aleasa) — **de decis de Marius**, vezi sectiunea 9.
---
## 7. Ordinea de executie
Pasi care lasa suita functionala dupa fiecare — calea veche (`frm_alte_date` ca dialog separat) **nu
se sterge** in etapa I, cf. textul povestii ("`frm_alte_date` nu se sterge cat timp calea veche mai e
in uz").
1. **Construieste sectiunea vizuala pliata** (patru grupuri din sectiunea 1 + analiticele din
sectiunea 2), fara nicio logica de alocare/validare inca — doar controale + toggle de
Visible/Height (sectiunea 6). *Criteriu:* fiecare control existent in `frm_alte_date`/antetul de
analitice apare o data, cu aceeasi eticheta, in sectiunea corecta a formularului unificat —
verificare camp-cu-camp fata de tabelele din sectiunile 1-2 de aici.
2. **Porteaza `actualizeaza_tipincasare` ca atare** (sectiunea 3), cu toate cele noua referinte
`Thisform.xxx` rezolvate corect in noul container (sectiunea 3.2). *Criteriu:* alegerea fiecarei
optiuni din `opt_incasat` produce exact aceleasi `Visible`/etichete pe controalele dependente ca pe
`frm_alte_date` de azi, verificabil headless (sectiunea 8).
3. **Rezolva explicit riscul de la sectiunea 4.3** — populare unica a starii, toggle de pliere fara
atingere de `.Value`. *Criteriu, verificabil headless:* pe un document de test cu `poDate.incasat<>0`
la construirea formularului, se depliaza si se plie
aza sectiunea de trei ori consecutiv fara a atinge
niciun control din grup — `poGeneratorNumere` (cursorul lui de numere alocate) arata **acelasi**
numar de chitanta la finalul celor trei toggle-uri ca la inceput, nu unul nou de fiecare data.
4. **Porteaza delegat/transport si adresa de facturare** (`do_cauta_delegat`/`do_cauta_masina`/
`do_cauta_agent`/`do_cauta_adresa`/`do_modifica`), cu validarea din `inainte_de_do_termin`
(sectiunea 1.1). *Criteriu:* fiecare cautare deschide acelasi dialog si scrie aceleasi proprietati
pe `poDate` ca azi (comparatie directa, cod identic mutat).
5. **Adauga analiticele read-only** (sectiunea 2), inclusiv completarea `do_dezactiveaza()` cu
`ReadOnly=.T.` explicit. *Criteriu:* tastarea directa in oricare din cele patru campuri nu modifica
valoarea afisata (verificare pe proprietate, headless).
6. **Implementeaza blocarea grupului C pe document deja emis** (decizia 25, sectiunea 5), cu flag-ul
de "document existent" si exceptia peste `but_modifica`. *Criteriu:* pe un document nou,
`but_modifica` (cand exista, dupa S3/decizia 9) nu afecteaza grupul C (mereu activ); pe un document
deja emis, grupul C ramane `Enabled=.F.` inainte **si** dupa apasarea lui `but_modifica`.
7. **Verificare de regresie end-to-end**: emite acelasi document (numerar, chitanta, bon fiscal, POS —
toate patru, nu doar unul) o data pe calea veche (`frm_alte_date` dialog) si o data pe formularul
unificat, compara `poDate`-ul rezultat inainte de scriere in Oracle (aceleasi campuri de incasare,
acelasi numar alocat) — tipar deja folosit in `s3_portare_antet.md` §7 pentru S3, reutilizat aici
pe grupul mai mic al lui S3b.
*Depinde de S3* (planul o spune explicit) — pasii 4 si 6 presupun ca `but_modifica`/blocarea antetului
(proiectata in S3, sectiunea I a planului) exista deja ca mecanism, nu doar ca design pe hartie.
---
## 8. Ce nu se poate testa headless
Precedent direct: `s3_portare_antet.md` §8, si memoria de proiect
(`grid-coloane-nu-se-materializeaza-headless` — coloanele de grid nu se materializeaza sub `-A -T`,
exista harness UI vizibil separat care le citeste corect).
**Se POATE testa headless** (contrar primei intuitii, pentru ca e logica pe proprietati, nu pictura pe
ecran):
- Toata masina de stari `actualizeaza_tipincasare` — `Createobject()` fara `.Show()` tot ruleaza
`Init` si tot cabl eaza evenimentele; `thisform.opt_incasat.Value = n` declanseaza
`ProgrammaticChange` identic cu UI vizibil sau nu. Verificarile de alocare/dezalocare de la pasul 3
al sectiunii 7 sunt testabile 100% headless, pe proprietatile lui `poGeneratorNumere`.
- Vizibilitatea controalelor dupa toggle (`.Visible`, `.Height`, existenta obiectului via `Type(...)`)
— acelasi motiv, confirmat deja de `s3_portare_antet.md` §8 pentru mecanismul similar din `Init`-urile
de antet.
**NU se poate testa headless**:
- **Aspectul vizual real dupa pliere/depliere** (suprapuneri, goluri, pozitionarea corecta a
controalelor de sub sectiune dupa reflow-ul manual, sectiunea 6.1) — layout absolut-pozitionat, fara
reflow automat; verificarea ceruta e "arata bine pe ecran", nu o proprietate booleana — necesita
harness UI vizibil (memoria de proiect citata mai sus) sau verificare manuala de Marius.
- **Cele patru dialoguri modale** (`do_cauta_delegat`/`do_cauta_masina`/`do_cauta_agent`/
`do_cauta_adresa`) — interactiunea reala de alegere dintr-o lista nu se simuleaza headless; se poate
testa doar efectul **dupa** ce rezultatul cautarii e construit manual (tiparul deja folosit in
proiect, citat in `s3_portare_antet.md` §8, pct. 1).
- **Lookup-urile Oracle din `Init` (delegat/masina ultima factura, `v_nom_casa`)** — necesita conexiune
Oracle reala (harnessul suporta asta prin `MARIUSM_AUTO`, dar tot nu e "headless" in sensul de
"fara dependinte externe") si date de test care sa existe pentru clientul folosit.
- **Butonul `cmdModificaBon`/`do_modifica_bon`** — deschide `viz_config_serii_complet WITH 3`
(`oserii_numere.prg`), alt formular modal, aceeasi limitare ca dialogurile de cautare.
---
## 9. Riscuri si capcane
1. **Riscul central** (sectiunea 4.3): re-populare a starii `opt_incasat` la fiecare toggle de pliere
ar re-declansa alocare/dezalocare, incalcand direct criteriul cerut de decizia 25/S3b. Tratat
explicit ca pas 3 in ordinea de executie — **nu** de lasat "se rezolva de la sine prin arhitectura",
pentru ca mecanismul de declansare (`ProgrammaticChange`) e usor de lovit accidental de orice cod
ulterior care "resincronizeaza UI-ul cu modelul" intr-un loc gresit.
2. **Gap preexistent, nu introdus de S3b, dar mostenit prin "muta ca atare"**: `inainte_de_do_renunt`
(`:3025-3030`) nu dezaloca numarul POS (26) la anulare — doar chitanta (16) si bon fiscal (3). Daca
formularul unificat introduce vreo cale noua de "renunta la document" care nu mapeaza exact pe acest
cod, riscul se poate agrava (numar POS ramas alocat orfan, de fiecare data cand utilizatorul incepe
un document cu POS si renunta). Recomandare: fie se corecteaza in trecere (nu e in perimetrul strict
al portarii "ca atare", dar e o linie), fie se semnaleaza explicit ca bug cunoscut de preluat separat.
3. **`_checkbox1`/"Listare detaliata" vs. `chkDetaliat`** (sectiunea 1.4) — doua controale cu semantica
probabil identica, ambiguitate deja semnalata in S1 (randul 57), neinchisa aici. Formularul unificat
trebuie sa aleaga unul singur; alegerea gresita (portarea amandurora ca doua campuri distincte)
ar introduce un camp duplicat fara sens pentru utilizator.
4. **`do_dezactiveaza()` insuficient pentru read-only real** (sectiunea 2.1) — daca implementarea
apeleaza doar metoda existenta fara completarea de `ReadOnly`, decizia 26 nu e respectata mecanic:
campul arata blocat (fara lupa) dar tot accepta taste.
5. **Referinte `Thisform.xxx` nekvalificate** in `actualizeaza_tipincasare` (sectiunea 3.2) — orice
decizie de a pune sectiunea pliata intr-un container/obiect separat (nu direct pe `Thisform`) rupe
tacit aceste referinte, cu eroare de "obiect inexistent" la runtime, nu la compilare.
6. **Dependinta pe S3**: `but_modifica` si testul "document existent" (sectiunea 5.1) nu exista inca
nicaieri in cod — proiectate doar pe hartie in plan (sectiunea I). Pasii 4 si 6 din sectiunea 7 nu
pot fi *implementati* complet inainte ca S3 sa livreze acel mecanism, doar proiectati.
7. **Bug-ul de `sectie`** (`omodificari.vc2:13941`, semnalat deja in `rute_scriere_antet.md` §1.3 si
in plan `:761-764`) — nu afecteaza direct S3b (analiticele sunt read-only aici, deci S3b nu scrie
niciodata `id_sectie`), dar afecteaza increderea in ce se **afiseaza**: daca bug-ul e real, coloana
`id_sectie` din Oracle poate sa nu reflecte eticheta aratata dupa o editare din #6. In afara
perimetrului S3b de reparat (e in #6), dar relevant pentru cine citeste afisarea din #13 dupa o
editare de la #6.
---
## 10. Criteriul de "gata", rescris verificabil
Textul din plan (`:1849-1852`) spune: *"un document cu incasare prin bon fiscal emis din formularul
unificat produce aceleasi randuri si acelasi numar de bon ca pe calea veche; deschiderea si inchiderea
formularului fara a atinge zona de incasare nu aloca si nu dezaloca niciun numar; iar pe un document
emis analiticele se vad dar nu se pot edita."* Precizat mai jos, pe fiecare bucata:
1. **Paritate de emitere, pe toate patru tipurile de incasare, nu doar bon fiscal**: se emite acelasi
document de test (client, articole, cantitati, preturi identice) o data pe calea veche
(`frm_date_factura`/`frm_date_aviz` -> `frm_facturare_articole(2)` -> `frm_alte_date`) si o data pe
formularul unificat, pentru fiecare din **Fara incasare / Chitanta / Bon fiscal / POS-Card**. Se
compara `lcListaIncasare` (stringul asamblat inainte de `scrie_factura2`, sectiunea 3.1 al
`rute_scriere_antet.md`) si numarul alocat (`poDate.nr_incasare`) — trebuie sa fie identice pe
fiecare din cele patru cazuri, nu doar pe bon fiscal.
2. **Non-alocare la toggle de pliere, testabila headless** (sectiunea 7, pasul 3, deja formulat ca
assert concret pe `poGeneratorNumere`) — pe **doua** scenarii de start, nu unul: document nou
(`poDate.incasat=0` la construire) **si** document venit din copiere cu incasare presetata
(`poDate.incasat<>0`, sectiunea 4.1 punctul 3) — al doilea caz e cel care azi *deja* aloca la
deschidere, exact scenariul pe care criteriul trebuie sa-l acopere explicit.
3. **Blocarea grupului C, pe ambele stari ale antetului**: pe un document deja emis, campurile din
grupul de incasare raman `Enabled=.F.` atat inainte cat si dupa apasarea lui `but_modifica` — nu
doar "la deschidere" (ce ar lasa loc unei regresii daca `but_modifica` le-ar debloca din greseala
odata cu restul).
4. **Analiticele, pe ambele stari**: pe un document emis, cele patru campuri (venit/cheltuiala, sectie,
responsabil, lucrare) afiseaza valoarea curenta din sursa lor (sectiunea 2.3 — de precizat exact
care sursa la implementare) si resping orice tentativa de tastare directa sau de deschidere a
dialogului de cautare — verificat pe proprietatea `ReadOnly`/`lactiv`, nu doar vizual.
5. **Delegat/transport/adresa/text aditional** — paritate camp-cu-camp cu `frm_alte_date` de azi, pe
cel putin un document proforma (grup delegat/incasare eliminat, sectiunea 1.4) si unul non-proforma
(grup complet), ca sa acopere ambele ramuri ale `Init`-ului de azi (`:3109-3207`).
*Depinde de:* S3 (but_modifica, mecanismul de blocare a antetului). *Nu depinde de:* etapa II
(regenerarea) — grupurile B/C raman blocate prin design in etapa I, nu prin absenta temporara a unei
functionalitati care ar trebui testata aici.
---
## Ce ramane de decis de Marius
1. **Textul exact al tooltip-urilor** pentru analiticele read-only (sectiunea 2.2) si pentru grupul de
incasare blocat pe document emis (sectiunea 5.3) — doar continutul minim necesar e propus aici, nu
formularea finala.
2. **Granularitatea butonului/butoanelor de pliere**: un singur comutator pentru toata zona "alte date
+ analitice", sau unul separat per subgrup (delegat/transport, incasare, adresa, text, analitice)?
Plan sectiunea I nu specifica, iar tiparul gasit (`afiseaza_rulaje`) e per-sectiune unica, nu
per-formular-intreg — precedentul nu decide singur granularitatea (sectiunea 6.1).
3. **Eager vs. lazy pentru lookup-urile Oracle din `Init`** (delegat/masina ultima factura, casa) —
semnalat si in `s3_portare_antet.md` §5 ca discutie deschisa, reconfirmat aici pentru acelasi cod
(sectiunea 6.1, ultimul punct).
4. **Corectarea gap-ului de dezalocare POS la anulare** (sectiunea 9, punctul 2) — se repara in trecere
ca parte a S3b, sau se lasa exact ca azi si se semnaleaza separat ca bug de preluat ulterior?
5. **`_checkbox1` vs. `chkDetaliat`** (sectiunea 1.4, sectiunea 9 punctul 3) — care dintre cele doua
controale de "listare detaliata" devine campul unic in formularul unificat; ambiguitatea ramane
deschisa din S1 si nu s-a inchis aici.
## Handoff
Cercetare incheiata, nu intrerupta la mijloc — toate cele zece sectiuni cerute in briefing sunt
complete, cu citate `fisier:linie` verificate direct pe fisierele reale (nu `.bak`). Niciun cod
atins, nicio interogare Oracle rulata (nu a fost nevoie — tot ce trebuia era in codul VFP deja citit
sau in cele patru rapoarte de referinta). Fisierul e complet la aceasta versiune; nu e nevoie de o
sesiune de continuare pentru S3b ca atare. Urmatorul pas natural (nu al acestei sarcini) ar fi S3
insusi (blocarea antetului, `but_modifica`) — S3b depinde de el pentru pasii 4 si 6 din sectiunea 7,
dar proiectarea de aici nu asteapta acel livrabil, doar implementarea o va astepta.