diff --git a/CLAUDE.md b/CLAUDE.md
index 2f474c5..4af4563 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -119,6 +119,12 @@ Depanare detaliata: `COMUN\docs\depanare_testare_vfp.md`.
## Mod de lucru: delegare catre subagenti + review inainte de commit
+> **REGULA OBLIGATORIE (ceruta explicit de Marius, 26.08.2026):** orice investigatie,
+> modificare de cod, editare de fisiere, rulare de teste sau verificare se deleaga unui
+> SUBAGENT (Task tool). Sesiunea principala DOAR orchestreaza si verifica rezultatele
+> subagentilor; nu lucreaza direct pe fisiere, nu ruleaza suite, nu editeaza cod. Inca
+> de la prima sarcina a unui bloc, nu dupa ce ai acumulat context.
+
- **Predarea contextului e OBLIGATORIE, si pentru sesiunea principala, si pentru subagenti.**
Nu e o optimizare, e o conditie de corectitudine. Declansatoare: **~50% din fereastra**
(sesiunea principala / orchestrator), **~200-250k tokens** (subagent), anuntul de compactare
@@ -140,3 +146,43 @@ Depanare detaliata: `COMUN\docs\depanare_testare_vfp.md`.
iar sesiunea principala doar orchestreaza si verifica rezultatele.
- **Fara commit fara review**: nu da commit (git sau svn) din proprie initiativa pe modificari de
cod — diff-ul se livreaza intai ca fisier in `docs/`, iar commit-ul vine dupa aprobare.
+
+### Executie continua a unui plan (mandat permanent, Marius, 30.08.2026)
+
+> „vreau sa continui toate stories, cu commit dupa fiecare, si handoff la limita de context”
+
+Cand lucrezi la un plan cu mai multe stories, mandatul e valabil pana la revocare explicita:
+
+1. **Toate stories**, in ordinea de dependente din fisierul de executie al planului — fara oprire
+ dupa fiecare ca sa intrebi „continuam?”.
+2. **Commit dupa fiecare story**, pe branch-ul de lucru, in repo-ul potrivit (cod `COMUN` din
+ `COMUN\`, restul din radacina proiectului). Review inainte de commit, dar **fara a mai cere
+ aprobare** — aprobarea e data pentru intreg lantul. Fara push; SVN si merge-ul raman la Marius.
+3. **Handoff la limita de context** — vezi Regula zero de mai sus. Fisierul de stare viu al
+ planului se actualizeaza dupa FIECARE story inchisa, nu la final.
+
+Corolar cand Marius nu poate testa manual: pentru fiecare story al carui criteriu oficial de „gata”
+e o proba manuala UI, se proiecteaza si o **proba automata de paritate** (headless sau prin
+`vfp_ui_harness.ps1`), iar ce ramane obligatoriu manual se inregistreaza explicit ca **datorie
+deschisa** — nu se declara „gata”.
+
+## Ponytail (plugin la nivel de user)
+
+Plugin-ul tert `ponytail` e activ implicit pe nivelul `full` la fiecare sesiune si reinjectat in
+fiecare subagent — nu doar in sesiunea principala. Nu ruleaza retea si nu trimite telemetrie: scrie
+doar un flag local (`~/.claude/.ponytail-active`) si citeste `~/.claude/settings.json`.
+
+Se pastreaza scara YAGNI/reuse-first (nu scrii ce exista deja in `inventar-comun.md`,
+`COMUN\programe`, `COMUN\clase`, sau ce face VFP/Oracle nativ) — se suprapune cu regula
+proiectului de modificari minime, SCOPED.
+
+Ce NU se aplica aici, cu regula proiectului care primeaza (detaliu complet:
+`COMUN\docs\reguli_lucru.md`, punctul 3, „Scara ponytail”):
+- comentarii `ponytail:` in cod -> interzise (regula 2); scurtatura si limita ei merg in
+ `docs\progres.md`, nu inline.
+- proba „runnable test / assert self-check” -> script headless (regulile 4 si 8), nu `test_*.py`.
+- „cod intai, maxim trei randuri” -> nu se aplica handoff-urilor, rapoartelor din `docs\` si
+ patch-urilor, care sunt output cerut explicit.
+- `/ponytail-review` si `/ponytail-audit`: `delete:`/`yagni:` sunt ipoteze, nu constatari — in
+ `COMUN` cauti apelantii in tot `D:\ROA` inainte sa stergi; audit pe tot arborele nu se ruleaza aici.
+- nivelul `ultra` nu se foloseste pe cod legacy partajat.
diff --git a/Clase/ofacturare_util.vc2 b/Clase/ofacturare_util.vc2
new file mode 100644
index 0000000..073e9ac
--- /dev/null
+++ b/Clase/ofacturare_util.vc2
@@ -0,0 +1,136 @@
+*--------------------------------------------------------------------------------------------------------------------------------------------------------
+* (EN) AUTOGENERATED - ATTENTION!! - NOT INTENDED FOR EXECUTION!! USE ONLY FOR MERGING CHANGES AND STORING WITH SCM TOOLS!!
+*--------------------------------------------------------------------------------------------------------------------------------------------------------
+*< FOXBIN2PRG: Version="1.21" SourceFile="ofacturare_util.vcx" CPID="1252" /> (Solo para binarios VFP 9 / Only for VFP 9 binaries)
+*
+*
+DEFINE CLASS frm_cursuri_valutare AS _frmbase OF "_frm_base.vcx"
+ *< CLASSDATA: Baseclass="form" Timestamp="" Scale="Pixels" Uniqueid="" />
+
+ *-- OBJECTDATA items order determines ZOrder / El orden de los items OBJECTDATA determina el ZOrder
+ *< OBJECTDATA: ObjPath="grd_cursuri" UniqueID="" Timestamp="" />
+ *< OBJECTDATA: ObjPath="grd_cursuri.cCurs.Header1" UniqueID="" Timestamp="" />
+ *< OBJECTDATA: ObjPath="grd_cursuri.cCurs.Text1" UniqueID="" Timestamp="" />
+ *< OBJECTDATA: ObjPath="grd_cursuri.cNume_val.Header1" UniqueID="" Timestamp="" />
+ *< OBJECTDATA: ObjPath="grd_cursuri.cNume_val.Text1" UniqueID="" Timestamp="" />
+ *< OBJECTDATA: ObjPath="grd_cursuri.cMultiplicator.Header1" UniqueID="" Timestamp="" />
+ *< OBJECTDATA: ObjPath="grd_cursuri.cMultiplicator.Text1" UniqueID="" Timestamp="" />
+
+ *
+ AutoCenter = .T.
+ Caption = "Cursuri valutare"
+ DoCreate = .T.
+ Height = 224
+ Name = "frm_cursuri_valutare"
+ Width = 420
+ WindowType = 1
+ _shape1.Name = "_shape1"
+ _shape1.Width = 422
+ _shape2.Left = 370
+ _shape2.Name = "_shape2"
+ Lb_titlu_alb_b121.Caption = "Curs valutar"
+ Lb_titlu_alb_b121.FontBold = .T.
+ Lb_titlu_alb_b121.Name = "Lb_titlu_alb_b121"
+ BUT_TERMIN1.Left = 390
+ BUT_TERMIN1.Name = "BUT_TERMIN1"
+ *
+
+ ADD OBJECT 'grd_cursuri' AS _grdrow WITH ;
+ ColumnCount = 3, ;
+ DeleteMark = .F., ;
+ FontName = "Arial Narrow", ;
+ Height = 180, ;
+ Left = 12, ;
+ Name = "grd_cursuri", ;
+ ScrollBars = 2, ;
+ TabIndex = 1, ;
+ Top = 32, ;
+ Width = 396, ;
+ Column1.ColumnOrder = 3, ;
+ Column1.ControlSource = "curs", ;
+ Column1.FontName = "Arial Narrow", ;
+ Column1.InputMask = (get_mask(14,gnPCurs)), ;
+ Column1.Name = "cCurs", ;
+ Column1.Width = 102, ;
+ Column2.ColumnOrder = 2, ;
+ Column2.ControlSource = "nume_val", ;
+ Column2.FontName = "Arial Narrow", ;
+ Column2.Name = "cNume_val", ;
+ Column2.Width = 130, ;
+ Column3.ColumnOrder = 1, ;
+ Column3.ControlSource = "multiplicator", ;
+ Column3.FontName = "Arial Narrow", ;
+ Column3.InputMask = (get_mask(10,0)), ;
+ Column3.Name = "cMultiplicator", ;
+ Column3.Width = 130
+ *< END OBJECT: ClassLib="_grd_base.vcx" BaseClass="grid" />
+
+ ADD OBJECT 'grd_cursuri.cCurs.Header1' AS header WITH ;
+ Alignment = 2, ;
+ Caption = "Curs", ;
+ FontName = "Arial Narrow", ;
+ Name = "Header1"
+ *< END OBJECT: BaseClass="header" />
+
+ ADD OBJECT 'grd_cursuri.cCurs.Text1' AS textbox WITH ;
+ BackColor = 255,255,255, ;
+ BorderStyle = 0, ;
+ FontName = "Arial Narrow", ;
+ ForeColor = 0,0,0, ;
+ Margin = 0, ;
+ Name = "Text1", ;
+ SelectedBackColor = 0,64,128
+ *< END OBJECT: BaseClass="textbox" />
+
+ ADD OBJECT 'grd_cursuri.cMultiplicator.Header1' AS header WITH ;
+ Alignment = 2, ;
+ Caption = "Multiplicator", ;
+ FontName = "Arial Narrow", ;
+ Name = "Header1"
+ *< END OBJECT: BaseClass="header" />
+
+ ADD OBJECT 'grd_cursuri.cMultiplicator.Text1' AS textbox WITH ;
+ BackColor = 255,255,255, ;
+ BorderStyle = 0, ;
+ FontName = "Arial Narrow", ;
+ ForeColor = 0,0,0, ;
+ Margin = 0, ;
+ Name = "Text1", ;
+ SelectedBackColor = 100,185,255
+ *< END OBJECT: BaseClass="textbox" />
+
+ ADD OBJECT 'grd_cursuri.cNume_val.Header1' AS header WITH ;
+ Alignment = 2, ;
+ Caption = "Valuta", ;
+ FontName = "Arial Narrow", ;
+ Name = "Header1"
+ *< END OBJECT: BaseClass="header" />
+
+ ADD OBJECT 'grd_cursuri.cNume_val.Text1' AS textbox WITH ;
+ BackColor = 255,255,255, ;
+ BorderStyle = 0, ;
+ FontName = "Arial Narrow", ;
+ ForeColor = 0,0,0, ;
+ Margin = 0, ;
+ Name = "Text1", ;
+ SelectedBackColor = 0,64,128
+ *< END OBJECT: BaseClass="textbox" />
+
+ PROCEDURE Init
+ Lparameters tcCursor, tdZiCurs, tnTip
+ Local lcCursor
+ DoDefault()
+ lcCursor = Iif(Empty(tcCursor), 'crscursuri', tcCursor)
+ If !Used(m.lcCursor) Or Reccount(m.lcCursor) = 0
+ This.Release()
+ Return .F.
+ Endif
+ This.grd_cursuri.RecordSource = m.lcCursor
+ If !Empty(Nvl(m.tdZiCurs, {}))
+ This.Lb_titlu_alb_b121.Caption = "Curs valutar (" + Dtoc(m.tdZiCurs) + ")"
+ Else
+ This.Lb_titlu_alb_b121.Caption = "Curs valutar"
+ Endif
+ ENDPROC
+
+ENDDEFINE
diff --git a/Clase/ofundal_facturare.vc2 b/Clase/ofundal_facturare.vc2
index eeeee74..ce70e02 100644
--- a/Clase/ofundal_facturare.vc2
+++ b/Clase/ofundal_facturare.vc2
@@ -32,11 +32,14 @@ DEFINE CLASS pg_meniu_princ AS pg_meniu OF "..\comun\clase\ofundal.vcx"
*< OBJECTDATA: ObjPath="Page2.Cw8" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Page2.Pict_liniuta2" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Page2.Cw9" UniqueID="" Timestamp="" />
+ *< OBJECTDATA: ObjPath="Page2.Cw10" UniqueID="" Timestamp="" />
+ *< OBJECTDATA: ObjPath="Page2.Pict_liniuta1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Page3.Pict_meniu1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Page3.Cw1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Page3.Cw4" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Page3.Cw3" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Page3.Cw2" UniqueID="" Timestamp="" />
+ *< OBJECTDATA: ObjPath="Page3.Cw5" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Page4.Pict_meniu1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Page4.Cw1" UniqueID="" Timestamp="" />
*< OBJECTDATA: ObjPath="Page4.Cw4" UniqueID="" Timestamp="" />
@@ -244,6 +247,16 @@ DEFINE CLASS pg_meniu_princ AS pg_meniu OF "..\comun\clase\ofundal.vcx"
Label_item1.WordWrap = .T.
*< END OBJECT: ClassLib="..\comun\clase\ofundal.vcx" BaseClass="container" />
+ ADD OBJECT 'Page2.Cw10' AS cw WITH ;
+ Left = 5, ;
+ Name = "Cw10", ;
+ nid_cw = 10, ;
+ TabIndex = 10, ;
+ Top = 250, ;
+ Label_item1.Caption = "Facturare (nou)", ;
+ Label_item1.Name = "Label_item1"
+ *< END OBJECT: ClassLib="..\comun\clase\ofundal.vcx" BaseClass="container" />
+
ADD OBJECT 'Page2.Cw2' AS cw WITH ;
Left = 5, ;
Name = "Cw2", ;
@@ -348,6 +361,13 @@ DEFINE CLASS pg_meniu_princ AS pg_meniu OF "..\comun\clase\ofundal.vcx"
LABEL_ITEM1.WordWrap = .T.
*< END OBJECT: ClassLib="..\comun\clase\ofundal.vcx" BaseClass="container" />
+ ADD OBJECT 'Page2.Pict_liniuta1' AS pict_liniuta WITH ;
+ Left = 6, ;
+ Name = "Pict_liniuta1", ;
+ Picture = ..\comun\grafice\f3.jpg, ;
+ Top = 239
+ *< END OBJECT: ClassLib="..\comun\clase\ofundal.vcx" BaseClass="image" />
+
ADD OBJECT 'Page2.Pict_liniuta2' AS pict_liniuta WITH ;
Left = 6, ;
Name = "Pict_liniuta2", ;
@@ -411,6 +431,16 @@ DEFINE CLASS pg_meniu_princ AS pg_meniu OF "..\comun\clase\ofundal.vcx"
Label_item1.WordWrap = .T.
*< END OBJECT: ClassLib="..\comun\clase\ofundal.vcx" BaseClass="container" />
+ ADD OBJECT 'Page3.Cw5' AS cw WITH ;
+ Left = 5, ;
+ Name = "Cw5", ;
+ nid_cw = 5, ;
+ TabIndex = 5, ;
+ Top = 106, ;
+ Label_item1.Caption = "Avize (nou)", ;
+ Label_item1.Name = "Label_item1"
+ *< END OBJECT: ClassLib="..\comun\clase\ofundal.vcx" BaseClass="container" />
+
ADD OBJECT 'Page3.Pict_meniu1' AS pict_meniu WITH ;
Height = 473, ;
Left = 2, ;
@@ -619,6 +649,9 @@ DEFINE CLASS pg_meniu_princ AS pg_meniu OF "..\comun\clase\ofundal.vcx"
_grdrow1.cAgent.Header1.Name = "Header1", ;
_grdrow1.cAgent.Name = "cAgent", ;
_grdrow1.cAgent.Text1.Name = "Text1", ;
+ _grdrow1.cCodFiscal.Header1.Name = "Header1", ;
+ _grdrow1.cCodFiscal.Name = "cCodFiscal", ;
+ _grdrow1.cCodFiscal.Text1.Name = "Text1", ;
_grdrow1.cComanda_externa.Header1.Name = "Header1", ;
_grdrow1.cComanda_externa.Name = "cComanda_externa", ;
_grdrow1.cComanda_externa.Text1.Name = "Text1", ;
@@ -641,6 +674,9 @@ DEFINE CLASS pg_meniu_princ AS pg_meniu OF "..\comun\clase\ofundal.vcx"
_grdrow1.cFacturat.Name = "cFacturat", ;
_grdrow1.cFacturat._checkbox1.Alignment = 2, ;
_grdrow1.cFacturat._checkbox1.Name = "_checkbox1", ;
+ _grdrow1.cIdPart.Header1.Name = "Header1", ;
+ _grdrow1.cIdPart.Name = "cIdPart", ;
+ _grdrow1.cIdPart.Text1.Name = "Text1", ;
_grdrow1.cLucrare.Header1.Name = "Header1", ;
_grdrow1.cLucrare.Name = "cLucrare", ;
_grdrow1.cLucrare.Text1.Name = "Text1", ;
@@ -690,6 +726,9 @@ DEFINE CLASS pg_meniu_princ AS pg_meniu OF "..\comun\clase\ofundal.vcx"
_grdrow2.cNrCrt.Header1.Name = "Header1", ;
_grdrow2.cNrCrt.Name = "cNrCrt", ;
_grdrow2.cNrCrt.Text1.Name = "Text1", ;
+ _grdrow2.cNumeListaPreturi.Header1.Name = "Header1", ;
+ _grdrow2.cNumeListaPreturi.Name = "cNumeListaPreturi", ;
+ _grdrow2.cNumeListaPreturi.Text1.Name = "Text1", ;
_grdrow2.cPret.Header1.Name = "Header1", ;
_grdrow2.cPret.Name = "cPret", ;
_grdrow2.cPret.Text1.Name = "Text1", ;
@@ -697,6 +736,9 @@ DEFINE CLASS pg_meniu_princ AS pg_meniu OF "..\comun\clase\ofundal.vcx"
_grdrow2.cPret_cu_tva.Name = "cPret_cu_tva", ;
_grdrow2.cPret_cu_tva._checkbox1.Alignment = 2, ;
_grdrow2.cPret_cu_tva._checkbox1.Name = "_checkbox1", ;
+ _grdrow2.cPTVA.Header1.Name = "Header1", ;
+ _grdrow2.cPTVA.Name = "cPTVA", ;
+ _grdrow2.cPTVA.Text1.Name = "Text1", ;
_grdrow2.Height = 367, ;
_grdrow2.Left = 173, ;
_grdrow2.Name = "_grdrow2", ;
@@ -734,7 +776,8 @@ DEFINE CLASS pg_meniu_princ AS pg_meniu OF "..\comun\clase\ofundal.vcx"
Cmd_executa4.Top = 425, ;
But_factura1.Name = "But_factura1", ;
BUT_START_CRITERII1.Name = "BUT_START_CRITERII1", ;
- BUT_RESET_CRITERII1.Name = "BUT_RESET_CRITERII1"
+ BUT_RESET_CRITERII1.Name = "BUT_RESET_CRITERII1", ;
+ But_attach1.Name = "But_attach1"
*< END OBJECT: ClassLib="..\comun\clase\ocomenzi.vcx" BaseClass="container" />
ADD OBJECT 'Page6.Ct_lucrari_detalii1' AS ct_lucrari_detalii WITH ;
@@ -883,6 +926,45 @@ DEFINE CLASS pg_meniu_princ AS pg_meniu OF "..\comun\clase\ofundal.vcx"
DO facturare_lista_de_preturi IN oproceduri_facturare.prg
ENDPROC
+ PROCEDURE Page2.Cw10.do_actiune
+ Private plFacturareNoua
+ plFacturareNoua = .T.
+ lcOptiuni = 'In lei;Retur factura in lei;Restaurant;Marfa in custodie - fara descarcare K;Marfa in custodie - cu descarcare K;\-;Invoice;Credit note;Factura fiscala in valuta;Retur factura in valuta'
+ lcOptiuni = m.lcOptiuni + ';\-;Contract: Factura lei;Contract: Invoice;Contract: Factura fiscala in valuta;\-;Pe baza de comanda;Din aviz'
+ lnOptiune = xmenu(m.lcOptiuni)
+ DO CASE
+ CASE m.lnOptiune = 1
+ factureaza(1)
+ CASE m.lnOptiune = 2
+ factureaza(8)
+ CASE m.lnOptiune = 3
+ factureaza(45)
+ CASE m.lnOptiune = 4
+ factureaza(49)
+ CASE m.lnOptiune = 5
+ factureaza(48)
+ CASE m.lnOptiune = 7
+ factureaza(5)
+ CASE m.lnOptiune = 8
+ factureaza(7)
+ CASE m.lnOptiune = 9
+ factureaza(10)
+ CASE m.lnOptiune = 10
+ factureaza(9)
+ CASE m.lnOptiune = 12
+ DO facturare_contracte WITH 'FACTURA LEI' IN oproceduri_facturare.prg
+ CASE m.lnOptiune = 13
+ DO facturare_contracte WITH 'INVOICE' IN oproceduri_facturare.prg
+ CASE m.lnOptiune = 14
+ DO facturare_contracte WITH 'FACTURA VALUTA' IN oproceduri_facturare.prg
+ CASE m.lnOptiune = 16
+ goComanda = ''
+ DO facturare_comenzi IN oproceduri_facturare.prg
+ CASE m.lnOptiune = 17
+ DO facturare_avize IN oproceduri_facturare.prg
+ ENDCASE
+ ENDPROC
+
PROCEDURE Page2.Cw2.do_actiune
lnOptiune = xmenu('Factura lei;Invoice;Factura fiscala in valuta')
DO CASE
@@ -941,6 +1023,22 @@ DEFINE CLASS pg_meniu_princ AS pg_meniu OF "..\comun\clase\ofundal.vcx"
DO aviz_subunitati.mpr
ENDPROC
+ PROCEDURE Page3.Cw5.do_actiune
+ Private plFacturareNoua
+ plFacturareNoua = .T.
+ lnOptiune = xmenu('Cãtre clienþi;Cãtre clienþi în custodie;Cãtre clienþi debitori;Transfer între subunitãþi')
+ DO CASE
+ CASE m.lnOptiune = 1
+ This.Parent.Cw1.do_actiune()
+ CASE m.lnOptiune = 2
+ This.Parent.Cw2.do_actiune()
+ CASE m.lnOptiune = 3
+ This.Parent.Cw3.do_actiune()
+ CASE m.lnOptiune = 4
+ This.Parent.Cw4.do_actiune()
+ ENDCASE
+ ENDPROC
+
PROCEDURE Page4.Cw1.do_actiune
lnOptiune = xmenu('Vizualizare \
+
+
+
+
+
+
+
NOTE_CONTABILE`, `ff_...:7248-7253,7259-7260`), fara nicio ramura care sa citeasca `V_CONT`.
-`V_CONT` alimenteaza doar `descarca_gestiune` (contul de iesire din gestiune, SCC pe nota de
-**stoc**, nu de venit), nu nota de venit.
-
-### 2. Variabile de sesiune `pack_facturare` — **NU exista setter pentru cont**
-
-Am listat toate variabilele publice de pachet cu prefix `nid_` din specificatia `pack_facturare`
-(`ff_...:72-211`, citat exhaustiv, cautare `grep -n "^ nid_"`):
-
-```
-nid_tipnir, nid_tipbon, nid_tipfactura, nid_tipaviz, nid_act, nid_serie, nid_fdoc, nid_part,
-nid_part_rez, nid_lucrare, nid_sectie_stoc, nid_gestiune_sursa, nid_responsabil, nid_ordl, nid_set,
-nid_util, nid_moneda_nationala, nid_fact, nid_factc, nid_partc, nid_jtva_coloana, nid_comanda,
-nid_valuta, nid_politica_stoc, nid_sucursala, nid_venchelt, nid_vanzare, nid_beneficiar
-```
-
-Niciuna tipata pe un cont (`VARCHAR2(4)`/cod de cont) — toate sunt FK-uri numerice
-(`%TYPE` pe alte tabele: `ID_SECTIE`, `ID_VENCHELT`, `ID_POL`, etc.). Cautare directa
-`nid_scc`/`nid_scd`/`nid_cont` in tot fisierul: **zero rezultate**. `nid_venchelt` (folosit ca
-fallback la `ID_VENCHELT` in `cursor_articol`, `ff_...:7244-7245`, deja documentat in
-`coresp_cont_venchelt.md` sectiunea 7) e o clasificare dimensionala
-(`NOM_VENIT_CHELTUIELI.ID_VENCHELT%TYPE`), nu un cont — **nu am gasit consumator care sa-l foloseasca
-drept `SCC`**. Cautare separata `PROCEDURE SET_` in tot pachetul: zero rezultate — nu exista niciun
-setter public de tip `SET_...` pentru cont. **Concluzie: NU.**
-
-### 3. `ACT_TEMP` scris direct din VFP — **DA, canal real, dar pe fluxul de editare, nu de emitere**
-
-Confirmat de `COMUN\docs\oracle_export.md:64-65`: *"Pachetul central de scriere a documentelor —
-clientul VFP populeaza tabelele temporare `ACT_TEMP`/`RUL_TEMP` (prin `oscrie_in_fisiere`-ul din
-COMUN), apoi pachetul distribuie"*. Mecanismul e generic si complet independent de `pack_facturare`:
-
-**Mecanismul** (`COMUN\programe\oscrie_in_fisiere.prg`):
-- `sql_temp_insert('actactan','ACT_TEMP')` (`oscrie_in_fisiere.prg:127`) face, pentru fiecare rand al
- oricarui cursor VFP numit `actactan`, un `INSERT INTO ACT_TEMP () VALUES (...)` construit dinamic din `user_tab_columns`
- (`oscrie_in_fisiere.prg:190-280`) — **orice camp `SCD`/`ASCD`/`SCC`/`ASCC` prezent in cursorul VFP
- ajunge direct in `ACT_TEMP`, indiferent de valoare, fara nicio validare de cont**.
-- Scrierea efectiva in `ACT` se face prin `pack_contafin.init_scriere_act_rul_local` +
- `final_scriere_act_rul_local` -> `SCRIE_IN_ACT`/`STERGE_DIN_ACT` (`oscrie_in_fisiere.prg:121-147`)
- — **`pack_contafin`, nu `pack_facturare`**. Confirmat si in
- `COMUN\docs\flux-modificare-stergere-nota-jurnal.md:20-28`.
-
-**Cine populeaza `actactan` cu valori calculate/editate de VFP** — cele doua cazuri gasite, ambele
-active in productie:
-
-**(a) Registrul Jurnal — editare/stergere manuala de nota, orice document, generic**
-(`COMUN\clase\comun.vc2`, clasa `afisjurcom`):
-- `do_modifica` (`comun.vc2:2222-2562`): incarca nota existenta
- (`Select * From v_act Into Cursor actactan`, `comun.vc2:2363`), instantiaza
- `frm_modific2024` (`comun.vc2:2439`, `omodificari.vc2:6375`) — formular in care utilizatorul poate
- edita direct `scd`/`ascd`/`scc`/`ascc` pe fiecare rand al notei (grid legat pe `tact`, verificare
- prin `verific_analitic`/`do_verifica`, tipar prezent si in `omodificari.vc2:1714-1788` — comentat
- azi, dar acelasi tipar activ e in `frm_modific2024`, vezi mai jos (b)). Dupa editare:
- `oscrie_in_fisiere(2,...)` = sterge nota veche (`comun.vc2:2454`), apoi
- `oscrie_in_fisiere(0,...)` = scrie nota noua **cu valorile din cursorul editat**
- (`comun.vc2:2482`), apoi `pack_contafin.finalizeaza_modificare_nota(...)`
- (`comun.vc2:2484-2486`). **Niciun apel catre `pack_facturare` in acest flux.**
-- Documentat integral, cu aceleasi citate, in `COMUN\docs\flux-modificare-stergere-nota-jurnal.md`.
-- E generic pe orice document din `ACT` (nu doar facturi) — daca o factura emisa are deja o nota,
- poate fi editata de aici.
-
-**(b) Editarea facturii emise — acelasi mecanism, scop specific "facturi emise" (proiectul #6
-insusi)**, `COMUN\clase\ofacturare_comun.vc2:3769-3838` (functia `do_editare_factura`, citita
-integral, **nu modificata**):
-
-```
-ofacturare_comun.vc2:3769 If IncarcaCursoareModificareNota(lnCod, pnAn, pnLuna, .F.) && ofacturare_editare.prg
-...
-ofacturare_comun.vc2:3787 Select a.*, Iif(Nvl(id_jtva_coloana,0)=0,0,1) As cu_Tva From tact a Into Cursor tact Readwrite
-...
-ofacturare_comun.vc2:3796 Omodif = Createobject([frm_modific2024], lnIdSet)
-ofacturare_comun.vc2:3797 Omodif.Show()
-ofacturare_comun.vc2:3799 If buton = 1
-ofacturare_comun.vc2:3800 If Thisform.do_deschide_tranzactie()
-ofacturare_comun.vc2:3801 Select actactan
-ofacturare_comun.vc2:3802 lnSucces = OSCRIE_IN_FISIERE(2,.T.,.T.) && sterge nota veche
-ofacturare_comun.vc2:3803 If lnSucces > 0
-...
-ofacturare_comun.vc2:3807 Select tact
-ofacturare_comun.vc2:3808 Replace id_jtva_coloana With Null, proc_tva With 0 For cu_Tva = 0
-ofacturare_comun.vc2:3809 Select * From tact Into Cursor actactan Readwrite && re-materializeaza tact (inclusiv orice SCD/SCC editat) in actactan
-ofacturare_comun.vc2:3810 Replace All id_util With gnIdUtil, sters With 0
-...
-ofacturare_comun.vc2:3821 lnSucces = OSCRIE_IN_FISIERE(0,.T.,.T.) && scrie nota noua, direct din actactan, in ACT_TEMP
-ofacturare_comun.vc2:3823 If lnSucces > 0
-ofacturare_comun.vc2:3824 lcSql = [begin pack_contafin.finalizeaza_modificare_nota(...); end;]
-ofacturare_comun.vc2:3828 If lnSucces > 0 And "OFACTURARE_EDITARE" $ Upper(Set("Procedure")) And Used('tvanz')...
-ofacturare_comun.vc2:3829 lnSucces = Iif(ScrieArticoleFacturaEditate(tvanz.id_vanzare), 1, -1) && scrie si VANZARI_DETALII
-```
-
-`IncarcaCursoareModificareNota` (`COMUN\programe\ofacturare_editare.prg:32-71`) incarca nota
-existenta a facturii (`vact_tot -> v_act -> actactan -> tact`, toate **READWRITE**) inainte de a
-arata `frm_modific2024`. Linia `:3809` **rescrie `actactan` direct din `tact`** — orice valoare
-aflata pe `tact.scd`/`tact.scc` in acel moment (editata manual prin `frm_modific2024`, sau setata
-programatic de orice cod VFP inainte de linia 3809) devine noua nota, scrisa in `ACT_TEMP` prin
-`OSCRIE_IN_FISIERE(0,...)` la linia 3821 — **fara niciun apel `pack_facturare`, fara politica de
-pret**. `pack_contafin.finalizeaza_modificare_nota` (linia 3824) doar re-leaga `cod`-ul nou de
-`VANZARI`; `ScrieArticoleFacturaEditate` (linia 3829) scrie separat `VANZARI_DETALII`.
-
-**Aceasta e dovada cea mai puternica posibila pentru intrebarea pusa**: canalul nu e teoretic — e
-**exact mecanismul pe care proiectul #6 il foloseste azi** ca sa permita editarea contului unei
-facturi deja emise, complet in afara `pack_facturare`.
-
-**Limitarea reala**: mecanismul opereaza pe **o nota deja existenta** (sterge randul vechi din `ACT`,
-scrie unul nou cu acelasi `id_fact`) — presupune ca factura a fost deja scrisa o data (prin
-`pack_facturare`, cu politica). Nu e (azi) un canal pentru **emiterea** initiala a unei facturi noi
-cu un articol fara politica — `scrie_factura2 -> contabilizeaza_articol` (calea de emitere) nu are
-nicio ramura care sa ocoleasca politica si nu apeleaza acest mecanism.
-
-**Alte doua confirmari ale aceluiasi tipar, tot pentru categoria "facturi"**:
-- `COMUN\ferestre\frm_initializare_facturi_balanta.sc2:458` — `CREATE CURSOR actactan (id_set I, an
- N(4), luna N(2), Dataact D, datascad D, dataireg D, serie_act C(20), nract N(20), proc_tva N(5,2),
- id_jtva_coloana I NULL, scd C(4), ascd C(4), scc C(4), ascc C(4), ...)` — cursor creat de la zero
- in VFP, cu `scd`/`scc` campuri simple, editabile liber, fara nicio derivare Oracle. Foloseste tot
- `frm_modific2024` (`:1806`) pentru editare/validare inainte de scriere.
-- `COMUN\ferestre\frm_import_note_facturi_clienti.sc2:667,815,898,911` — acelasi tipar
- (`actactan`/`tact` editabil + `frm_modific2024`), pentru import manual de note pe facturi de
- clienti.
-
-Ambele sunt scenarii de **initializare/import** (sold de deschidere, import de note), nu de
-facturare curenta — dar confirma ca `ACT_TEMP` pentru **categoria "facturi"** se scrie deja, in mod
-curent, direct din cursoare VFP construite de la zero, fara `pack_facturare`.
-
-### 4. `ID_VENCHELT` / `CRM_NOTE_VANZARI` — **NU e canal alternativ catre SCC**
-
-Deja stabilit exhaustiv in `coresp_cont_venchelt.md` sectiunea 7: `ID_VENCHELT` e o dimensiune
-(`NOM_VENIT_CHELTUIELI.ID_VENCHELT`), citita cu fallback pe `nid_venchelt`
-(`ff_...:7244-7245`), dar **nu participa la calculul `SCC`** — `V_SCC` vine exclusiv din
-`cursor_articol.D.SCC`. Nu exista camp de tip cont pe `VANZARI`/`VANZARI_DETALII` — reconfirmat aici
-prin cautare `grep -inE "SCC|CONT_VENIT"` in blocurile `CREATE`/`ALTER TABLE VANZARI` din
-`ff_...` (fara rezultate suplimentare fata de ce era deja stabilit).
-
-### 5. `GetAnaliticByGrupUtilizatori` — **doar analitic, nu cont sintetic**
-
-Confirmat deja in `coresp_cont_venchelt.md` sectiunea 7: functia da fallback pentru `ASCD`/`ASCC`
-(analiticul), nu pentru `SCD`/`SCC` (contul sintetic). Nu exista o functie analoaga pentru cont —
-cautare `GetSinteticBy`/`GetContBy` in tot `ff_...`: zero rezultate.
-
----
-
-## Lista exhaustiva a intrarilor catre `SCD`/`SCC` in `ACT_TEMP`, pe/langa fluxul de facturare
-
-Sursa: `ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` + fisierele VFP citate.
-
-1. **`pack_facturare.contabilizeaza_articol -> scrie_nota`** (`ff_...:7218-7556` / `12338-12570`,
- `INSERT INTO ACT_TEMP` la `:12458-12544`) — calea principala de **emitere**. `SCD`/`SCC` vin din
- `cursor_articol` (`D.SCD`, `D.SCC`, lantul politicii). Blocheaza cu FACT-024
- (`:7275-7311`) daca articolul nu e in politica — fara fallback (deja stabilit in
- `nota_contabila_fara_politica.md`).
-2. **Ramurile speciale din `scrie_factura2`** (transfer subunitati `ntip IN (23,25,30,41)`, custodie
- `ntip IN (42,47)`, rata `id_rata<>0`) — tot `contabilizeaza_articol`, acelasi punct 1.
-3. **`scrie_factura_avize_retur`** (`ff_...:6273-6666`, apel la `:6867`) si **`scrie_aviz_retur`**
- (`ff_...:7094-7180`, apel la `:7149`) — tot `contabilizeaza_articol`.
-4. **`descarca_gestiune`** (`ff_...:7476-7498`, apelata din interiorul buclei `cursor_articol`) —
- scrie o a doua nota, de **iesire din gestiune** (`SCD`/`SCC` = conturi de stoc, din `V_CONT`/
- `poArticol.Cont`, nu din politica) — parte a fluxului de facturare, dar nu e nota de venit.
-5. **Discount pe linie** (`ff_...:7501-7518`) — scrie o nota separata (vazuta pe date live ca
- `id_nota=2`, `SCD=667`/`SCC=4111`, `verif_baza_vie_cont_venit.md` sectiunea 4) — tot in interiorul
- `cursor_articol`, deci tot dependenta de politica pentru a ajunge acolo.
-6. **`oscrie_vanzare_din_stoc`** (`COMUN\programe\ofacturare_stoc.prg:104-450`) — flux ROAGEST
- "vanzare din stoc". Apeleaza `pack_facturare.adauga_articol_factura_stoc` per articol
- (`:357-378`) apoi `oscrie_in_fisiere(0,.F.,.T.)` (`:392`). **Neverificat complet**: codul citit nu
- arata explicit unde/cum se populeaza `actactan` cu `SCD`/`SCC` inainte de linia 392 in acest flux
- particular (cursorul `ACTACTAN` e doar *citit* la `:253-289` pentru alte campuri, nu am gasit
- punctul de scriere in fisierul citit) — posibil populat de o procedura anterioara neexaminata.
- Marcat ca zona neinchisa, vezi "Ce nu s-a putut stabili".
-7. **Registrul Jurnal — editare/stergere manuala** (`COMUN\clase\comun.vc2:2222-2724`, clasa
- `afisjurcom`) — canalul confirmat la pista 3(a). Genereic, orice document din `ACT`.
-8. **Editare factura emisa** (`COMUN\clase\ofacturare_comun.vc2:3769-3838`, proiectul #6) — canalul
- confirmat la pista 3(b), specific "facturi emise".
-9. **`frm_initializare_facturi_balanta.sc2`** si **`frm_import_note_facturi_clienti.sc2`** — canalul
- confirmat la pista 3, scop initializare/import pe categoria "facturi".
-10. **eFactura import** (`COMUN\clase\anaf_efactura.vc2:12241,13087-13102,13244-13325`) — acelasi
- tipar generic (`actactan`/`tact` + `frm_modific2024` + `oscrie_in_fisiere`), dar pentru facturi
- de **achizitie** importate din XML ANAF, nu facturi emise — mentionat pentru completitudine, nu
- aplicabil direct la #13.
-11. **`ointroduceri.vc2`/`ointroduceri.prg`** (NIR, BON, RETUR, intrare din gestiune valorica) si
- **`oschimbare_pret.prg`**, **`oproceduri_rulaje.prg`**, **`reglari_denominare2005.prg`** —
- acelasi canal generic `actactan`/`oscrie_in_fisiere`, dar pentru alte categorii de document
- (gestiune, nu vanzare/factura). Mentionate pentru completitudinea listei de consumatori ai
- canalului, nu aplicabile la #13.
-
-**Niciuna dintre intrarile 1-6 (fluxul de emitere efectiv) nu are o ramura care sa ocoleasca
-politica.** Intrarile 7-11 folosesc toate acelasi canal generic (punctul 3), dar niciuna nu e
-cablata pe fluxul de **emitere** — toate opereaza pe note deja existente sau pe alte categorii de
-document.
-
----
-
-## DDL `ACT_TEMP` (interogat 10.08.2026, schema `MARIUSM_AUTO`, `ROA_CENTRAL`)
-
-| Coloana | Tip | Null |
-|---|---|---|
-| SCD | VARCHAR2(4) | **Y** |
-| ASCD | VARCHAR2(4) | Y |
-| SCC | VARCHAR2(4) | **Y** |
-| ASCC | VARCHAR2(4) | Y |
-| COD, NRACT, SUMA, PERECHED, PERECHEC, SUMA_VAL, CURS, NEIMPOZAB, NNIR, ID_UTIL, ID_UTILS, ID_RESPONSABIL, ID_VENCHELT, ID_SECTIE, ID_SET, ID_FACT, ID_PARTD, ID_PARTC, ID_FDOC, ID_LUCRARE, ID_GESTIN, ID_GESTOUT, ID_VALUTA, PROC_TVA, STERS, ID_FACTD, ID_FACTC, VALIDAT, TVA_INCASARE | numeric | N (29 coloane NOT NULL, restul optionale) |
-
-Restul coloanelor (52 in total) sunt fie `NUMBER` (majoritatea `NOT NULL`), fie `DATE`/`VARCHAR2`
-opționale (`DATAIREG`, `EXPLICATIA`, `DATASCAD`, `EXPLICATIA4/5`, `ID_SUCURSALA`, `ID_ACT`, `ID_CTR`,
-`ID_JTVA_COLOANA`, `SERIE_ACT`, `ID_UTILV`, `DATAORAV`, `TAXCODE`, `PAYMENTCODE`).
-
-Constrangeri: **29 `CHECK` constraints** (`SYS_C0014966`...`SYS_C0014994`) — corespund exact
-coloanelor `NOT NULL` de mai sus (Oracle genereaza `CHECK (coloana IS NOT NULL)` pentru `NOT NULL`
-declarat fara nume). **Niciun constraint pe `SCD`/`SCC`** (nici `NOT NULL`, nici `CHECK` de format,
-nici FK catre un plan de conturi). **Nicio cheie primara/unica** — normal pentru un tabel `_TEMP` de
-staging. Concluzie: schema **nu blocheaza in niciun fel** o valoare `SCC` calculata de VFP, oricare
-ar fi ea, inclusiv `NULL`.
-
----
-
-## Ce nu s-a putut stabilit si de ce
-
-- **Punctul exact unde `ACTACTAN` primeste `SCD`/`SCC` in fluxul `oscrie_vanzare_din_stoc`**
- (`ofacturare_stoc.prg`, intrarea 6 de mai sus) — codul citit (`:104-450`) nu arata sursa; ar
- necesita urmarirea completa a apelantului (`initializeaza_vanzare_din_stoc`) si a modulului care
- populeaza `ACTACTAN` inainte de acest punct (posibil `pack_facturare.adauga_articol_factura_stoc`
- intoarce un ref cursor legat automat de `goExecutor` pe numele `actactan`, dar nu am gasit apelul
- explicit). Nu schimba verdictul (oricum ar fi tot `pack_facturare`, deci tot politica), dar ramane
- o zona neinchisa complet.
-- **Daca discountul pe linie (`SCD=667`/`SCC=4111`) are vreo cale alternativa in afara
- `cursor_articol`** — nu verificat aici, presupus dependent de politica la fel ca restul buclei.
-- **Comportamentul practic al `frm_modific2024` cu privire la validarea contului tastat manual**
- (daca exista vreo verificare `verific_cont`/plan de conturi la salvare, sau accepta orice text de
- 4 caractere) — nu urmarit pana la capat in `omodificari.vc2`; relevant doar daca se propune
- reutilizarea canalului 3(b)/3(a) pentru scriere programatica (fara interactiune UI), caz in care ar
- trebui verificat daca `frm_modific2024` insusi impune vreo validare care ar bloca o scriere
- automata.
-- **Daca fluxul de emitere (`scrie_factura2`) ar putea, teoretic, sa scrie intai o factura "goala" de
- nota (sau cu o nota tehnica minimala) si apoi sa foloseasca imediat, in aceeasi tranzactie logica,
- mecanismul de la pista 3(b) pentru a corecta `SCC`-ul** — nu explorat aici (ar fi o propunere de
- design, in afara scopului acestei cercetari read-only); mentionat doar ca directie posibila care
- reiese direct din ce s-a gasit.
-- Nu am cautat/citit `pack_contafin.SCRIE_IN_ACT`/`STERGE_DIN_ACT` in `PACK_CONTAFIN.pck` pentru a
- confirma ca acestea, la randul lor, nu re-deriva `SCC` din altceva — presupunerea (bazata pe
- `oracle_export.md` si pe `flux-modificare-stergere-nota-jurnal.md`, care descriu deja aceste
- proceduri drept "distribuie ce a scris clientul", nu "recalculeaza") e ca fac un simplu
- `INSERT INTO ACT SELECT * FROM ACT_TEMP`-tip transfer, nu o derivare noua — dar nu am deschis
- personal codul lor in aceasta runda.
diff --git a/docs/cercetare/cont_venit_corespondente.md b/docs/cercetare/cont_venit_corespondente.md
deleted file mode 100644
index 0b3e7ec..0000000
--- a/docs/cercetare/cont_venit_corespondente.md
+++ /dev/null
@@ -1,240 +0,0 @@
-# Corespondenta cont de stoc (3xx) -> cont de venit (7xx): ce exista in cod
-
-**Context**: continuare a `cont_venit_articol_fara_politica.md`, care stabilise ca `VANZARI_DETALII.CONT`
-e un cont de **gestiune/stoc** (371, 301-303, 357), fara sa gaseasca un cont de venit pe linia de
-factura in `pack_facturare`, si lasase neverificat unde se genereaza efectiv contul de venit.
-Cercetarea de fata raspunde la cele 4 intrebari, cu corectii fata de raportul anterior.
-
-## Raspuns scurt
-
-1. **Nu exista un tabel de corespondenta "3xx -> 7xx"** (nume de forma `CORESPONDENTA*`,
- `NOM_CONTURI*`, `CONT_VENIT*`, `ARTICOLE_CONTABILE*`) nicaieri in `SCRIPTURI_CLAR`. In schimb
- exista un **mecanism echivalent functional, dar configurat manual, nu derivat automat din contul
- de stoc**: tabelul `NOTE_CONTABILE` (coloane `SCD`/`ASCD` = cont+analitic debitor,
- `SCC`/`ASCC` = cont+analitic creditor), legat de politica de pret a articolului prin
- `CRM_POLITICI_PRETURI.ID_NOTA -> CRM_NOTE_VANZARI.ID_SET -> NOTE_CONTABILE`. Un contabil
- configureaza acest tabel dintr-un ecran dedicat (`frm_config_note_contabile[2007]`), nu se
- calculeaza din `NOM_ARTICOLE.CONT`/`STOC.CONT`.
-2. **`NOM_ARTICOLE.CONT` NU e restrans la conturi de stoc (clasa 3).** Validarea la editare
- (`verific_cont`) verifica doar ca respectivul cod exista in planul de conturi al anului curent
- (`vplcont_sintetic`), fara filtru pe clasa. UI-ul trimite explicit catre "Planul de conturi"
- (buton de help general), nu catre un subset de conturi de stoc. Asta confirma afirmatia lui
- Marius: campul accepta orice cont, inclusiv 6xx/7xx.
-3. **Nota contabila a vanzarii SE genereaza in `pack_facturare`** — raportul anterior a cautat
- literalii `707`/`704`/`706`/`708` (care nu apar hardcodati nicaieri, corect) si a conchis gresit
- ca lipseste mecanismul. El exista, dar e **indirect**: `pack_facturare.contabilizeaza_articol`
- (`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:7182-7556`) ia `SCD`/`SCC` din `NOTE_CONTABILE` (via
- politica de pret a articolului) si scrie nota cu `pack_facturare.scrie_nota(...)`. `SCC` (contul
- creditor) e contul de venit efectiv al liniei — nu vine din `VANZARI_DETALII.CONT` (care ramane
- contul de gestiune, folosit separat, doar pentru descarcarea de gestiune, in
- `descarca_gestiune`).
-4. **`ID_VENCHELT`/`NOM_VENIT_CHELTUIELI` nu are coloana de cont** (nicio `ALTER TABLE
- NOM_VENIT_CHELTUIELI ADD ... CONT` in `SCRIPTURI_CLAR`). E o dimensiune analitica separata
- (clasificare venituri/cheltuieli, posibil pentru raportare/buget), transmisa ca parametru propriu
- catre `scrie_nota`, in paralel cu `SCD`/`SCC` — nu e sursa contului.
-
-## 1. Nu exista tabel de corespondenta 3xx->7xx; exista `NOTE_CONTABILE` + politica de pret
-
-### Cautare tabel dedicat — negativa
-Cautari in `D:\ROA\DATABASE\SCRIPTURI_CLAR` (`CREATE TABLE`/`ALTER TABLE`, case-insensitive) pentru
-`CORESPONDENT*`, `NOM_CONTURI*`, `CONT_VENIT*`, `PLAN_CONTURI*`, `ARTICOLE_CONTABILE*`: niciun
-rezultat relevant — singurele hituri pe `CORESPONDENT` sunt cuvantul romanesc generic ("banca
-corespondenta" etc.) in sute de fisiere fara legatura, iar `CONT_VENIT` nu apare deloc ca nume de
-tabel/coloana.
-
-### Mecanismul real: lant de 4 tabele, configurat pe politica de pret
-`pack_facturare.contabilizeaza_articol` (`ff_...:7227-7280`) foloseste acest cursor pentru a afla
-contul debitor/creditor al liniei de vanzare:
-
-```sql
-CURSOR cursor_articol IS
- SELECT A.ID_POL_ART, A.ID_POL, A.ID_ARTICOL, A.PRET, ...
- NVL(pack_facturare.nid_venchelt, NVL(A.ID_VENCHELT, C.ID_VENCHELT)) AS ID_VENCHELT,
- NVL(pack_facturare.nid_sectie_stoc, C.ID_SECTIE) as ID_SECTIE,
- C.ID_SET, D.EXPLICATIE, D.SCD, D.ASCD, D.SCC, D.ASCC, D.CU_TVA, ...
- FROM CRM_POLITICI_PRET_ART A
- LEFT JOIN CRM_POLITICI_PRETURI B ON A.ID_POL = B.ID_POL
- LEFT JOIN CRM_NOTE_VANZARI C ON B.ID_NOTA = C.ID_NOTA
- LEFT JOIN NOTE_CONTABILE D ON C.ID_SET = D.ID_SET
- WHERE A.ID_POL = detalii_articol.id_pol AND A.ID_ARTICOL = detalii_articol.id_articol;
-```
-(`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:7227-7280`)
-
-Lantul e: **articol + politica de pret** (`CRM_POLITICI_PRET_ART`, deja documentat in raportul
-anterior ca avand `PRET`/`PROC_TVAV`/`ID_VALUTA`, fara `CONT`) `->` **antetul politicii de pret**
-(`CRM_POLITICI_PRETURI.ID_POL`, care are `ID_NOTA`) `->` **nota de vanzare CRM**
-(`CRM_NOTE_VANZARI.ID_NOTA`, care are `ID_SET`) `->` **sablonul de nota contabila**
-(`NOTE_CONTABILE.ID_SET`, care are `SCD`/`ASCD`/`SCC`/`ASCC`/`EXPLICATIE`/`CU_TVA`/`IN_VALUTA`).
-
-Apoi, la scriere (`ff_...:7405-7437`):
-```sql
-CASE
- WHEN pack_facturare.ntip <= 20 or pack_facturare.ntip IN (...) THEN
- -- factura, factura roahotel
- V_SCD := crs_rand_articol.scd;
- V_ASCD := NVL(crs_rand_articol.ascd, PACK_FACTURARE.GetAnaliticByGrupUtilizatori(...));
- WHEN pack_facturare.ntip in (28, 29) THEN
- -- aviz catre clienti debitori
- V_SCD := '461'; ...
- ELSE
- -- aviz
- V_SCD := '418'; ...
-END CASE;
-
-V_SCC := crs_rand_articol.scc;
-V_ASCC := NVL(crs_rand_articol.ascc, PACK_FACTURARE.GetAnaliticByGrupUtilizatori(...));
-```
-(`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:7407-7437`)
-
-Pentru o factura normala (`ntip <= 20`), `V_SCD` e contul debitor din nota (tipic un cont de
-creante, 411/etc.), iar `V_SCC` e contul creditor din nota — **acesta e efectiv contul de venit**
-al liniei (707/704/706/708, in functie de cum a configurat contabilul nota respectiva), preluat
-**direct din `NOTE_CONTABILE.SCC`**, fara nicio derivare din contul de stoc al articolului. Perechea
-`V_SCD`/`V_SCC` (plus `ID_VENCHELT`, `ID_SECTIE`, `EXPLICATIE`, cota TVA) e trimisa la
-`pack_facturare.scrie_nota(...)` (`ff_...:7452-7476`), care scrie randul in nota contabila
-efectiva a vanzarii.
-
-**Concluzie fata de ipoteza lui Marius**: mecanismul exista si rezolva exact problema — "de unde
-stiu contul de venit al unei linii de vanzare, indiferent daca articolul e gestionabil sau nu" —
-dar **nu e o corespondenta automata cont-stoc -> cont-venit**. E o **configurare manuala per
-politica de pret**: fiecare politica de pret (`CRM_POLITICI_PRETURI`) e legata la o "nota de
-vanzare" CRM (`CRM_NOTE_VANZARI`), care la randul ei e legata la un sablon de nota contabila
-(`NOTE_CONTABILE`) cu perechea SCD/SCC fixata de un contabil. Politica de pret aplicata articolului
-decide, indirect, contul de venit — nu clasa/valoarea contului de gestiune al articolului.
-
-### Ecranul de configurare (unde se seteaza SCD/SCC)
-`D:\ROA\ROAFACTURARE\COMUN\ferestre\frm_config_note_contabile.sc2` (+ varianta
-`frm_config_note_contabile2007.sc2` pentru anii >= 2007, selectata in
-`COMUN\programe\omeniu_initializari.prg:257-282`) e formularul din meniu "Configurare note
-contabile". Clasa e `onote_contabile.vc2`, cu un grid `gridInregistrari` avand coloanele
-`cScd`/`cAscd`/`cScc`/`cAscc` (`onote_contabile.vc2:2401-2435`) legate direct de
-`cnote_contab.scd`/`.scc`/`.ascd`/`.ascc`, si salvare prin INSERT/UPDATE direct pe
-`note_contabile(explicatie,scd,ascd,scc,ascc,ordine,cu_tva,ptva,id_set,in_valuta,...)`
-(`onote_contabile.vc2:315-322`, `:486-493`). Deci **contabilul e cel care scrie manual perechea
-SCD/SCC** (inclusiv contul de venit `SCC`) pentru fiecare `id_set`/nota, nu exista automatism care
-sa deriveze `SCC` din contul de gestiune al articolului.
-
-## 2. `NOM_ARTICOLE.CONT` — nu e restrans la clasa 3
-
-- **Camp**: `Clb_tx_cont.Text_simplu1.ControlSource = "porec.cont"`, `MaxLength = 4`, eticheta
- `"Cont*"` (obligatoriu), buton de help cu tooltip `"Help - Planul de conturi (CTRL+ H)"` —
- `COMUN\clase\onom_articole.vc2:1058-1087`. Trimiterea catre "Planul de conturi" (nu catre un
- subset "conturi de stoc") sugereaza ca formularul asteapta orice cont valid, nu doar clasa 3.
-- **Validare la Valid() al campului** (in alt formular generic de conturi, `onomenclatoare.vc2`, nu
- in cel de articole, dar foloseste aceeasi functie globala):
- ```
- PROCEDURE clb_cont.Text_simplu1.Valid
- IF !EMPTY(this.Value)
- lnVerificat = verific_cont(thisform.orec.cont)
- IF lnVerificat < 0
- RETURN 0
- ENDIF
- ENDIF
- ENDPROC
- ```
- (`COMUN\clase\onomenclatoare.vc2:3251-3258`)
-- **`verific_cont`** (`COMUN\programe\oproceduri_comune.prg:2389-2415`):
- ```
- Procedure verific_cont
- Parameters tcCont, tlNoMessage
- lcSel = [SELECT cont from ] + GCS + [.vplcont_sintetic WHERE TRIM(cont) = ?pcCont and an = ?gnAn ]
- ...
- If Reccount('crs_verific') = 0
- lnSucces = -1
- Endif
- If lnSucces < 0 And !tlNoMessage
- amessagebox('Acest cont nu este definit in planul de conturi!', 0 + 48, 'Atentie')
- Endif
- Endproc
- ```
- Singura conditie e ca `cont` sa existe in `vplcont_sintetic` (planul de conturi sintetic al
- anului curent, `gnAn`) — **fara `LIKE '3%'`, fara `SUBSTR(cont,1,1) = '3'`, fara nicio alta
- restrictie de clasa**. O varianta identica exista si in
- `COMUN\programe\ooperatii_comune.prg:1307` (nu am comparat corp cu corp, dar semnatura e aceeasi).
-- Nu exista `CHECK CONSTRAINT` pe `NOM_ARTICOLE.CONT` in `SCRIPTURI_CLAR` (cautare
- `CHECK.*CONT`/`constraint.*CONT.*check` — zero rezultate relevante), deci nici la nivel de
- baza de date nu exista o restrictie de clasa.
-- Nu am gasit nicaieri in `COMUN` sau `ROAFACTURARE` o ramificare pe `Left(cont,1)`/
- `SUBSTR(cont,1,1)` aplicata specific campului `NOM_ARTICOLE.CONT` (cautare in
- `D:\ROA\ROAFACTURARE` si `D:\ROA\ROAFACTURARE\COMUN`) — singurul loc cu `SUBSTR(cont,1,1)` gasit e
- in `onomenclatoare.vc2:3647`, un filtru de grid pe planul de conturi general (tab-uri "1", "2",
- "3"... pentru navigare in plan), fara legatura cu articolele.
-
-**Concluzie**: campul e validat generic (orice cont din planul de conturi al anului), fara
-restrictie de clasa la nivel de UI sau DB. Asta confirma ce a spus Marius: un articol negestionabil
-poate avea legitim un cont 6xx/7xx in `NOM_ARTICOLE.CONT`.
-
-## 3. Unde se genereaza efectiv nota contabila a vanzarii
-
-Raportul anterior cauta gresit literalii `707`/`704`/`706`/`708` (niciunul nu apare hardcodat — corect)
-si a conchis ca nu exista mecanism in `pack_facturare`. De fapt **exista, dar e in `pack_facturare`,
-nu intr-un pachet separat de contabilitate**:
-
-- **Functia**: `pack_facturare.contabilizeaza_articol(detalii_articol VANZARI_DETALII_TEMP%ROWTYPE)`
- (`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:7182-7556`), apelata pe fiecare rand din
- `VANZARI_DETALII_TEMP` — vezi apelul `V_INCASAT_CALCUL := V_INCASAT_CALCUL +
- pack_facturare.contabilizeaza_articol(tab_detalii(i));` in `scrie_aviz_retur`
- (`ff_...:7148-7150`); acelasi tipar se repeta si in fluxul principal de facturare (nu doar in
- aviz-retur — semnatura si structura functiei arata ca acopera si `ntip <= 20`, adica factura
- propriu-zisa, prin `CASE ... WHEN pack_facturare.ntip <= 20 ...` la `ff_...:7409-7421`).
-- **Sursa `SCD`/`SCC`**: vezi sectiunea 1 — cursorul `cursor_articol` (`ff_...:7227-7280`), pe baza
- politicii de pret a articolului (`detalii_articol.id_pol`), nu pe `VANZARI_DETALII.CONT`.
-- **`VANZARI_DETALII.CONT` ramane folosit separat, doar pentru gestiune**: in aceeasi functie,
- `descarca_gestiune(...)` primeste explicit `detalii_articol.cont` ca parametru
- (`ff_...:7485-7507`, apelat cand `nscadere_stoc = 1 AND id_gestiune <> -1000 AND in_stoc = 1`) —
- acesta e contul de gestiune/stoc (371/301-303/357 etc., documentat in raportul anterior),
- folosit pentru randul de descarcare de gestiune (marfa iesita din stoc), complet independent de
- `V_SCD`/`V_SCC` calculate mai sus pentru randul de venit al vanzarii. **Cele doua conturi
- coexista pe aceeasi linie de vanzare, cu surse complet diferite**: unul (gestiune) vine din
- `NOM_ARTICOLE.CONT`/`STOC.CONT`/`NOM_GESTIUNI.CONT` (cf. raport anterior), celalalt (venit) vine
- din `NOTE_CONTABILE.SCC` via politica de pret.
-- **Nu exista fallback/hardcodare** pentru `SCC`: daca `NOTE_CONTABILE` nu are un rand pentru
- `ID_SET`-ul politicii, `LEFT JOIN`-urile din `cursor_articol` produc `NULL` pe `SCC`/`SCD`
- (fara eroare explicita in acest cursor — spre deosebire de cazul `V_COMPUS`/politica lipsa la
- `ff_...:7293-7311`, care ridica `FACT-024`).
-
-## 4. `ID_VENCHELT` / `NOM_VENIT_CHELTUIELI`
-
-- **Nu are coloana de cont**: nicio `ALTER TABLE NOM_VENIT_CHELTUIELI ADD ... CONT` in
- `SCRIPTURI_CLAR` (cautare directa, zero rezultate) si nicio `CREATE TABLE NOM_VENIT_CHELTUIELI`
- in arhiva (tabelul predateaza 2009, inceputul arhivei `SCRIPTURI_CLAR` — la fel ca
- `NOTE_CONTABILE`, `CRM_NOTE_VANZARI`, `CRM_POLITICI_PRETURI`, pentru care nu exista `CREATE TABLE`
- in arhiva din acelasi motiv).
-- **Structura vazuta din uz**: `NOM_VENIT_CHELTUIELI.ID_VENCHELT%TYPE` (tip declarat repetat in
- `pack_facturare`, ex. `ff_...:191`) si `ACT.ID_VENCHELT%TYPE` (`ff_...:6725`) — deci
- `ID_VENCHELT` e o coloana FK pe `ACT` (tabelul de note contabile efective) si pe `CRM_NOTE_VANZARI`
- / `CRM_POLITICI_PRET_ART` (vezi `NVL(B.ID_VENCHELT, D.ID_VENCHELT)` la `ff_...:7205`, unde `B` =
- `CRM_POLITICI_PRET_ART`, `D` = `CRM_NOTE_VANZARI` in cursorul comentat din pachet).
-- **Cine il consuma**: `pack_facturare.contabilizeaza_articol` il rezolva cu prioritate similara
- contului: `NVL(pack_facturare.nid_venchelt, NVL(A.ID_VENCHELT, C.ID_VENCHELT))` (override global de
- sesiune -> articol/politica -> nota de vanzare) si il trimite ca parametru propriu catre
- `scrie_nota(...)` (`ff_...:7461`), **separat** de `SCD`/`SCC`. E deci o **a treia dimensiune**
- (clasificare venituri/cheltuieli) atasata randului de nota contabila, nu sursa contului insusi —
- raportul anterior avea dreptate sa il caracterizeze ca "o clasificare, nu un cont", desi nu
- urmarise consumatorul pana la capat.
-- Numele `NOM_VENIT_CHELTUIELI` si folosirea alaturi de `SCD`/`SCC`/`ID_SECTIE` sugereaza un
- centru de venituri/cheltuieli pentru raportare (posibil situatii financiare pe sectii/centre de
- cost), nu un mecanism alternativ de determinare a contului 7xx.
-
-## Neverificat
-
-- **Structura completa (toate coloanele) a `NOTE_CONTABILE`, `CRM_NOTE_VANZARI`,
- `CRM_POLITICI_PRETURI` si `NOM_VENIT_CHELTUIELI`**: niciuna nu are `CREATE TABLE` in
- `SCRIPTURI_CLAR` (arhiva incepe 2009, tabelele sunt mai vechi). Coloanele folosite in cod sunt
- confirmate (`SCD`/`ASCD`/`SCC`/`ASCC`/`EXPLICATIE`/`CU_TVA`/`IN_VALUTA`/`ID_SET` pe
- `NOTE_CONTABILE`; `ID_NOTA`/`ID_SET` pe `CRM_NOTE_VANZARI`; `ID_NOTA`/`ID_POL` pe
- `CRM_POLITICI_PRETURI`; `ID_VENCHELT` pe `NOM_VENIT_CHELTUIELI`), dar lista completa ar necesita
- interogarea schemei Oracle live (`DESC NOTE_CONTABILE` etc.) sau un export DDL mai vechi decat
- 2009, in afara bugetului acestei cercetari.
-- **Continutul efectiv al `NOTE_CONTABILE.SCC`** pentru notele configurate curent (adica ce conturi
- 707/704/706/708 sunt de fapt setate, si daca fiecare politica de pret are o nota configurata) —
- ar necesita interogarea datelor din schema Oracle live, nu doar codul static.
-- **Daca `contabilizeaza_articol` e chiar apelata pe fluxul principal de facturare** (nu doar din
- `scrie_aviz_retur`) — am dedus asta din `CASE ... ntip <= 20 ...` (factura normala tratata explicit
- in functie), dar nu am urmarit *toti* apelantii ei in fisier (fisierul are 17000+ linii; cautarea
- `pack_facturare.contabilizeaza_articol` ar trebui repetata exhaustiv daca se doreste certitudine
- completa pe toate punctele de intrare — facturare avans, deviz, retail etc.).
-- **Comportamentul cand `NOTE_CONTABILE`/`CRM_NOTE_VANZARI` lipsesc pentru o politica de pret**:
- cursorul foloseste `LEFT JOIN`, deci `SCD`/`SCC` ar ajunge `NULL` fara eroare explicita in acest
- punct — nu am verificat daca exista o validare ulterioara (la `scrie_nota` sau la commit-ul notei)
- care sa blocheze o nota cu cont `NULL`.
diff --git a/docs/cercetare/coresp_cont_venchelt.md b/docs/cercetare/coresp_cont_venchelt.md
deleted file mode 100644
index 4eb7702..0000000
--- a/docs/cercetare/coresp_cont_venchelt.md
+++ /dev/null
@@ -1,800 +0,0 @@
-# CORESP_CONT_VENCHELT ca sursa de cont de venit pentru articole fara politica de pret (decizia 27)
-
-Cercetare pe cod, read-only, fara modificari. Continua `cont_venit_articol_fara_politica.md` si
-`cont_venit_corespondente.md` (care stabilisera ca SCC vine azi din `NOTE_CONTABILE` prin lantul
-politicii de pret) si `nota_contabila_fara_politica.md` (care stabilise ca `contabilizeaza_articol`
-ridica FACT-024 si opreste tranzactia cand nu exista politica).
-
-## 9. Intrebarea care putea rasturna tot: "in ROAACNPRO si pe factura din comanda/contract se adauga articole fara politica de preturi — de ce nu si aici?"
-
-**Raspuns scurt, verificat pe cod: impresia e explicabila, dar niciunul din cele doua exemple nu e de
-fapt un articol fara politica trecut cu bine prin `contabilizeaza_articol`. FACT-024 ramane blocantul
-real — nu exista azi, in productie, niciun flux in care un articol ajunge la `contabilizeaza_articol`
-fara sa fie membru al unei politici si sa treaca fara eroare.**
-
-### 9a) Ce verifica de fapt FACT-024 — apartenenta articolului la politica liniei, nu "id_pol e gol"
-
-Blocul (`D:\ROA\ROAFACTURARE\docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:7278-7302`, citat integral
-la sectiunea 6) face:
-```sql
-SELECT COMPUS, ID_POL_ART
- INTO V_COMPUS, V_ID_POL_ART
- FROM VCRM_POLITICI_PRET_ART
- WHERE ID_ARTICOL = detalii_articol.id_articol
- AND ID_POL = detalii_articol.id_pol;
-```
-Mesajul confirma exact asta: `'Articolul ' || ... || ' nu este definit in politica de preturi ' || ...`
-— verifica **apartenenta articolului la politica `id_pol` care a ajuns pe linie**, nu doar "exista vreun
-`id_pol`". Insa `id_pol` **nu e derivat de Oracle** din client/contract/tip document — e parametru de
-intrare explicit (`V_ID_POL IN NUMBER`, `adauga_articol_factura`, `ff_...:4993`, citat integral la
-sectiunea 8a), trimis de VFP pe fiecare linie. Deci sunt **doua cauze distincte care duc la aceeasi
-eroare**:
-1. `id_pol` e NULL/gol pe linie (articolul a fost ales dintr-o cautare care nu are deloc coloana
- `id_pol` — cazul `caut_articol`, sectiunea 9d) — `NO_DATA_FOUND` trivial (`X = NULL` nu se potriveste
- niciodata).
-2. `id_pol` e o valoare reala, dar articolul **nu e** in lista acelei politici — la fel `NO_DATA_FOUND`,
- cu acelasi mesaj.
-Ambele cauze converg spre FACT-024; codul nu le distinge in eroare. Formularea din intrebarea lui
-Marius ("nu se cauta politica articolului, ci apartenenta articolului la politica documentului") e
-**partial corecta**: verificarea e de apartenenta, dar `id_pol` nu vine din "antetul documentului" ca
-o singura valoare fixa — vine per-linie, de la formularul de adaugare a articolului (sectiunea 9d).
-
-### 9b) ROAACNPRO — importul Roris/Contracte NU trece deloc prin `contabilizeaza_articol`
-
-Verificat direct in `D:\ROA\ROAACNPRO\Programe\proceduri_acnpro.prg` (read-only). Cautare
-`pack_facturare\.|pack_acn\.|pack_contafin\.` in tot fisierul — apelurile de la salvarea facturii
-(`factura_salvare_db`, `:3331-3467`) sunt:
-```
-proceduri_acnpro.prg:3332 lcSql = [begin pack_facturare.initializeaza_scriere_actrul(NULL,1); end;]
-proceduri_acnpro.prg:3343 lcSql = [begin pack_facturare.initializeaza_date_factura(...
-proceduri_acnpro.prg:3382 lcSql = [begin pack_facturare.adauga_articol_factura_deviz(...
-proceduri_acnpro.prg:3412 lcSql = [begin pack_facturare.scrie_in_vanzari(0,...
-proceduri_acnpro.prg:3430 lcSql = [begin pack_acn.salveaza_regdoc(?.id, ?.id_vanzare, ?.tip, ...
-```
-**Exact tiparul deja documentat pentru ROAAUTO "Alte servicii" in `nota_contabila_fara_politica.md`**:
-`adauga_articol_factura_deviz` (insereaza doar in `VANZARI_DETALII_TEMP`, fara `ID_POL` — semnatura
-n-are acest parametru) urmat de `scrie_in_vanzari` (copiaza in `VANZARI_DETALII`, **fara sa scrie vreo
-nota contabila de venit**) — **`contabilizeaza_articol` nu apare deloc** in acest fisier (cautare
-directa `contabilizeaza_articol` in `proceduri_acnpro.prg`: zero rezultate). Nota contabila a
-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 `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`.
-
-**Concluzie 9b**: ROAACNPRO nu e un exemplu de "articol fara politica trecut cu bine prin
-`contabilizeaza_articol`" — e un produs care **nu foloseste deloc** acest mecanism de contabilizare
-pentru facturile lui. Impresia lui Marius e intemeiata pe experienta ("acolo merge fara sa aleg vreo
-politica"), dar explicatia e alta decat "FACT-024 se poate evita" — e ca **acel flux nu ruleaza deloc
-codul care ar putea da FACT-024**.
-
-### 9c) Factura din comanda/contract in ROAFACTURARE — articolul "liber" e de fapt din lista de preturi
-
-Deja cercetat, cu dovezi, in `docs\cercetare\retur_si_lista_preturi.md` sectiunea B (citit integral aici,
-nu doar rezumat). Punctul central (`retur_si_lista_preturi.md` sectiunea B7):
-- **Contract** (tip 2,6,26,52): `crsarticole` (grila principala de articole, folosita si pentru
- adaugare "libera") e populat de `pack_facturare.cursor_contract(...)`, care da **lista de preturi
- completa**, nerestrictionata la continutul contractului — "azi se poate deja adauga liber din lista de
- preturi pe un document contract".
-- **Comanda** (tip 3): `crsarticole` e populat de `cursor_comanda`, **doar** articolele comenzii — nu
- exista adaugare libera in fluxul normal (doar prin copiere de document, care re-adauga tot din
- `cursor_preturi`).
-
-Verificat aici, suplimentar, ca `cursor_preturi` (folosit si de `cursor_contract`, structura identica)
-**selecteaza explicit `A.ID_POL`** ca coloana de output:
-```sql
--- ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:2162-2167 (cursor_preturi, ramura V_TIP = 45, tipic pentru toate ramurile CASE)
-OPEN V_CURSOR FOR
- SELECT rownum as id_c,
- B.ID_ARTICOL,
- NULL AS LOT,
- NULL as SERIE,
- A.ID_POL,
- ...
-```
-si ca cursorul insusi porneste, la fiecare apel, prin `pack_facturare.completare_politica_stoc()`
-(`ff_...:2151`), care garanteaza deja randuri in `CRM_POLITICI_PRET_ART` pentru toate articolele
-`IN_STOC=1` (procedura citata integral la sectiunea 8c2). Deci **fiecare articol afisat in grila
-"lista de preturi"/"contract" vine deja cu un `id_pol` valid, dintr-o politica reala**, exact pentru ca
-e extras printr-un join pe `CRM_POLITICI_PRETURI`/`CRM_POLITICI_PRET_ART`. "Adaugare libera pe contract"
-nu inseamna "articol fara politica" — inseamna "orice articol din lista de preturi, nu doar cele din
-contract", dar tot cu politica ceruta, doar aleasa implicit prin cursor, nu prin dialogul manual
-`do_cauta_politica`.
-
-**Concluzie 9c**: nu e un contraexemplu la FACT-024 — e acelasi mecanism (articol + politica), livrat
-printr-o alta grila de selectie (`crsarticole` populat de `cursor_contract` in loc de `caut_articol`),
-care intampla sa nu ceara utilizatorului sa caute manual politica pentru ca cursorul o aduce deja
-atasata pe fiecare rand.
-
-### 9d) Ce diferentiaza de fapt "adaugare din nomenclator" (cazul #13) de "adaugare din lista de preturi/contract" (cazul care merge azi)
-
-Diferenta e cursorul sursa al gridului de articole, nu tipul de document:
-- **`caut_articol`** (`COMUN\programe\ocautare.prg:1636-1735`, folosit pentru cautare libera in
- nomenclator) — SELECT-ul confirmat la `ocautare.prg:1671-1689` (`vnom_articole_crm`/`vnom_articole`):
- **nu are coloana `id_pol`** in nicio ramura (`tlCRM` sau nu). Un articol ales prin acest dialog ajunge
- in `poArticol` (scatter din `crsarticole`, `ofacturare.vc2:12850-12851`) **fara `id_pol`** — exact
- cazul care da FACT-024 azi, si exact cazul cerut de povestea #13 ("adaugat direct din nomenclator").
-- **`cursor_preturi`/`cursor_contract`** (Oracle, sectiunea 9c) — id_pol e parte din rezultat, pentru ca
- interogarea porneste de la politica de pret, nu de la nomenclator.
-
-Deci povestea #13 cere exact ce nu exista azi: un articol ales **prin cautarea de nomenclator**
-(fara trecere prin vreo politica), caruia i se cere totusi sa treaca prin `contabilizeaza_articol` fara
-eroare. Niciunul din exemplele lui Marius (ROAACNPRO, contract) nu demonstreaza ca asta functioneaza deja
-undeva — primul nu foloseste deloc functia, al doilea nu e de fapt "fara politica".
-
-### Verdict 9
-
-**FACT-024 ramane blocantul real**, confirmand (nu contrazicand) analiza din sectiunile 6-8. Nu exista
-azi, pe niciun flux de productie cercetat, un caz in care un articol trece prin
-`pack_facturare.contabilizeaza_articol` fara sa fie membru al unei politici de pret si nu cade cu
-eroare. Impresia lui Marius e intemeiata pe doua experiente reale, dar explicatia lor e alta:
-- ROAACNPRO: alt produs, alta procedura de contabilizare (`pack_acn.salveaza_regdoc`), niciodata
- `contabilizeaza_articol`;
-- Contract in ROAFACTURARE: articolul PARE liber, dar e adus printr-un cursor care il livreaza deja cu
- o politica reala atasata (`cursor_contract`/`cursor_preturi` + `completare_politica_stoc`).
-
-Asta nu inseamna ca planul A (sectiunea 8, VFP alege singur un `id_pol`) sau planul B (sectiunea 6,
-fallback in pachet) sunt de abandonat — arata insa ca **niciuna din cele doua nu se poate simplifica
-la "nu faceti nimic, functioneaza deja"**: mecanismul de protectie e real si consecvent, nu un artefact
-uitat.
-
-## Constrangere noua (Marius, aparuta in timpul cercetarii): pack_facturare e plan B
-
-Marius prefera sa **nu se scrie cod nou in `pack_facturare`** — e pachetul comun folosit de toata
-suita, si orice ramura noua acolo e risc peste tot, nu doar in ROAFACTURARE. Sectiunea 6 (punctul de
-injectie in pachet) ramane in raport ca informatie, dar devine **plan B**. Intrebarea reala, tratata in
-sectiunea 8 de mai jos: **se poate obtine acelasi rezultat din VFP, alegand singur un `id_pol` potrivit,
-fara sa se modifice `pack_facturare`?** Raspuns scurt: **da, ingredientele exista deja**, dar solutia nu
-e "zero cod" — e cod VFP nou (nu Oracle), care se sprijina pe 3 mecanisme deja functionale in productie.
-Detalii in sectiunea 8.
-
-## Concluzie: fezabil cu conditii, si conditiile sunt mai mari decat pare din formularea deciziei 27
-
-0. **Verificare prioritara (sectiunea 9, ceruta de Marius in timpul cercetarii): FACT-024 ramane
- blocantul real.** Nu exista azi niciun flux de productie in care un articol trece prin
- `contabilizeaza_articol` fara sa fie membru al unei politici de pret si nu cade cu eroare.
- ROAACNPRO nu e un contraexemplu — nu foloseste deloc `contabilizeaza_articol` (alta procedura de
- contabilizare, `pack_acn.salveaza_regdoc`). Contractul in ROAFACTURARE nu e un contraexemplu —
- articolele "libere" vin din `cursor_contract`/`cursor_preturi`, care le ataseaza deja o politica
- reala. Detalii complete in sectiunea 9.
-1. **Tabelul exista, e populat cu date reale si e folosit activ in productie** — dar niciodata pentru
- `CONT_VENIT`. Toti consumatorii gasiti (pack_vin, pack_devize, gestiune_pack_gest_import,
- gestiune_rapoarte) citesc `CONT_CHELT` (sau `CONT_APROVIZIONARE`), niciunul `CONT_VENIT`. Coloana
- `CONT_VENIT` e completata cu date reale (o migrare din 2023 acopera 20 de conturi de gestiune), dar
- n-are niciun consumator — nici Oracle, nici VFP. Cititul ei pentru facturare ar fi un consumator nou,
- nu o reteta deja rulata in productie.
-2. **Cheia de join e stabila si testata**: mereu `CONT` (contul de gestiune al liniei), cu filtru
- `STERS = 0`, prin `LEFT JOIN`. Pattern-ul se poate copia identic pentru `CONT_VENIT`.
-3. **Punctul care schimba verdictul de la "fezabil simplu" la "fezabil cu conditii mari"**: in
- `contabilizeaza_articol`, ramura "articol simplu" nu executa **nimic** (nici `scrie_nota`, nici
- `descarca_gestiune`) daca `cursor_articol` (care citeste din `CRM_POLITICI_PRET_ART`) nu gaseste
- niciun rand — si nu gaseste niciun rand exact in cazurile in care azi se ridica FACT-024. Un simplu
- "prinde exceptia si continua" ar produce o linie facturata **fara nota contabila si fara descarcare
- de gestiune, fara nicio eroare** — mai rau decat blocajul actual. Fallback-ul cere o **ramura noua,
- paralela cursorului**, nu doar inlocuirea unei valori.
-4. **Chiar cu ramura noua, `CU_TVA` si `IN_VALUTA` (cota TVA inclusa in pret / linie in valuta) nu au
- nicio sursa alternativa** in afara `NOTE_CONTABILE`. Corespondentele si `NOM_ARTICOLE.CONT` dau doar
- un cont, nu aceste doua semnale de interpretare a pretului — ele trebuie fie hardcodate (risc de
- calcul gresit al bazei/TVA), fie cerute ca intrare noua de la utilizator/articol.
-5. **704 ca literal de fallback are un precedent real in suita**, dar in alt subsistem: proprietatea
- `cconte = 704` ("cont implicit articol client") din `frm_configurare_efactura`
- (`COMUN\clase\anaf_efactura.vc2:8376`), folosita la import eFactura, nu in `pack_facturare`. Nu e o
- reteta gata scrisa pentru facturare, dar arata ca alegerea lui Marius nu e arbitrara in suita.
-
-## 1. `CORESP_CONT_VENCHELT` exista? Structura, DDL, consumatori
-
-**Exista.** Nu are `CREATE TABLE` in arhiva `D:\ROA\DATABASE\SCRIPTURI_CLAR` (arhiva incepe 2009-2010,
-tabelul e mai vechi — acelasi motiv pentru care `NOTE_CONTABILE`/`CRM_NOTE_VANZARI` nu au `CREATE TABLE`
-in arhiva, documentat deja in `cont_venit_corespondente.md`).
-
-**Coloane confirmate din `ALTER TABLE` + `CREATE OR REPLACE VIEW` (cronologic):**
-- `CONT`, `CONT_CHELT`, `CONT_VENIT`, `STERS` — preexistente arhivei (folosite direct in view-ul din
- 2010 fara `ALTER TABLE` premergator vizibil).
-- `CONT_APROVIZIONARE varchar2(4)` — adaugata 19.02.2010
- (`D:\ROA\DATABASE\SCRIPTURI_CLAR\2010\02\ff_2010_02_19_03_GESTIUNI.sql:9`:
- `alter table CORESP_CONT_VENCHELT add CONT_APROVIZIONARE varchar2(4);`).
-- `CONT_DIFERENTE varchar2(4)` — adaugata 05.02.2015
- (`D:\ROA\DATABASE\SCRIPTURI_CLAR\2015\02\ff_2015_02_05_01_GESTIUNE.sql:6-7`:
- `alter table coresp_cont_venchelt add cont_diferente varchar2(4);` +
- `comment on column CORESP_CONT_VENCHELT.cont_diferente is 'cont diferente de pret pe NIR fata de
- pretul din factura de achizitie (ex: 6588 = 401 sau 308 = 401)';`).
-- Nu am gasit `ID_CCV`/`DATAORAS` in DDL-ul cercetat (cautare directa, zero rezultate in
- `SCRIPTURI_CLAR`) — interogarea din decizia 27 (`select id_ccv, cont, cont_chelt, cont_venit, sters,
- dataoras, cont_aprovizionare, cont_diferente from coresp_cont_venchelt`) le presupune, dar tabelul
- fiind pre-arhiva, DDL-ul complet nu e in cod static. **Ramane de verificat pe baza vie** (vezi sectiunea
- finala) — probabil `ID_CCV` e cheia surogat (PK) si `DATAORAS` un timestamp tehnic, tipar comun in
- suita ROA pentru tabelele de configurare, dar neconfirmat din DDL.
-- Toate coloanele `CONT*` sunt `varchar2(4)` (confirmat din `ALTER TABLE` explicit pentru
- `CONT_APROVIZIONARE`/`CONT_DIFERENTE`; consistent cu tratarea lor ca cod de cont in tot codul citit).
-
-**View-ul consumat de VFP**, `VCORESP_CONT_VENCHELT`, filtreaza deja `STERS = 0` (deci VFP nu mai trebuie
-sa filtreze separat):
-```sql
--- D:\ROA\DATABASE\SCRIPTURI_CLAR\2015\02\ff_2015_02_05_01_GESTIUNE.sql:10-13
-create or replace view vcoresp_cont_venchelt as
-select cont, cont_chelt, cont_venit, cont_aprovizionare, cont_diferente
- from coresp_cont_venchelt
- where sters = 0;
-```
-
-**Populare cu date reale — `CONT_VENIT` e completat, nu doar declarat.** Migrare dedicata 23.02.2023
-(`D:\ROA\DATABASE\SCRIPTURI_CLAR\2023\02\ff_2023_02_23_01_COMUN.sql:1-21`, titlul chiar din fisier:
-`-- Completare cont venit pe corespondenta 3xx - 6xx/7xx`):
-```sql
-update CORESP_CONT_VENCHELT set cont_venit = '707' where cont = '301';
-update CORESP_CONT_VENCHELT set cont_venit = '707' where cont = '302';
-update CORESP_CONT_VENCHELT set cont_venit = '707' where cont = '3021';
-... (3022,3023,3024,3025,3026,3028, 303 -> tot '707')
-update CORESP_CONT_VENCHELT set cont_venit = '711' where cont = '331';
-update CORESP_CONT_VENCHELT set cont_venit = '711' where cont = '332';
-update CORESP_CONT_VENCHELT set cont_venit = '702' where cont = '341';
-update CORESP_CONT_VENCHELT set cont_venit = '7015' where cont = '345';
-update CORESP_CONT_VENCHELT set cont_venit = '703' where cont = '346';
-update CORESP_CONT_VENCHELT set cont_venit = '7015' where cont = '348';
-update CORESP_CONT_VENCHELT set cont_venit = '7018' where cont = '361';
-update CORESP_CONT_VENCHELT set cont_venit = '707' where cont = '371';
-update CORESP_CONT_VENCHELT set cont_venit = '707' where cont = '381';
-```
-Deci pentru conturile de gestiune uzuale (marfuri 371/381, materii prime 301-303/3021-3028, produse
-finite 345/348, semifabricate 341, animale 346, ambalaje 381) exista deja o valoare `CONT_VENIT`
-configurata in Oracle, de 3 ani. **Datele exista** — intrebarea e doar cine le citeste.
-
-**Ecran de configurare in VFP: NU exista.** Cautare exhaustiva `CORESP_CONT_VENCHELT` (case-insensitive)
-in `D:\ROA\ROAFACTURARE\COMUN` -> exact 3 fisiere, niciunul un formular de editare:
-- `COMUN\clase\ointroduceri.vc2:2` — un comentariu de istoric (19.02.2010, mentioneaza
- `crsconfigcvc (coresp_cont_venchelt)`), nu cod.
-- `COMUN\programe\ointroduceri.prg:733` (procedura `update_corespondente_cvc`, citata integral mai jos)
- — un `SELECT` care **reincarca** un cursor local, nu scrie in tabel.
-- `COMUN\programe\updateserver.prg:733` — acelasi `SELECT`, alt loc de apel.
-
-```
--- COMUN\programe\ointroduceri.prg:727-743
-Procedure update_corespondente_cvc
- If Used('crsconfigcvc')
- Use In crsconfigcvc
- Endif
- *!* 19.02.2010
- lcSql = [select cont,cont_chelt,cont_venit, cont_aprovizionare, cont_diferente from vcoresp_cont_venchelt order by cont]
- *!* 19.02.2010 ^
- lnSucces = goExecutor.oExecute(lcSql,[crsconfigcvc])
- If lnSucces < 0
- amessagebox(goExecutor.cEroare,16,"Eroare")
- Endif
- goExecutor.oReset()
- Return lnSucces
-Endproc
-```
-
-Deci tabelul e intretinut exclusiv prin **scripturi SQL manuale** (cele din `SCRIPTURI_CLAR`, rulate de un
-DBA/dezvoltator la nevoie), nu printr-un formular VFP — la fel ca alte tabele tehnice de configurare mai
-vechi din suita. Nu exista niciun `INSERT INTO CORESP_CONT_VENCHELT` in arhiva (randurile de baza,
-`CONT`/`CONT_CHELT`/`CONT_VENIT`, predateaza arhiva); doar `UPDATE`/`ALTER TABLE` pentru coloanele
-adaugate ulterior (`CONT_APROVIZIONARE` in 2010, `CONT_DIFERENTE` in 2015, valorile `CONT_VENIT` in
-2023).
-
-## 2. Cheia de cautare
-
-**`CONT` = contul de gestiune al liniei, mereu.** Confirmat prin 4 exemple reale de `JOIN`, in module
-diferite:
-
-- **pack_vin** (`D:\ROA\DATABASE\SCRIPTURI_CLAR\2023\07\ff_2023_07_18_02_VIN_PACK_VIN.sql:1579-1589`,
- procedura `inregistreaza_materiale`):
- ```sql
- FROM (SELECT SUM(...) as suma, A.CONT as SCC, A.ACONT as ASCC, A.ID_GESTIUNE
- FROM VIN_RULAJE_TEMP A WHERE A.TIP = V_TIP
- GROUP BY A.ID_GESTIUNE, A.CONT, A.ACONT) A
- LEFT JOIN CORESP_CONT_VENCHELT B
- ON A.SCC = B.CONT
- AND B.STERS = 0;
- ```
- aici `A.SCC` e de fapt contul de gestiune (aliasul `SCC` vine din contextul rulajului de stoc, nu din
- `NOTE_CONTABILE`) — deci join-ul e tot `cont_gestiune = B.CONT`.
-- **pack_devize** (14+ aparitii identice intre 2013-2014, ex.
- `D:\ROA\DATABASE\SCRIPTURI_CLAR\2014\01\ff_2014_01_22_01_DEVIZE_PACK_DEVIZE.sql:3214-3217`):
- ```sql
- from rul_temp a
- left join coresp_cont_venchelt b
- on a.cont = b.cont
- and b.sters = 0
- ```
- `rul_temp.cont` e contul de gestiune al articolului din rulajul de stoc.
-- **gestiune_pack_gest_import** (5+ aparitii 2013-2017, ex.
- `D:\ROA\DATABASE\SCRIPTURI_CLAR\2017\05\ff_2017_05_31_01_GESTIUNE_PACK_GEST_IMPORT.sql:512`):
- `left join coresp_cont_venchelt b` — pe `a.cont = b.cont` (acelasi tipar).
-- **Raport recent, 2026** (`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\07\ff_2026_07_23_01_GESTIUNE_RAPOARTE.sql:25-29`,
- view `VRUL_ACT_CHELTUIELI`):
- ```sql
- iesiri AS (
- SELECT R.*, CC.CONT_CHELT AS CONT_CHELT_CORESP
- FROM VRUL_TOT R
- LEFT JOIN CORESP_CONT_VENCHELT CC ON CC.CONT = R.CONT AND CC.STERS = 0
- WHERE R.STERS = 0 AND R.CANTE <> 0
- )
- ```
- cel mai recent consumator gasit (23.07.2026), deci tabelul e inca "viu" in productie — dar
- `CONT_CHELT_CORESP` calculat aici nici nu apare in `SELECT`-ul final al view-ului (e calculat si
- abandonat), semn ca tiparul de "join pe CONT, ia campul de care ai nevoie" e suficient de standard
- incat sa fie reutilizat fara alta discutie de design.
-- **In VFP**: `Select crsconfigcvc; Locate For Cont = Upper(Alltrim(...))` — vezi sectiunea 3, mereu
- aceeasi cheie `CONT`.
-
-**Nu am gasit nicio discriminare suplimentara pe gestiune/tip document.** Toate `JOIN`-urile/`LOCATE`
-sunt strict pe `CONT` (+ `STERS = 0`), fara `ID_GESTIUNE`, fara `TIP_DOC`. `ID_CCV` nu apare folosit ca
-FK in niciun cod cercetat — pare o simpla cheie surogata a tabelului, neexpusa in `VCORESP_CONT_VENCHELT`
-(view-ul nu o include).
-
-**Ambiguitate / mai multe randuri active pentru acelasi `CONT`**: nu exista `UNIQUE`/`PRIMARY KEY`
-vizibil in cod (DDL-ul e pre-arhiva), dar **toate cele ~20 de utilizari reale presupun un singur rand
-activ per `CONT`** — niciun cod cercetat foloseste `DISTINCT`, `ROW_NUMBER()`, `MAX(...)` sau alt
-mecanism de dezambiguizare pe rezultatul join-ului. Daca ar exista doua randuri active cu acelasi `CONT`,
-`LEFT JOIN`-ul ar multiplica randurile din interogarea principala (risc de dublare de suma in
-`pack_vin`/`pack_devize`) — nu exista protectie in cod contra acestui caz. **Presupunerea de unicitate e
-implicita in tot codul care exista deja**, nu doar in propunerea lui Marius.
-
-## 3. Cine il foloseste azi — CONT_CHELT are 4 module consumatoare, CONT_VENIT are zero
-
-| Consumator | Fisier | Coloana citita |
-|---|---|---|
-| `pack_vin.inregistreaza_materiale` | `ff_2023_07_18_02_VIN_PACK_VIN.sql:1567` (si variante 2010/2012/2014) | `CONT_CHELT` |
-| `pack_devize` (procedura de calcul cost material, 14+ export-uri 2013-2014) | `ff_2014_01_22_01_DEVIZE_PACK_DEVIZE.sql:3222` (si altele) | `CONT_CHELT` (in `GROUP BY`, folosit ca `SCD`) |
-| `pack_gest_import` (5+ export-uri 2013-2017) | `ff_2017_05_31_01_GESTIUNE_PACK_GEST_IMPORT.sql:512` | `CONT_CHELT` (deductie din context, tipar identic) |
-| `VRUL_ACT_CHELTUIELI` (raport, 2026) | `ff_2026_07_23_01_GESTIUNE_RAPOARTE.sql:26` | `CONT_CHELT` (calculat, needatat in output final) |
-| VFP `ointroduceri.vc2` (bon consum, finalizare aprovizionare, transfer) | `:5476-5490` (`oinventar.vc2`), `:14663-14681`, `:15327-15332` | `CONT_CHELT`, `CONT_APROVIZIONARE` |
-| VFP `ointroduceri.vc2` (diferente NIR vs factura) | `:15395-15403` (bloc dezactivat `IF .F.`) | `CONT_DIFERENTE` (cod comentat/mort, nu ruleaza azi) |
-
-**Niciun consumator pentru `CONT_VENIT`** — cautare directa `CONT_VENIT` (case-insensitive) in tot
-`D:\ROA\DATABASE\SCRIPTURI_CLAR` (arhiva completa 2009-2026): doar 3 fisiere, toate deja citate (2 view-uri
-care includ coloana in `SELECT` fara sa o consume, 1 script de populare cu date). In VFP, cautare
-`cont_venit` (case-insensitive) in `COMUN` si `ROAGEST`: un singur hit, `SELECT ... cont_venit ...` in
-`update_corespondente_cvc`/`updateserver.prg` (fetch in cursor), **zero utilizari ale campului dupa
-fetch** (nicio referinta `.cont_venit`/`crsconfigcvc.cont_venit` gasita).
-
-**Concluzie**: propunerea lui Marius ar fi **primul consumator real al `CONT_VENIT`** in toata suita,
-desi coloana e populata din 2023. Reteta "citeste corespondenta pe cont de gestiune" e deja rulata in
-productie de 10+ ani, dar mereu pentru latura `CONT_CHELT` (cheltuiala la consum de stoc), niciodata
-pentru `CONT_VENIT` (venit la vanzare). Riscul tehnic al join-ului (cheie, filtru `STERS`, tipul
-`LEFT JOIN`) e deja validat de utilizarea existenta; riscul de **date** (daca valorile `CONT_VENIT`
-completate in 2023 sunt corecte/complete pentru toate conturile de gestiune folosite azi in facturare,
-nu doar cele 20 acoperite explicit) e nou si neverificat pe baza vie.
-
-## 4. Semantica coloanelor
-
-Dedusa din utilizari reale, nu din nume:
-
-- **`CONT`**: contul de gestiune/stoc al liniei (clasa 3xx: 301-303, 331/332, 341, 345/346/348, 361,
- 371, 381) — cheia de cautare in toate cazurile vazute (sectiunea 2).
-- **`CONT_CHELT`**: contul de cheltuiala (6xx) care se debiteaza cand marfa/materialul iese din gestiune
- (consum, bon de consum, productie) — confirmat de toti cei 4+ consumatori din sectiunea 3, unde e
- folosit mereu ca `SCD` (debit) pe o nota de tip "iesire din gestiune".
-- **`CONT_VENIT`**: prin simetrie de nume si migrarea din 2023 ("cont venit pe corespondenta 3xx-7xx"),
- e menit sa fie contul de venit (7xx) corespunzator vanzarii aceluiasi cont de gestiune — dar **nu are
- niciun consumator care sa confirme comportamentul in executie** (nicio ramura de cod care sa arate ce
- se intampla la `NULL`, la vanzare partiala, la retur). Semantica e dedusa din nume + date, nu din
- utilizare, contrar regulii "nu presupune semantica dupa nume" — de aceea marchez ca **ipoteza, nu
- fapt verificat pe comportament**.
-- **`CONT_APROVIZIONARE`**: contul folosit la operatia "finalizare aprovizionare" (`ID_SET` 264/265),
- cand se transfera valoarea din contul de tranzit (401 sau alt cont de gestiune) intr-un cont de
- gestiune specific de tranzit intern (32x) — confirmat de comentariul din DDL 2010 si de utilizarea in
- `ointroduceri.vc2:15323-15332` (`Case Alltrim(Upper(oSet.explicatia)) = 'FINALIZARE APROVIZIONARE' ...
- lcContC = Alltrim(cont_aprovizionare)`).
-- **`CONT_DIFERENTE`**: contul folosit pentru diferentele de pret intre NIR si factura de achizitie —
- confirmat de comentariul DDL 2015 ("cont diferente de pret pe NIR fata de pretul din factura de
- achizitie, ex: 6588 = 401 sau 308 = 401") si de codul `ointroduceri.vc2:15394-15403`, dar acel bloc e
- **dezactivat** (`IF .F. THEN ... ENDIF`), deci in executia curenta ramane mereu fallback-ul hardcodat
- `'6588'` — dovada ca chiar si un camp cu semantica clara si comentariu explicit poate ajunge neutilizat
- in productie, ceea ce intareste incertitudinea despre `CONT_VENIT`.
-- **`STERS`**: flag boolean soft-delete, filtrat explicit `= 0` in **toate** utilizarile gasite (view-ul
- `VCORESP_CONT_VENCHELT` il filtreaza deja la nivel de view; join-urile Oracle directe pe tabel il
- filtreaza explicit `AND B.STERS = 0`/`AND CC.STERS = 0`). Niciun cod cercetat citeste randuri cu
- `STERS = 1`.
-- **`DATAORAS`**: nu apare in niciun cod cercetat (Oracle sau VFP) — nu am gasit nicio referinta directa
- la aceasta coloana in afara interogarii propuse in decizia 27. Tipic in suita ROA e un timestamp
- tehnic de audit (data ultimei modificari a randului), dar **neconfirmat aici** — ramane de verificat pe
- schema vie.
-- **Ambiguitate pe `CONT`**: vezi sectiunea 2 — niciun cod nu trateaza cazul "mai multe randuri active
- pentru acelasi CONT"; presupunerea de unicitate e implicita, nu impusa de o constrangere vizibila.
-
-## 5. `NOM_ARTICOLE.CONT` pentru articole negestionabile si fallback pe 704
-
-- **`NOM_ARTICOLE.CONT` nu e restrans la clasa 3** — reconfirmat (vezi deja `cont_venit_corespondente.md`
- sectiunea 2): validarea `verific_cont` (`COMUN\programe\oproceduri_comune.prg:2389-2415`) verifica doar
- ca contul exista in planul de conturi al anului, fara filtru de clasa; niciun `CHECK CONSTRAINT` in
- DDL. Deci campul poate contine legitim un cont 6xx/7xx pentru un articol negestionabil, exact cum
- presupune decizia 27.
-- **Niciun fallback pe `704` existent in `pack_facturare`** — cautare `'704'` (literal SQL) in
- `D:\ROA\ROAFACTURARE\docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (17000+ linii, exportul curent al
- pachetului): **zero rezultate**. Cautare in tot `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026` (toate scripturile
- din 2026): **zero rezultate**. Fallback-ul pe 704 propus de Marius ar fi cod nou, nu o reteta deja
- scrisa in `pack_facturare`.
-- **Exista totusi un precedent independent pentru 704 ca "cont implicit de venit"**, in alt subsistem:
- ```
- COMUN\clase\anaf_efactura.vc2:8370-8376 (clasa "frm_configurare_efactura")
- *p: cconte && cont implicit articol client
- *p: ccontp && cont implicit articol furnizor
- ...
- cconte = 704
- ccontp = 628
- ```
- E o proprietate cu valoare implicita `704` ("cont implicit articol client", deci un cont de venit
- implicit pentru liniile generate la import eFactura) intr-un ecran de configurare a modulului ANAF
- eFactura. **Nu am gasit cod care sa citeasca explicit `.cconte`** (cautare `\.cconte\b` in tot `COMUN`:
- zero rezultate) — proprietatea e definita cu valoare implicita, dar consumatorul ei concret n-a fost
- gasit in timpul alocat (posibil legat generic la un camp de configurare cu acelasi nume, tipar comun in
- suita, dar neconfirmat aici). **Ce arata cu certitudine**: alegerea `704` ca implicit pentru "cont
- articol client" nu e o inventie a acestei cereri — a mai fost aleasa o data, independent, de altcineva
- din echipa (sau de Marius insusi, in alt moment), pentru un scop asemanator. Nu e insa o reteta de cod
- reutilizabila direct in `pack_facturare` — e in alt pachet/clasa, alt flux (import, nu emitere).
-
-## 6. Punctul de injectie in `contabilizeaza_articol`
-
-Sursa: `D:\ROA\ROAFACTURARE\docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (exportul curent al
-pachetului, 17548+ linii). Numerotarea de mai jos e din **acest fisier**, verificata prin citire directa
-(difera cu cateva linii fata de exportul mai vechi citat in rapoartele anterioare, care avea FACT-024 la
-7301 in loc de 7311 — normal, fisierul a mai fost actualizat intre timp).
-
-**Structura exacta a blocului care ridica FACT-024** (`:7275-7302`, inceputul functiei):
-```
-7275 BEGIN
-7276
-7277 -- 05.07.2011
-7278 BEGIN
-7279 SELECT COMPUS, ID_POL_ART
-7280 INTO V_COMPUS, V_ID_POL_ART
-7281 FROM VCRM_POLITICI_PRET_ART
-7282 WHERE ID_ARTICOL = detalii_articol.id_articol
-7283 AND ID_POL = detalii_articol.id_pol;
-7284 EXCEPTION
-7285 WHEN NO_DATA_FOUND THEN
-7286 SELECT DENUMIRE
-7287 INTO lcArticol
-7288 FROM NOM_ARTICOLE
-7289 where id_articol = detalii_articol.id_articol;
-7290
-7291 SELECT NUME_LISTA_PRETURI
-7292 INTO lcPolitica
-7293 FROM CRM_POLITICI_PRETURI
-7294 where id_pol = detalii_articol.id_pol;
-7295
-7296 RAISE_APPLICATION_ERROR(-20000,
-7297 'Articolul ' || detalii_articol.id_articol || '|' ||
-7298 lcArticol ||
-7299 ' nu este definit in politica de preturi ' ||
-7300 detalii_articol.id_pol || '|' || lcPolitica ||
-7301 '! (FACT-024)');
-7302 END;
-```
-
-**Acesta e locul unde s-ar decide "articolul nu are politica" — dar NU e suficient sa se schimbe doar
-acest bloc.** Motivul, cu citate exacte:
-
-1. Dupa acest bloc, codul verifica `IF V_COMPUS = 1 THEN` (articol compus, `:7305`, ridica alta eroare,
- FACT-016) `ELSE` (`:7391`) — ramura "articol simplu" care e cea relevanta pentru cazul cerut.
-2. Ramura "articol simplu" **deschide un cursor nou**, `cursor_articol` (definit la `:7218-7271`),
- filtrat exact pe aceeasi cheie care a dat `NO_DATA_FOUND` mai sus:
- ```
- 7261 FROM CRM_POLITICI_PRET_ART A
- ...
- 7268 WHERE
- 7269 -- A.STERS = 0 AND
- 7270 A.ID_POL = detalii_articol.id_pol
- 7271 AND A.ID_ARTICOL = detalii_articol.id_articol;
- ```
-3. Tot corpul de lucru real (calculul `V_SCD`/`V_ASCD`/`V_SCC`/`V_ASCC`/`V_EXPLICATIE`, apelul
- `pack_facturare.scrie_nota(...)` la `:7443-7467`, apelul `pack_facturare.descarca_gestiune(...)` la
- `:7476-7498`, scrierea discountului la `:7501-7518`) e **in interiorul**
- `WHILE cursor_articol%FOUND LOOP` (`:7396-7541`). **Daca articolul nu are politica de pret, acest
- cursor nu returneaza niciun rand** (e exact aceeasi conditie care a dat `NO_DATA_FOUND` la pasul 1,
- pe acelasi `(id_pol, id_articol)`), deci bucla ruleaza zero iteratii.
-
-**Concluzia tehnica**: daca s-ar modifica *doar* blocul `EXCEPTION WHEN NO_DATA_FOUND` (pasul 1) ca sa nu
-mai ridice `RAISE_APPLICATION_ERROR` si sa lase `V_COMPUS := 0` implicit, executia ar trece la ramura
-"articol simplu", ar deschide `cursor_articol`, acesta ar gasi tot zero randuri (aceeasi cauza), bucla nu
-ar rula deloc, si functia ar reveni `RETURN V_INCASAT_CALCUL` cu valoarea initiala `0`
-(declarata la `:7178`), **fara sa scrie nicio nota contabila si fara sa descarce gestiunea** — silentios,
-fara nicio eroare. Asta e o regresie mai grava decat FACT-024: azi tranzactia se opreste vizibil; cu un
-fallback naiv, factura s-ar emite fara inregistrare contabila si fara descarcare de stoc, nedetectabil
-fara audit manual.
-
-**Ce ar cere de fapt fallback-ul, pentru a pastra comportamentul actual cand politica exista**:
-- Blocul de la pasul 1 ar trebui sa **distinga** explicit cazul "politica lipseste" (continua cu
- fallback) de cazul "articol compus fara politica" (probabil tot eroare, nu e in scopul cerut) —
- posibil punand un flag local (`V_ARE_POLITICA := FALSE`) in loc de `RAISE_APPLICATION_ERROR`.
-- Ar trebui adaugata o **ramura noua, in afara/inainte de bucla `cursor_articol`**, activa doar cand
- `V_ARE_POLITICA = FALSE`, care sa:
- - calculeze `V_SCD`/`V_ASCD` **reutilizand `CASE`-ul existent pe tip document** (`:7398-7423` —
- acesta nu depinde de `cursor_articol`, poate fi extras/reutilizat identic);
- - calculeze `V_SCC` din sursa noua (corespondente pentru articol gestionabil / `NOM_ARTICOLE.CONT` sau
- `704` pentru negestionabil) — **doar acest pas e cel descris de decizia 27**;
- - decida un `V_ASCC` (azi vine din `NVL(crs_rand_articol.ascc, GetAnaliticByGrupUtilizatori(...))` —
- fara rand din cursor, ar trebui sa cada direct pe `GetAnaliticByGrupUtilizatori(...)`, posibil fara
- modificare, pentru ca aceasta functie nu depinde de cursor);
- - decida `V_EXPLICATIE`, `ID_VENCHELT`, `ID_SECTIE`, `CU_TVA`, `IN_VALUTA` — vezi sectiunea 7, aici e
- gaura reala, nu doar cod de rescris.
- - apeleze explicit `pack_facturare.scrie_nota(...)` si, conditionat, `descarca_gestiune(...)`, cu
- parametrii calculati mai sus, **duplicand** (nu reutilizand) logica din interiorul buclei existente.
-
-Asta confirma exact avertismentul din decizia 27 insasi ("modificare in COMUN, cu impact peste toata
-suita") — nu e un `IF` adaugat pe o linie, e o ramura noua de ~40-60 linii care trebuie sa reproduca o
-parte din logica ramurii existente, cu surse diferite pentru fiecare camp.
-
-## 7. Ce se pierde fata de lantul complet `CRM_POLITICI_PRET_ART -> ... -> NOTE_CONTABILE`
-
-Aceasta e partea centrala a raspunsului: **fallback-ul pe cont de venit (corespondente + nomenclator +
-704) acopera doar `SCC`, nu si restul campurilor pe care lantul de politica de pret le aduce azi din
-`NOTE_CONTABILE` fara efort.** Campurile aduse azi de `D.EXPLICATIE, D.SCD, D.ASCD, D.SCC, D.ASCC,
-D.CU_TVA, D.IN_VALUTA` (`cursor_articol`, `:7248-7253, 7259-7260`) si ce se intampla cu fiecare fara
-politica:
-
-- **`SCD`/`ASCD` (contul debitor si analiticul lui)**: **nu se pierde** — `V_SCD` se calculeaza deja
- independent de `NOTE_CONTABILE`, dintr-un `CASE` pe tipul de document (`:7398-7423`, ex. `461` pt aviz
- catre debitori, `418` pt aviz simplu, `crs_rand_articol.scd` doar pt factura normala — dar acesta din
- urma **tot vine din `NOTE_CONTABILE.SCD` prin cursor**, deci pt factura normala SCD s-ar pierde la fel
- ca SCC). **Corectie necesara fata de formularea initiala a intrebarii**: nu doar SCC vine din
- `NOTE_CONTABILE` pt factura normala — si SCD (contul de creante, tipic 411) vine de acolo. Decizia 27
- vorbeste doar de "cont de venit", nu de contul debitor — inseamna ca **si sursa lui `V_SCD` pentru
- factura normala ar trebui rezolvata** (probabil un cont fix, gen 411/`4111`, dar nu e in scopul
- deciziei 27 asa cum e formulata azi).
-- **`CU_TVA`**: **se pierde, fara alta sursa in cod.** Controleaza daca pretul de pe linie e interpretat
- cu sau fara TVA la scrierea sumei (`pack_facturare.scrie_nota(...)`, parametru `crs_rand_articol.cu_tva`
- la `:7463`). Nu exista nicio coloana echivalenta in `CORESP_CONT_VENCHELT` sau `NOM_ARTICOLE`. Fara ea,
- fallback-ul trebuie sa aleaga o valoare hardcodata sau sa o deriveze din alt camp deja disponibil pe
- `detalii_articol` (ex. `pret_cu_tva`, vazut ca parametru separat la `:7447` — posibil suficient, dar
- necesita verificare separata, nu facuta aici).
-- **`IN_VALUTA`**: **se pierde, fara alta sursa.** Controleaza daca linia e tratata ca fiind in valuta la
- nivel de nota contabila (`V_IN_VALUTA := crs_rand_articol.in_valuta;` la `:7470`, folosit apoi la
- discount `:7507`). La fel ca `CU_TVA`, nicio coloana echivalenta in corespondente/nomenclator.
-- **`EXPLICATIE`**: se pierde ca sablon configurat, dar are deja fallback partial in cod — `V_EXPLICATIE`
- e calculat cu un `CASE` pe tipul de operatie (`:7430-7439`, ex. concateneaza `pack_facturare.cdescriere`
- pt facturi tip 7) folosind `crs_rand_articol.explicatie` ca baza; fara cursor, baza ar fi goala/NULL,
- dar structura `CASE` insasi nu depinde de cursor — impact moderat, nu blocant.
-- **`ID_VENCHELT`**: are deja un fallback la nivel de sesiune —
- `NVL(pack_facturare.nid_venchelt, NVL(A.ID_VENCHELT, C.ID_VENCHELT))` (`:7244-7245`) — daca
- `pack_facturare.nid_venchelt` e setat global (parametru de sesiune), fallback-ul functioneaza deja fara
- politica; daca nu e setat, ramane `NULL` (fara eroare in cod, dar posibil relevant pentru rapoarte care
- folosesc aceasta dimensiune, neverificat).
-- **`ID_SECTIE`**: acelasi tipar — `NVL(pack_facturare.nid_sectie_stoc, C.ID_SECTIE)` (`:7246`), cu
- fallback pe variabila de sesiune.
-- **`ID_SET`** (identificatorul setului de nota folosit la scriere): **nu se pierde** — parametrul trimis
- efectiv la `scrie_nota` e `pack_facturare.nid_set` (variabila de sesiune, `:7462`), nu
- `crs_rand_articol.id_set` din cursor (acel camp e citit la `:7247` dar nu e folosit la apelul de
- scriere in ramura articol simplu — verificat direct in cod). Deci acest camp special nu depinde de
- politica de pret.
-
-**Rezumat sectiunea 7**: din cele 7 campuri aduse de lantul politicii de pret, 2 (`ID_VENCHELT`,
-`ID_SECTIE`) au deja fallback pe variabile de sesiune si ar functiona fara politica; `EXPLICATIE` are
-impact moderat (structura de calcul ramane, doar baza se pierde); `ID_SET` nu depinde deloc de politica
-in ramura articol simplu; dar **`CU_TVA` si `IN_VALUTA` nu au nicio sursa alternativa** — sunt gaura reala
-pe care simpla adaugare a unui cont de venit din corespondente/nomenclator nu o umple. **Confirmarea
-finala a intrebarii din cerere**: da, fallback-ul pe cont de venit e insuficient pentru o nota contabila
-completa — nu pentru ca "SCC" ar fi gresit, ci pentru ca doua campuri de control (TVA, valuta) raman fara
-sursa.
-
-## 8. Varianta VFP, fara sa se atinga `pack_facturare` (plan A, cerut de Marius)
-
-Ideea de verificat: daca `contabilizeaza_articol` deriva `SCC` din `id_pol`, VFP ar putea sa aleaga
-singur, inainte de a trimite articolul, un `id_pol` a carui nota are deja `SCC` = contul de venit
-calculat dupa regula lui Marius — pachetul ar rula neschimbat. Raspunsul, punct cu punct:
-
-### a) `id_pol` vine din VFP? Da — e trimis explicit, pe fiecare linie
-
-Semnatura efectiva a procedurii apelate pe fluxul principal (verificat direct in export, nu presupus):
-```
-D:\ROA\ROAFACTURARE\docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:4989-5015
-PROCEDURE adauga_articol_factura(V_ID_TEMP IN NUMBER,
- V_ID_ARTICOL IN NUMBER,
- V_SERIE IN VARCHAR2,
- V_EXPLICATIE IN VARCHAR2,
- V_ID_POL IN NUMBER,
- V_ID_GESTIUNE IN NUMBER,
- ...
- V_CONT IN VARCHAR2,
- ...
-```
-`V_ID_POL` e parametru de intrare explicit — Oracle nu il deriva din client/contract/tip document, il
-primeste ca atare de la VFP. **Niciun alt parametru din aceasta lista nu ofera un canal pentru
-SCC/id_set** (raspuns si la punctul d — vezi mai jos).
-
-**De unde il ia azi VFP**: din controlul de cautare obligatoriu al formularului `frm_articol_factura`
-(clasa `ofacturare.vc2`):
-```
-COMUN\clase\ofacturare.vc2:6822-6825
-ADD OBJECT 'Ct_clb_politici_preturi' AS ct_clb_cautare WITH ;
- cconditie = ISNULL(poDate.id_pol) or EMPTY(poDate.id_pol), ;
- cprocedura = thisform.do_cauta_politica, ;
- cvar_afisata = poDate.nume_politica, ...
-```
-```
-COMUN\clase\ofacturare.vc2:7167-7182
-PROCEDURE do_cauta_politica
- Local loCauta
- loCauta = caut_politici_curente_util()
- If !Isnull(loCauta) And !Empty(Nvl(loCauta.id_pol,0))
- poDate.id_pol = loCauta.id_pol
- poDate.nume_politica = loCauta.nume
- ...
-```
-`cconditie = ISNULL(poDate.id_pol) or EMPTY(poDate.id_pol)` e exact starea "articol fara politica" din
-cererea #13 — controlul UI cere explicit utilizatorului sa caute o politica cand campul e gol. VFP
-controleaza integral valoarea: azi vine din alegerea utilizatorului, dar nimic tehnic nu impiedica sa fie
-setata programatic, fara interactiune, la un `id_pol` calculat.
-
-### b) Drumul invers e interogabil? Da — e simetricul exact al cursorului deja documentat la sectiunea 6
-
-Cursorul din `contabilizeaza_articol` (`ff_...:7261-7267`) merge
-`CRM_POLITICI_PRET_ART -> CRM_POLITICI_PRETURI -> CRM_NOTE_VANZARI -> NOTE_CONTABILE` prin
-`A.ID_POL = B.ID_POL`, `B.ID_NOTA = C.ID_NOTA`, `C.ID_SET = D.ID_SET`. Interogarea inversa, plecand de la
-un `SCC` dorit catre `id_pol`-urile candidate, foloseste aceleasi coloane de legatura, doar fara filtrul
-pe articol:
-```sql
-SELECT DISTINCT PP.ID_POL
- FROM CRM_POLITICI_PRETURI PP
- JOIN CRM_NOTE_VANZARI NV ON NV.ID_NOTA = PP.ID_NOTA
- JOIN NOTE_CONTABILE NC ON NC.ID_SET = NV.ID_SET
- WHERE NC.SCC = :cont_venit_calculat; -- '707'/'711'/'702'/'703'/'7015'/'7018' (gestionabil) sau valoarea din NOM_ARTICOLE.CONT/'704' (negestionabil)
-```
-E o interogare noua (nu am gasit-o deja scrisa nicaieri in cod), dar foloseste exclusiv coloane si
-relatii deja confirmate ca existente si corecte (sectiunea 1 din `cont_venit_corespondente.md` + citirea
-directa a `cursor_articol` la sectiunea 6 a acestui raport). **Neverificat pe date reale**: cate randuri
-returneaza pentru fiecare `SCC` candidat — zero (nicio politica configurata cu acel SCC azi), unul
-(cazul ideal) sau mai multe (ambiguitate: care `id_pol` se alege?). Interogarea de rulat pe baza vie e
-chiar cea de mai sus, cu `:cont_venit_calculat` inlocuit pe rand cu `707`, `711`, `702`, `703`, `7015`,
-`7018`, `704`.
-
-### c) Se poate insera din VFP un rand in `CRM_POLITICI_PRET_ART`? Da — cod existent, functional, deja rulat in productie
-
-Doua mecanisme distincte, ambele reale:
-
-**c1. RPC direct, apelabil din VFP azi** — `pack_preturi.adauga_politica_pret_art`, apelat din
-`ofacturare.vc2` in procedura de modificare a listei de preturi la NIR (`ID_SET = 231`):
-```
-COMUN\clase\ofacturare.vc2:15551-15587
-*!* verific daca exista articolul in politica de preturi
-lcSql = [Select id_pol_art, id_venchelt, proc_tvav from crm_politici_pret_art where id_pol = ] + Alltrim(Str(tnIdPol)) + [ and id_articol = ] + Alltrim(Str(tnIdArticol))
-lnSucces = goExecutor.oExecute(m.lcSql, "cPoliticiPretArt")
-...
-If Nvl(loPoliticaPretArt.id_pol_art,0) = 0
- lcSql = [begin pack_preturi.adauga_politica_pret_art(] + ;
- ALLTRIM(Str(tnIdPol)) + [,] + ; && id_pol
- Alltrim(Str(tnIdArticol)) + [,] + ; && id_articol
- Alltrim(Str(tnPretLista,20,4)) + [,] + ; && pret
- Alltrim(Str(tnPretftvaLista,20,4)) + [,] + ; && pretftva
- Alltrim(Str(tnPretvtvaLista ,20,4)) + [,] + ; && pretctva
- [NULL, ] + ; && id_valuta
- Alltrim(Str(tnProcTvav,20,4)) + [,] + ; && proc_tvav
- [NULL, ] + ; && procent
- [NULL, ] + ; && id_venchelt
- Alltrim(Str(gnIdUtil)) + ; && id_util
- [); end;]
-```
-Verifica intai daca exista deja un rand (`id_pol`, `id_articol`), si daca nu, insereaza unul nou prin RPC
-existent — **exact tiparul necesar pentru punctul (c)**: "adauga articolul X in politica de pret Y",
-apelabil din VFP fara nicio modificare de pachet (`pack_preturi` nu e `pack_facturare`).
-
-**c2. Auto-populare in masa, deja existenta in `pack_facturare` insusi, dar fara parametru nou** — o
-procedura care nu ar necesita nicio modificare de cod pentru ca deja exista si e apelabila ca atare:
-```
-D:\ROA\ROAFACTURARE\docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:2093-2120
-PROCEDURE completare_politica_stoc IS
-BEGIN
- IF pack_facturare.nid_politica_stoc IS NOT NULL THEN
- MERGE INTO CRM_POLITICI_PRET_ART A
- USING (SELECT ID_ARTICOL FROM NOM_ARTICOLE
- WHERE STERS = 0 AND INACTIV = 0 AND IN_STOC = 1) B
- ON (A.ID_POL = pack_facturare.nid_politica_stoc AND A.ID_ARTICOL = B.ID_ARTICOL)
- WHEN NOT MATCHED THEN
- INSERT (ID_POL, ID_ARTICOL, ID_VALUTA)
- VALUES (pack_facturare.nid_politica_stoc, B.ID_ARTICOL, pack_facturare.nid_moneda_nationala);
- ...
- END IF;
-END completare_politica_stoc;
-```
-Aceasta e o functie **existenta, apelabila fara nicio modificare**, care garanteaza deja un rand in
-`CRM_POLITICI_PRET_ART` pentru *orice* articol cu `IN_STOC = 1` sub o singura politica "de stoc"
-(`pack_facturare.nid_politica_stoc`). Acest id_pol e la randul lui o **optiune de configurare controlata
-din VFP**:
-```
-COMUN\clase\ofacturare.vc2:21733-21734 (Init-ul ecranului de optiuni facturare)
-actualizeaza_politica_pret(23,@gnId_pol_pret_tr,@lcPolPretTr)
-actualizeaza_politica_pret(1,@gnId_pol_pret_stoc,@lcPolPretStoc)
-...
-COMUN\clase\ofacturare.vc2:21753
-This.nidpolpretstoc = Nvl(gnId_pol_pret_stoc,0)
-```
-`gnId_pol_pret_stoc` e o optiune globala (`ID_POL_PRET_STOC`, salvata/citita prin
-`actualizeaza_politica_pret`), care alimenteaza `pack_facturare.nid_politica_stoc` la initializarea
-sesiunii Oracle. **Avertisment**: aceasta politica pare deja folosita azi pentru un scop specific
-(vanzare/evaluare la pret de stoc — `nin_valuta`, `nTipVanzareRetail` sunt tratate diferentiat pentru ea
-la `ff_...:7223-7260`), cu o singura nota/SCC configurata pentru toate articolele `IN_STOC=1`. Nu e
-direct reutilizabila pentru reteta pe 6 conturi diferite (707/711/702/703/7015/7018) ceruta de decizia
-27 — dar **arata modelul exact** ("o politica tehnica, configurata o singura data, populata automat"),
-model care se poate replica de cate ori e nevoie (o politica tehnica per `SCC` distinct), fara sa se
-toate cod in `pack_facturare`.
-
-### d) Alte cai de bypass la nivel de parametru — cautate explicit, nu gasite
-
-Semnatura completa a `adauga_articol_factura` (sectiunea a) si a variantelor `_deviz`/`_stoc` (deja
-citate in `cont_venit_articol_fara_politica.md`) **nu au niciun parametru pentru cont de venit sau
-`id_set` direct** — singurul levier disponibil la nivelul acestui apel e `V_ID_POL`. Nu exista un
-parametru `V_SCC`/`V_ID_SET`/`V_COD_VENIT` pe nicio varianta citita. Concluzie: **`id_pol` e singura
-cale de influenta din VFP asupra contului de venit**, exact premisa din care a pornit intrebarea.
-
-### e) Verdict onest
-
-**Cale VFP posibila, dar nu "zero cod" si nu fara pasi de configurare o singura data**:
-
-1. VFP calculeaza `SCC`-ul dorit exact ca in decizia 27 (interogare simpla, deja tipul de cod scris in
- `update_corespondente_cvc` — sectiunea 1 a acestui raport): `CORESP_CONT_VENCHELT.CONT_VENIT` pe
- contul de gestiune pentru articol gestionabil, `NOM_ARTICOLE.CONT` (daca e 6xx/7xx) sau `'704'` pentru
- negestionabil.
-2. VFP cauta (interogarea de la punctul b) o `id_pol` existenta a carei nota are deja acel `SCC`. **Daca
- gaseste una** (plauzibil pentru conturile comune 707/711/702/703, care probabil se folosesc deja in
- politici de pret reale ale firmei) — trece la pasul 3 direct, fara nicio configurare noua.
-3. VFP se asigura (RPC `pack_preturi.adauga_politica_pret_art`, punctul c1, deja existent) ca exista un
- rand `CRM_POLITICI_PRET_ART` pentru (acel `id_pol`, articolul curent) — insereaza unul cu pretul
- tastat manual de utilizator (`tnPretLista` = pretul liniei) daca nu exista.
-4. VFP trimite acel `id_pol` in `adauga_articol_factura`, exact ca pe fluxul actual (cu politica).
- `contabilizeaza_articol` **ruleaza neschimbat** — si, bonus fata de varianta plan B (sectiunea 7),
- **campurile `CU_TVA`/`IN_VALUTA`/`EXPLICATIE`/`ASCD`/`ASCC` vin corect din nota reala configurata**,
- nu raman goale ca in fallback-ul partial din pachet.
-
-**Ce nu e gratuit**:
-- **Pasul 2 poate rata** (nicio politica existenta cu acel `SCC`) — pentru un `SCC` fara precedent (de
- ex. `704`, pentru care nu am gasit nicio nota configurata azi, sectiunea 5), ar trebui creat manual,
- o singura data, un lant nou `CRM_POLITICI_PRETURI` + `CRM_NOTE_VANZARI` + `NOTE_CONTABILE` (contabilul
- configureaza nota din `frm_config_note_contabile[2007]`, deja documentat in
- `cont_venit_corespondente.md` sectiunea 1) — asta e configurare (ecran existent), nu cod nou, dar e un
- pas manual, nu automat.
-- **Efect lateral real**: o "politica tehnica" (creata special pentru acest mecanism) ar aparea in
- ecranul de cautare politici al utilizatorului (`caut_politici_curente_util()`, aceeasi functie folosita
- la cautarea normala) — trebuie fie exclusa explicit din acel cursor de cautare (filtru pe un flag/prefix
- dedicat), fie acceptata ca vizibila, cu riscul ca un utilizator sa o aleaga din greseala pentru o
- factura normala. Nu am verificat daca `caut_politici_curente_util()` are deja un filtru care ar exclude
- automat politici fara preturi reale/marcate altfel.
-- **Ambiguitatea de la pasul 2** (mai multe `id_pol` cu acelasi `SCC`) ar cere o regula de departajare
- (cea mai recenta? prima gasita? o marcare explicita "politica implicita pentru SCC X"?) — neverificat
- pe date reale, vezi sectiunea "Ramas de verificat".
-- Aceasta varianta **schimba `id_pol`-ul scris pe linie** (azi `NULL`/gol pentru articol fara politica,
- ar deveni id-ul politicii tehnice) — orice raport/ecran care azi presupune "`id_pol` gol = articol fara
- politica" (de ex. eventuale filtre in rapoarte de vanzari) ar vedea un `id_pol` populat; nu am gasit
- cod care sa faca aceasta presupunere explicit, dar nici n-am cautat-o exhaustiv (in afara bugetului).
-
-**Concluzie e)**: nu e nevoie de "niciuna dintre cai" pentru un "nu" — exista o cale VFP verificabila si
-construita din piese deja functionale in productie (RPC de inserare in politica de pret, plus o
-interogare de cautare inversa noua dar directa). E **fezabila**, probabil **mai completa** decat plan B
-(rezolva si `CU_TVA`/`IN_VALUTA`, nu doar `SCC`), dar cere: (i) o interogare noua de cautare `id_pol` pe
-`SCC`, (ii) reutilizarea unui RPC existent pentru inserarea articolului in politica, (iii) potential
-configurare manuala o singura data (nota noua) pentru `SCC`-urile fara precedent, (iv) o decizie explicita
-despre cum se exclude/trateaza politica tehnica in ecranele de cautare vizibile utilizatorului.
-
-## Ramas de verificat pe baza de date vie
-
-- **Structura completa DDL a `CORESP_CONT_VENCHELT`** (`DESC coresp_cont_venchelt` sau echivalent):
- confirmarea coloanelor `ID_CCV` (probabil PK surogat) si `DATAORAS` (probabil timestamp tehnic),
- tipurile exacte, nullability, si daca exista o constrangere `UNIQUE`/index pe `CONT` (relevant pentru
- ambiguitatea discutata in sectiunea 2 si 4) — DDL-ul nu e in arhiva `SCRIPTURI_CLAR` (tabel pre-2009).
- Interogare de verificat: `SELECT column_name, data_type, nullable FROM user_tab_columns WHERE
- table_name = 'CORESP_CONT_VENCHELT' ORDER BY column_id;` si
- `SELECT index_name, uniqueness FROM user_indexes WHERE table_name = 'CORESP_CONT_VENCHELT';`.
-- **Continutul complet al `CONT_VENIT`** — migrarea din 2023 acopera 20 de conturi de gestiune; ramane de
- verificat daca acopera **toate** conturile de gestiune folosite azi in `NOM_ARTICOLE.CONT`/`STOC.CONT`
- in productie (altfel fallback-ul ar produce `CONT_VENIT = NULL` pentru conturi de gestiune
- neacoperite). Interogare: `SELECT DISTINCT cont FROM (SELECT cont FROM nom_articole UNION SELECT cont
- FROM stoc) WHERE cont NOT IN (SELECT cont FROM coresp_cont_venchelt WHERE sters = 0);`.
-- **Daca exista mai mult de un rand activ (`STERS = 0`) pentru acelasi `CONT`** — cod critic pentru
- join-uri fara dezambiguizare. Interogare: `SELECT cont, COUNT(*) FROM coresp_cont_venchelt WHERE
- sters = 0 GROUP BY cont HAVING COUNT(*) > 1;`.
-- **Valorile reale din `NOM_ARTICOLE.CONT` pentru articole negestionabile** — cate au deja un cont
- 6xx/7xx explicit vs. cate au un cont 3xx "gresit" (articol marcat negestionabil dar cu cont de gestiune
- ramas din import) vs. cate au `NULL`/gol, ceea ce ar decide cat de des s-ar folosi de fapt fallback-ul
- pe `704`. Interogare: `SELECT SUBSTR(cont,1,1) AS clasa, COUNT(*) FROM nom_articole WHERE gestionabil =
- 0 GROUP BY SUBSTR(cont,1,1);` (numele exact al coloanei `gestionabil` de verificat pe schema).
- Verificat si numele exact al coloanei `NOM_ARTICOLE.CONT` — vezi si `cont_venit_articol_fara_politica.md`.
-- **Cine citeste efectiv proprietatea `cconte` din `frm_configurare_efactura`** — nu am gasit consumatorul
- in codul static cercetat (`\.cconte\b`, zero rezultate in `COMUN`); posibil legata generic la o
- configuratie pe nume de camp, tipar comun in suita, dar neconfirmat.
-- **Comportamentul `scrie_nota`/`ACT_TEMP` la `SCD`/`SCC` NULL sau la `CU_TVA`/`IN_VALUTA` NULL** — codul
- PL/SQL nu are validare (confirmat in `nota_contabila_fara_politica.md`, sectiunea 2), dar constrangerile
- reale de tabel (`ACT`/`ACT_TEMP`, `NOT NULL`?) nu au fost verificate — ar decide daca o implementare pe
- jumatate facuta a fallback-ului ar da eroare Oracle explicita (`ORA-01400`) sau ar trece silentios.
diff --git a/docs/cercetare/custodie_48_49_stergere_reemitere.md b/docs/cercetare/custodie_48_49_stergere_reemitere.md
deleted file mode 100644
index 1c10088..0000000
--- a/docs/cercetare/custodie_48_49_stergere_reemitere.md
+++ /dev/null
@@ -1,217 +0,0 @@
-# Custodie (tipuri 48/49): stergere + reemitere intoarce curat descarcarea din custodie?
-
-Cercetare read-only. Raspunde la intrebarea daca editarea prin regenerare (STERS=1 pe documentul
-vechi + document nou, in aceeasi tranzactie, mecanismul proiectat la S9 din
-`docs\plan_13_unificare_formular_facturare.md:3576-3660`) pentru facturile de marfa in custodie
-(tipurile 48/49) lasa stocul de custodie neschimbat.
-
-Sursa principala citata: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`
-(prescurtat `EXPORT` mai jos, `EXPORT:linie`). Verificat direct in aceasta runda: numerotarea din
-export **coincide** cu cea folosita in materialele anterioare citate de team-lead (`scrie_fact_aviz_custodie`
-la `:10089-10325` pentru corpul functiei si `:7521-7536` pentru locul de unde e apelata;
-`sterge_factura` la `:5432-5607`) — nu s-a gasit niciun offset.
-
-**Rezultat central, care rescrie premiza cererii**: `scrie_fact_aviz_custodie` **nu se apeleaza
-niciodata pentru documente de tip 48/49**. Se apeleaza exclusiv cand `pack_facturare.ntip = 4`
-("factura din avize" — alt tip de document, complet diferit). Tipurile 48/49 sunt o ramura separata,
-care **nu atinge stocul deloc** la emitere (nu doar "il descarca prin alta cale"). Detalii mai jos.
-
-## 1. Ce sunt exact tipurile 48 si 49
-
-Confirmat pe cod, nu doar pe indiciul din materiale:
-
-- **Denumirile** ("custodie cu descarcare K" / "custodie fara descarcare K") vin din
- `COMUN\docs\tipuri_documente_facturare.md`, deja verificate pe cod de cercetarea anterioara
- `docs\cercetare\s5_acoperire_tipuri.md` (tabelul de la liniile 102-103 de acolo).
-- **Reachable din meniu**: `Meniuri\politica.mn2`, submeniul `Marfaincus` — tip 48 la linia 29,
- tip 49 la linia 26 (citat deja corect in `s5_acoperire_tipuri.md:22,102-103,146-147`).
-- **Amandoua sunt facturi de sine statatoare** (categoria "Facturi", nu "Avize" — spre deosebire de
- 42/47, care sunt avize catre custodie), sursa **VFP** de articole fiind aceeasi pentru ambele:
- `Case Inlist(tnTip, 48, 49) -> pack_facturare.cursor_articole_k(...)`
- (`COMUN\programe\ofacturare.prg:271-272` pe formularul standard, identic la `:750-752` pe prototip).
-- **`cursor_articole_k`** (`EXPORT:3595-3701`, definitia activa; exista si o declaratie in spec la
- `:382`) e o interogare de **lista de preturi**, nu o interogare de stoc/aviz: alege articolele
- dintr-o **politica de pret dedicata** (`A.ID_POL = to_number(pack_sesiune.getoptiunefirma('IDPOLPRETFACTK'))`,
- `EXPORT:3681-3682`) si **filtreaza explicit doar articole negestionabile**:
- `WHERE C.IN_STOC = 0 AND C.IN_CRM = 1 AND C.STERS = 0 AND C.INACTIV = 0` (`EXPORT:3695-3698`).
- Cu alte cuvinte: **48 si 49 sunt aceeasi sursa de articole** ("K" = politica de pret speciala
- pentru custodie, optiunea de firma `IDPOLPRETFACTK`), restransa explicit la articole
- **care nu sunt gestionate in stoc** (`IN_STOC=0` in `NOM_ARTICOLE`).
-- **Nu s-a gasit in aceasta runda ce anume distinge 48 de 49** ("cu"/"fara descarcare K") — pe tot
- codul examinat (`adauga_articol_factura`, `contabilizeaza_articol`, `cursor_articole_k`,
- `sterge_factura`), cele doua tipuri sunt tratate **identic**, fara nicio ramura care sa le separe.
- Diferenta pare sa fie doar de conventie de utilizare (business), nu de cod — semnalat la sectiunea
- "Neacoperit".
-
-## 2. Ce scrie emiterea pe un document 48/49
-
-**Nu se atinge stocul deloc, prin design, nu prin accident.** Lant de dovezi:
-
-1. `adauga_articol_factura` (`EXPORT:4989-5220`) nu are ramura proprie pentru `ntip IN (48,49)` —
- cade in `ELSE` (`:5187-5203`), care preia `V_IN_STOC` direct din `V_IN_STOC_TEMP`, valoarea
- trimisa de VFP din grid — la randul ei populata din `cursor_articole_k.GESTIONABIL`
- (`C.IN_STOC AS GESTIONABIL`, `EXPORT:3634`), deci **intotdeauna 0** pentru articolele oferite pe
- aceste doua tipuri.
-2. `contabilizeaza_articol` (`EXPORT:7173-7547`): tip 48/49 intra in bucketul "factura normala"
- pentru determinarea `SCD`/`ASCD` (`WHEN pack_facturare.ntip <= 20 or ntip IN (... 48, 49, 51, 52)`,
- `EXPORT:7400-7412`) — scrie o nota contabila normala prin `scrie_nota` (`:7443-7467`), ca orice
- factura obisnuita, folosind conturile din politica de pret K.
-3. **Apelul catre `descarca_gestiune` e conditionat** de `detalii_articol.in_stoc = 1`
- (`EXPORT:7472-7475`, ramura `IF pack_facturare.ntip <> 4`, care e adevarata pentru 48/49). Cum
- `in_stoc` vine intotdeauna 0 pentru articolele acestor doua tipuri (pasul 1), **conditia nu se
- indeplineste niciodata** — `descarca_gestiune` nu se executa.
-4. **Confirmare independenta, in interiorul lui `descarca_gestiune` insusi**: chiar daca cineva ar
- reusi sa forteze apelul, functia are propria garda de iesire timpurie:
- ```
- EXPORT:7789-7797
- -- NU SE DESCARCA GESTIUNEA PENTRU ARTICOLELE NEGESTIONABILE
- -- ASTFEL INCAT SA SE POATA FACE OPERATII GEN AVIZ DIN CUSTODIE INCLUSIV CU ARTICOLE NEGESTIONABILE
- SELECT MAX(IN_STOC) INTO lnInStoc FROM NOM_ARTICOLE WHERE ID_ARTICOL = V_ID_ARTICOL;
- if lnInStoc = 0 then GOTO SFARSIT; end if;
- ```
- Comentariul insusi confirma intentia de design: articolele negestionabile (exact categoria din
- care se alimenteaza 48/49) sunt **explicit excluse** din descarcarea de gestiune, tocmai pentru
- ca fluxul de custodie sa poata folosi articole care nu au stoc urmarit.
-5. **`scrie_fact_aviz_custodie` nu se apeleaza pentru 48/49.** Singurul apel din tot pachetul
- (`EXPORT:7520-7537`) e in interiorul aceleiasi functii `contabilizeaza_articol`, pe ramura
- `ELSE` a testului `IF pack_facturare.ntip <> 4` (`:7472`) — adica **doar cand `ntip = 4`**
- ("factura din avize"). Pentru 48/49, `ntip` e 48 sau 49, niciodata 4, deci acest cod **nu se
- executa niciodata** pe aceasta ramura. Functia `scrie_fact_aviz_custodie` insasi
- (`EXPORT:10089-10325`) nu scrie in `STOC`/`RUL` — cauta un rand deja existent in `RUL` (cu
- `ID_TIP_RULAJ = 0`, `EXPORT:10175`) pentru a calcula valori de cost, si scrie doar **note
- contabile** (`scrie_nota`, conturi `371/357/607/378/4428` — conturi de marfuri in custodie /
- cheltuieli, `EXPORT:10229-10324`) — e o functie de **conversie contabila**, nu de miscare de
- stoc.
-
-**Concluzie sectiune**: premiza din cerere ("pe ramura custodiei se cheama `scrie_fact_aviz_custodie`
-in loc de `descarca_gestiune`") descrie corect fluxul pentru **tip 4** (factura emisa dintr-un aviz,
-posibil un aviz catre custodie 42/47 emis anterior), **nu** pentru tipurile 48/49 cerute explicit.
-Pentru 48/49, niciuna din cele doua proceduri nu scrie nimic in stoc — documentul e din start
-"fara efect de stoc", pentru ca sursa lui de articole (`cursor_articole_k`) e restransa la articole
-negestionabile.
-
-## 3. Ce face stergerea (`sterge_factura`) pe un document 48/49
-
-`sterge_factura` (`EXPORT:5432-5607`) nu are nicio ramura proprie pentru `V_TIP IN (48,49)`. Constantele
-speciale verificate (`EXPORT:78-86`): `nTipVanzareRetail=43`, `nTipFacturaHotel=44`,
-`nTipFacturaRestaurant=45`, `nTipNotaPlata=46`, `nTipFacturaACN=51` — 48 si 49 nu sunt printre ele.
-
-`CASE`-ul principal (`EXPORT:5501-5551`) evalueaza `V_TIP` astfel pentru 48/49:
-- `V_TIP = 24`? Nu.
-- `V_TIP > 20 AND V_TIP NOT IN (44,45,46)`? **Da** — 48 si 49 cad in aceasta ramura generica
- ("alte tipuri de avize", `EXPORT:5512-5523`), care face:
- ```sql
- UPDATE VANZARI_CANTITATI SET STERS = 1
- WHERE ID_VANZARE_DET_AVIZ IN
- (SELECT ID_VANZARE_DET FROM VANZARI_DETALII WHERE ID_VANZARE = V_ID_VANZARE AND STERS = 0);
- ```
- `VANZARI_CANTITATI` e tabelul de bookkeeping "cantitate ramasa din comanda/aviz" (Rol A, documentat
- in `docs\cercetare\s4_punct2_registru_cantitate_ramasa.md`, citat si in `s5_acoperire_tipuri.md`
- coloana "Rol"). **48/49 nu au niciodata acest rol** (`s5_acoperire_tipuri.md:103-104`: coloana Rol
- = "—" pentru ambele) — articolele lor vin din `cursor_articole_k` (lista de preturi K), nu din
- `cursor_comanda`. Deci acest `UPDATE` **actioneaza pe zero randuri** pentru documente 48/49 (nu
- exista randuri `VANZARI_CANTITATI` legate de ele) — e un no-op inofensiv, nu o eroare, dar nici o
- actiune custodie-specifica.
-- Restul ramurilor CASE (`V_TIP=4`, `V_TIP=nTipFacturaRestaurant`) nu se aplica.
-
-Restul procedurii e comun tuturor tipurilor (nimic specific 48/49):
-- `UPDATE VANZARI_DETALII SET STERS=1 ... WHERE ID_VANZARE = V_ID_VANZARE` (`:5560-5564`) —
- marcheaza liniile facturii ca sterse.
-- `IF V_TIP IN (2,6,52)` pentru `CTR_RATE_FACTURI` (`:5566-5580`) — nu se aplica (48/49 nu sunt in
- lista).
-- `UPDATE VANZARI_CORESP SET STERS=1 ...` (`:5582-5585`) — sterge corespondentele
- factura<->aviz/comanda, generic.
-- CASE-ul final pe pachete externe (restaurant/hotel/ACN, `:5587-5605`) — nu se aplica pentru 48/49,
- cad in `ELSE NULL`.
-
-**Nu exista, nicaieri in `sterge_factura`, vreun apel care sa reverseze explicit efectul lui
-`descarca_gestiune`** (nu s-a gasit `incarca_gestiune` sau echivalent, pentru niciun tip de document,
-nu doar 48/49 — cautare `grep -n "UPDATE STOC"` in tot pachetul, zero rezultate; singurele scrieri
-gasite in zona lui `descarca_gestiune` sunt in `RUL_TEMP`, `EXPORT:9464,10006`, tabel tranzitoriu care
-se descarca in `RUL` mai departe in flux, nu direct in acest apel). Mecanismul prin care stocul
-"revine" la stergerea unei facturi normale (`ntip<=20`) **nu a fost identificat in aceasta runda** —
-posibil printr-un filtru `WHERE VANZARI_DETALII.STERS=0` in interogarile de stoc disponibil, posibil
-prin alt pachet (`PACK_STOC`?) sau printr-un trigger, in afara `PACK_FACTURARE` si a perimetrului
-citit. Marcat explicit la "Neacoperit" — **e o intrebare generala a sistemului, nu specifica
-custodiei**, pentru ca `sterge_factura` trateaza identic (fara reversare explicita) orice tip de
-document.
-
-## 4. Garzi existente la stergere — prind si cazul custodiei?
-
-Cele trei garzi de la inceputul lui `sterge_factura`, verificate pe liniile citate de team-lead
-(coincid exact, fara offset):
-
-- `EXPORT:5452-5462` — blocheaza daca exista **facturi de retur** (`VANZARI_CORESP.TIP=3`) pe
- documentul curent.
-- `EXPORT:5466-5476` — blocheaza daca exista **facturi/avize de retur** (`TIP IN (1,2)`) pe un
- aviz curent.
-- `EXPORT:5480-5494` — blocheaza daca exista **avize de retur** pe avizele care au generat o
- factura din aviz curenta.
-
-**Niciuna nu mentioneaza custodie sau `ntip IN (48,49)`** — toate trei filtreaza exclusiv pe
-`VANZARI_CORESP.TIP IN (1,2,3)` (relatii factura<->retur / aviz<->retur), independent de tipul
-documentului curent (`V_ID_VANZARE`). Pentru un document 48/49 fara retur emis pe el, **niciuna nu
-se declanseaza** — stergerea trece liber, exact ca pentru o factura normala fara retur.
-
-## 5. Verdict
-
-**Regenerarea (stergere + reemitere) e SIGURA pentru documentele 48/49 in privinta stocului de
-custodie — dar dintr-un motiv diferit de cel presupus in cerere.** Nu pentru ca stergerea "intoarce
-curat" o descarcare de custodie — ci pentru ca **emiterea unui document 48/49 nu descarca nimic din
-stoc/custodie in primul rand** (sectiunea 2: sursa de articole e restransa structural la articole
-negestionabile, `IN_STOC=0`, iar `descarca_gestiune` are doua garzi independente care o opresc pentru
-astfel de articole). Stergerea (sectiunea 3) nu are nimic custodie-specific de reversat, si nici nu
-are nevoie sa aiba, pentru ca nimic custodie-specific n-a fost scris la emitere. **`ntip=4` (factura
-din avize) e ramura care foloseste efectiv `scrie_fact_aviz_custodie`, si e un tip de document
-diferit de 48/49** — premiza din cerere ("pe ramura custodiei se cheama `scrie_fact_aviz_custodie`
-in loc de `descarca_gestiune`") descrie corect tip 4, nu 48/49.
-
-**Conditie sub care verdictul s-ar putea rasturna, ne-exclusa 100% in aceasta runda**: siguranta de
-mai sus depinde de invariantul "un document 48/49 contine numai articole cu `IN_STOC=0`". Daca
-articolele adaugate pe un document 48/49 ar veni vreodata **printr-o alta cale** decat
-`cursor_articole_k` (o cautare libera de articole, nerestransa la politica K), un articol gestionabil
-(`IN_STOC=1`) ar trece garda de la `adauga_articol_factura`/`contabilizeaza_articol` (sectiunea 2,
-pasul 1: `V_IN_STOC_TEMP` ar deveni 1) si **`descarca_gestiune` s-ar executa normal** — caz in care
-`sterge_factura`, care nu reverseaza explicit stocul pentru niciun tip (sectiunea 3), ar lasa un
-decalaj real. **Nu s-a gasit in aceasta runda** o cale VFP care sa permita asta pentru 48/49 (grid-ul
-de articole al acestor doua tipuri e populat o singura data, la deschiderea formularului, direct din
-`cursor_articole_k` — `COMUN\programe\ofacturare.prg:271-272`; nu exista o cautare separata de
-articole vazuta in codul citit), dar nu s-a verificat exhaustiv toate punctele de intrare posibile in
-`VANZARI_DETALII_TEMP` pentru aceste doua tipuri.
-
-## Verificat direct / Dedus / Neacoperit
-
-**Verificat direct pe cod (fisier:linie citat in sectiunile 1-4):**
-- Tip 48/49 = facturi (nu avize), sursa unica de articole `cursor_articole_k`, restransa la
- `IN_STOC=0`.
-- `scrie_fact_aviz_custodie` se apeleaza exclusiv pentru `ntip=4`, niciodata pentru 48/49.
-- `descarca_gestiune` are doua garzi independente (`in_stoc=1` la apelant, plus garda proprie pe
- `NOM_ARTICOLE.IN_STOC`) care o opresc pentru articolele din 48/49.
-- `sterge_factura` nu are ramura proprie pentru 48/49 (cade in bucketul generic ">20, exclus
- hotel/restaurant/notaplata"), iar actiunea acelui bucket (`VANZARI_CANTITATI`) nu are ce sa
- actioneze pentru aceste doua tipuri (fara rol in acel tabel).
-- Cele trei garzi de refuz al stergerii nu disting custodia, si nu se declanseaza pentru un document
- 48/49 fara retur emis pe el.
-
-**Dedus, nu verificat exhaustiv:**
-- Ca operatorul nu poate adauga pe un document 48/49 un articol gestionabil pe alta cale decat
- `cursor_articole_k` — bazat pe faptul ca grid-ul se populeaza o singura data la deschidere, dar
- n-am urmarit tot codul de interactiune al grid-ului (`adauga la lista`/editare inline) pentru cele
- doua tipuri.
-- Ca diferenta reala dintre tip 48 si tip 49 e doar de conventie/business, nu de cod — n-am gasit
- nicio ramura care sa le separe, dar nici n-am cautat in afara `PACK_FACTURARE`/`ofacturare.prg`
- (de exemplu in rapoarte sau in alte proceduri VFP care ar putea trata diferit "cu descarcare K" vs
- "fara").
-
-**Neacoperit in aceasta runda:**
-- Mecanismul general prin care stocul "revine" la stergerea unei facturi **normale** (`ntip<=20`) —
- nu s-a gasit niciun `UPDATE STOC`/reversare explicita in `PACK_FACTURARE`; posibil calculat prin
- interogari care filtreaza `VANZARI_DETALII.STERS=0`, posibil in alt pachet Oracle sau prin trigger,
- in afara perimetrului citit in aceasta runda. Nu e o intrebare specifica custodiei — se aplica
- identic la orice tip de document — dar ramane deschisa.
-- Semnificatia exacta si diferenta functionala/de raportare intre "custodie cu descarcare K" (48) si
- "custodie fara descarcare K" (49) — n-am gasit in cod ce anume descarca "K" daca nu e stoc fizic
- (posibil un calcul contabil de adaos comercial specific comertului cu amanuntul, coeficientul K,
- dar nu confirmat pe cod in aceasta runda).
-- Testare pe date reale (baza de dev) a unui ciclu emitere->stergere->reemitere pe un document 48/49
- — cercetarea a fost exclusiv pe cod si `SELECT`-uri simple, fara sa ruleze fluxul.
diff --git a/docs/cercetare/discount_document_cota_tva.md b/docs/cercetare/discount_document_cota_tva.md
deleted file mode 100644
index 586eff4..0000000
--- a/docs/cercetare/discount_document_cota_tva.md
+++ /dev/null
@@ -1,731 +0,0 @@
-# Cota de TVA a discountului de DOCUMENT (VANZARI.DISCOUNT) — program + eFactura
-
-Cercetare read-only. Nu s-a modificat niciun fisier, nu s-a rulat `git_sync.ps1`, pe Oracle doar
-`SELECT`.
-
-STATUS: complet.
-
-Acest document e rezultatul imbinarii a doua rapoarte de cercetare pe aceeasi intrebare, facute de
-doi agenti separati. Raportul suplimentar, `discount_document_cota_tva_b.md`, ramane pe disc ca
-sursa a partii adaugate aici (sectiunile 3.1-3.3 si observatiile din 2.3 si 4.1).
-
-## Raspunsul scurt
-
-Discountul de document **NU se sparge pe cote**. El devine o **singura pseudo-linie negativa**
-numita `"Discount % Factura"`, careia i se atribuie **cota maxima de TVA de pe factura**
-(`Calculate Max(proc_tvav) To lnProcTvav`). eFactura chiar genereaza `cac:AllowanceCharge` la nivel
-de document, cu `TaxCategory/ID` + `Percent` + `TaxScheme` corecte si `AllowanceChargeReason =
-"Discount"`, `ReasonCode = 95` — dar **cota e cea maxima, aleasa prin `Max()`, nu de
-utilizator si nici proportionala**, iar "explicatia" e literalul hardcodat `"Discount"`.
-
-Regula "cota maxima" e scrisa **de doua ori**, independent: in VFP (`Calculate Max(proc_tvav)`) si in
-PL/SQL (`PACK_FACTURARE.recalculeaza_totaluri_vanzari`, care din ea deriva `VANZARI.DISCOUNT_TVA`,
-`TOTAL_TVA` si `TOTAL_CU_TVA`). Pentru #13 asta e informatia operationala: **se schimba in doua
-locuri, nu in unul** (sectiunea 1.5).
-
-Pe factura obisnuita (cote mixte, fara scutire), XML-ul rezultat e intern coerent (TaxSubtotal-urile
-includ deja pseudo-linia de discount) si **trece validarea** — verificat cu validatorul local
-DUKIntegrator, inclusiv pe cazul mixt si pe unul cu baza impozabila negativa. Deci defectul pe care
-**l-am putut dovedi** nu se vede: e o eroare **tacuta de atribuire fiscala**. Pe o factura cu 1000
-lei la 21% si 1000 lei la 11% cu discount de document 10%, se declara cu **10 lei mai putin TVA**
-decat ar trebui (sectiunea 4.4), mereu in acelasi sens — TVA colectat subdeclarat. Pe factura
-scutita XML-ul e si mai putin coerent decat atat — vezi paragraful urmator.
-
-**Sectiunea 3 s-a inchis intre timp, cu un rezultat impartit.** Pe o factura obisnuita (toate
-liniile `scutit=0`, `expltva` gol), pseudo-linia de discount se contopeste corect in grupul cotei
-maxime — verificat prin masuratoare, nu doar dedus (sectiunea 3.1). Dar pe o factura **scutita,
-cu taxare inversa sau intracomunitara**, gruparea chiar se rupe: pseudo-linia formeaza un
-`TaxSubtotal` **orfan**, cu baza negativa si categorie gresita (sectiunea 3.2). Validatorul local nu
-respinge nici aceasta forma (sectiunea 3.3) — deci ramane, ca si defectul de atribuire fiscala, o
-eroare **tacuta**, nu una care blocheaza factura.
-
----
-
-## 1. Cum se aplica azi discountul de document in program
-
-**Cine il aplica: amandoua, fiecare pentru consumatorul lui.** Oracle stocheaza `VANZARI.DISCOUNT`
-(valoare absoluta, in moneda documentului) si `VANZARI.DISCOUNT_EVIDENTIAT`, si **isi calculeaza
-singur** TVA-ul discountului in `PACK_FACTURARE.recalculeaza_totaluri_vanzari` (sectiunea 1.5);
-prelucrarea pentru **listare si eFactura** se face separat, in cursoare VFP (sectiunile 1.1-1.4).
-Ambele folosesc aceeasi regula — cota maxima — dar o implementeaza independent.
-
-### 1.1. Randul-sentinela `ZZZZ...` in `crsfactura`
-
-`COMUN\programe\ofacturare_comun.prg:1886-1897` (`Procedure prelucreaza_facturacrs`):
-
-```
-1886 If tnDiscount<> 0
-1888 Calculate Sum(valdiminuatftva),Sum(vvaldiminuatftva),Max(id_temp) To lnTotalBaza,lnTotalBazaVal,lnIdTemp
-1890 Append Blank
-1891 Replace denumire With Replicate('Z',20),cantitate With 1,;
-1892 pretftva With lnTotalBaza,discountftva With tnDiscount,valdiscountftva With tnDiscount,;
-1893 valdiscounttva With Round(tnDiscount * (tnProcTvav - 1),gnPc),;
-1894 vpretftva With lnTotalBazaVal,vdiscountftva With tnDiscountVal,vvaldiscountftva With tnDiscountVal,;
-1895 vvaldiscounttva With Round(tnDiscountVal * (tnProcTvav - 1),gnPVal),;
-1896 proc_Tvav With tnProcTvav,id_temp With lnIdTemp+1
-1897 Endif
-```
-
-Observatii portante:
-- **baza** discountului = `Sum(valdiminuatftva)` peste **toate** liniile, indiferent de cota;
-- **TVA-ul** discountului = `tnDiscount * (tnProcTvav - 1)` — o **singura** cota, `tnProcTvav`;
-- randul e un **singur rand de document**, nu o repartizare pe linii.
-
-### 1.2. De unde vine `tnProcTvav` — cota maxima de pe factura
-
-Toate cele trei cai de apel calculeaza acelasi lucru:
-
-| apelant | linia | cod |
-|---|---|---|
-| listare factura emisa (din lista de facturi) | `COMUN\clase\ofacturare_comun.vc2:4494-4498` (`frm_facturi.do_listeaza_formular`, 4188-4539) | `Calculate Max(proc_tvav) To lnProcTvav` -> `prelucreaza_facturacrs([crsdetalii],[crsfactura],lnProcTvav,lnDiscount,lnDiscountVal)` |
-| listare proforma | `COMUN\clase\ofacturare_comun.vc2:7293-7298` (`frm_proforme.do_listare`, 7233-7315) | idem |
-| listare din `oproceduri_facturare` | `COMUN\programe\oproceduri_facturare.prg:1386-1391` | `Select crsDetaliiListare` / `Calculate Max(proc_tvav) To lnProcTvav` |
-| facturare din stoc | `COMUN\programe\ofacturare_stoc.prg:582, 728` | `Calculate Max(proc_tvav) To lnProcTvav` |
-
-**Deci cota de TVA a discountului de document = MAX(cotele de pe liniile facturii).** Nu e nici
-aleasa de utilizator, nici derivata din structura pe cote, nici proportionala. Nu exista niciun
-control in formular pentru ea si nicio coloana in `VANZARI` care sa o retina.
-
-### 1.3. Randul `ZZZZ...` devine pseudo-linia `"Discount NN.NN % Factura"`
-
-`COMUN\programe\ofacturare_comun.prg:1273-1392` (in `prelucreaza_factura`, scan peste
-`crsfacttemp`):
-
-```
-1279 If loArticol.denumire <> Replicate('Z',20)
- ... (linia normala de articol se copiaza in cursorul destinatie)
-1361 Else
-1362 loArticol.denumire = [FACTURA]
-1363 Endif
-1365 If lnPretListAviz = 2 && pret fara tva
-1367 If loArticol.discountftva <> 0
-1368 Append Blank
-1369 lnProcentDiscount = loArticol.discountftva * 100 / loArticol.pretftva
-1370 Replace denumire With [Discount ]+Alltrim(Str(lnProcentDiscount,10,2))+[ % ]+Alltrim(Proper(loArticol.denumire)),;
-1374 pretftva With (-1) * loArticol.discountftva,valftva With (-1) * loArticol.valdiscountftva,...;
-1375 ... valtva With (-1) * loArticol.valdiscounttva,;
-1376 proc_tva With loArticol.proc_Tvav,id_jtva_coloana With loArticol.id_jtva_coloana,...
-1378 Endif
-```
-
-Randul `ZZZZ...` nu ajunge niciodata in cursorul final ca atare — la `:1361-1363` doar i se schimba
-denumirea in `FACTURA`, iar la `:1367-1377` se creeaza pseudo-linia
-**`"Discount 10.00 % Factura"`** cu `pretftva` si `valftva` **negative** si `proc_tva = tnProcTvav`.
-
-**Coloanele atinse in cursorul final** (`crsFacturaFinala` / `crsfacturafinalaval`): `denumire`,
-`cantitate`, `pretftva` (negativ), `valftva` (negativ), `valtva` (negativ), `proc_tva`,
-`id_jtva_coloana`, `id_jtva_coloana_ex`. Deci **discountul de document mosteneste si coloana de
-jurnal TVA (`id_jtva_coloana`) a randului-sentinela** — care nu e setata la `:1891-1896`, deci
-ramane 0/blank pe randul `ZZZZ`. (Consecinta in eFactura: sectiunea 2.3.)
-
-### 1.4. `discount_evidentiat` schimba cate pseudo-linii "Discount" apar
-
-- `discount_evidentiat = 0` (implicit): ramura `ofacturare_comun.prg:1177-1203`. Liniile de articol
- primesc `0 As discountftva` (`:1188`), deci **nu** genereaza pseudo-linii; doar randul `ZZZZ`
- (reinserat separat prin `Where denumire = Replicate('Z',20)`, `:1193-1203`) pastreaza
- `discountftva` -> **o singura** pseudo-linie de discount, cea de document.
-- `discount_evidentiat = 1`: ramura `:1157-1173`, un singur `Insert` fara `WHERE`, `discountftva`
- pastrat per articol (coloana 20 din `group by 2,3,...,20,...`) -> **fiecare articol cu discount
- unitar produce propria pseudo-linie** `"Discount X % "`, plus cea de document. Aici
- cotele chiar sunt cele ale articolelor respective.
-
-### 1.5. Regula "cota maxima" e implementata A DOUA OARA, in Oracle
-
-Corectie la afirmatia de la inceputul sectiunii 1 ("Oracle stocheaza doar `VANZARI.DISCOUNT`"):
-**este incompleta**. `PACK_FACTURARE.recalculeaza_totaluri_vanzari` reface acelasi rationament
-independent, in PL/SQL —
-`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`, procedura de la
-`:16024`:
-
-```
-16081 MAX(ROUND(decode(lnInValuta, 1,
-16082 ROUND(a1.curs * NVL(lnDiscountFactura,0) / a1.multiplicator, lnPreciziePretV),
-16085 NVL(lnDiscountFactura,0)) *
-16088 (a1.proc_tvav - 1), lnPreciziePretV)) as DISC_TVA_RON,
-16090 MAX(ROUND(NVL(lnDiscountFactura,0) * (a1.proc_tvav - 1), lnPreciziePretV)) as DISC_TVA_VAL,
-```
-
-**Precizare pe forma exacta**: nu e `discount * MAX(proc_tvav)`, ci `MAX(discount * (proc_tvav-1))`
-— maximul se ia peste **produsele rotunjite**. Cat timp `lnDiscountFactura >= 0` cele doua coincid
-(acelasi rand castiga), deci efectul e identic cu al VFP-ului. Ar diverge doar pe un discount
-**negativ** (o majorare), unde `MAX` ar alege cota cea mai **mica** — n-am verificat daca un discount
-negativ e posibil in UI.
-
-**Ce se scrie cu asta** (`:16049-16062` -> `:16214-16227`): nu doar `VANZARI.DISCOUNT_TVA`, ci si
-**totalurile salvate ale documentului**:
-
-```
-16052 a.suma_tva_ron - a.disc_tva_ron as TOTAL_TVA,
-16053 a.suma_fara_tva_ron - a.disc_fara_tva_ron + a.suma_tva_ron - a.disc_tva_ron as TOTAL_CU_TVA,
-...
-16214 update vanzari set discount = lnDiscountFactura, discount_tva = lnDiscountTVA, ...
-16218 total_tva = lnTotalTVA, total_cu_tva = lnTotalCuTVA, ... where id_vanzare = V_ID_VANZARE;
-```
-
-**Consecinta pentru #13**: regula de repartizare a discountului pe cote trebuie schimbata **in doua
-locuri, nu unul** — `prelucreaza_facturacrs` (VFP, pentru listare/eFactura/nota contabila) **si**
-`recalculeaza_totaluri_vanzari` (Oracle, pentru `VANZARI.DISCOUNT_TVA` / `TOTAL_TVA` /
-`TOTAL_CU_TVA`, adica pentru ce se vede in liste, rapoarte de sinteza si sold). Daca se schimba doar
-unul, `VANZARI.TOTAL_TVA` si TVA-ul din XML **vor diverge**. Nu am verificat care dintre cele doua
-valori e considerata azi "cea buna" acolo unde ambele sunt disponibile.
-
-### 1.6. Ramura "pret cu TVA" (`lnPretListAviz = 1`) — nu atinge facturile
-
-`ofacturare_comun.prg:1380-1391` (ramurile `Otherwise` / `tnDiscountEvidentiat=1 And
-lnPretListAviz=1`) seteaza pe pseudo-linia de discount **numai** `pretctva`/`valctva`/`valtva`,
-**nu** si `pretftva`/`valftva` — care raman 0. Am verificat daca asta poate ajunge in eFactura:
-**nu poate**. `lnPretListAviz` e initializat `= 2` (`COMUN\programe\ofacturare.prg:1112`) si e pus
-pe `1` intr-un singur loc, in ramura de **aviz de transfer** (`lcRaport = [AVIZ]`,
-`ofacturare.prg:1856-1861`, conditionat de `gnPretListAviz = 1`), iar avizele nu trec de filtrul
-`tip_doc_394 IN ('F','S','M','U','H')` din `xmlefactura.prg:276-279`. Deci nu e un defect eFactura.
-
----
-
-## 2. Ce ajunge in XML-ul eFactura
-
-**Generatorul viu** e `COMUN\programe\xmlefactura.prg` (`getXmlEFactura`), apelat prin
-`goExport.export2xml_efactura` (`COMUN\programe\oexport.prg:1586-1594`) din
-`COMUN\programe\ofacturare.prg:2126`, cu cursorul `crsFacturaFinala` (sau `crsfacturafinalaval` in
-valuta) — exact cursorul de listare (`ofacturare.prg:2108-2114`).
-`COMUN\clase\anaf_efactura.vc2` este UI-ul/transportul ANAF (trimitere, validare, preview), nu
-generatorul de XML.
-
-### 2.1. Da — se genereaza `cac:AllowanceCharge` la nivel de document
-
-Detectia e **euristica pe denumire + semn**, `xmlefactura.prg:230`:
-
-```
-230 Iif('DISCOUNT' $ Upper(a.denumire) And a.pretftva < 0, 1, 0) As discount ;
-```
-
-Pseudo-linia `"Discount 10.00 % Factura"` cu `pretftva < 0` (sectiunea 1.3) satisface ambele
-conditii. Randurile marcate `discount = 1` sunt excluse din liniile normale (`Scan For discount =
-0`, `:901`) si emise ca alocari de document, `xmlefactura.prg:756-795`:
-
-```
-757 If mliniireducere > 0
-758 SELECT SUM(-1*valftva) as valftva, proc_tva ;
-759 FROM C_IES_FORM ;
-760 WHERE discount = 1 ;
-761 GROUP BY proc_tva ;
-762 ORDER BY proc_tva ;
-763 INTO CURSOR cDiscounturiTemp
-765 Select cDiscounturiTemp
-766 SCAN
-770 oallowancecharge = oinvoice.appendchild(oxml.createelement("cac:AllowanceCharge"))
-771 ... ChargeIndicator = "false"
-773 ... cbc:AllowanceChargeReasonCode = "95"
-775 ... cbc:AllowanceChargeReason = "Discount"
-777 odocallowancecharge = ... ("cbc:Amount") && BT-92
-778 odocallowancecharge.setattribute("currencyID", "RON")
-779 odocallowancecharge.Text = Alltrim(Str(m.lnValftva, 15, 2))
-780 otaxcategoryallowance = ... ("cac:TaxCategory")
-782 Select tip From C_TVA_FACTURA Where proc_tva = (m.lnProcTva - 1) * 100 Into Array agettipcota
-786 otaxcategoryallowance.lastchild.Text = Alltrim(agettipcota(1))
-787 ... ("cbc:Percent")
-788 otaxcategoryallowance.lastchild.Text = Alltrim(Str((m.lnProcTva - 1) * 100, 2, 0))
-789 otaxschemeallowance = ... ("cac:TaxScheme") / cbc:ID = "VAT"
-792 ENDSCAN
-```
-
-Raspunsurile punctuale:
-
-- **`cac:TaxCategory/cbc:ID`** (`S`, `AE`, `Z`, `E`, `K`, `O`): **nu e hardcodat** — se ia din
- `C_TVA_FACTURA.tip`, adica din `This.GetTipTaxa(mtipfactura, intracomunitar, taxare_inversa,
- scutit, proc_tva, @lcExplicatie, @lcMotiv, expltva)` (`xmlefactura.prg:298`), pe grupul cu
- **aceeasi cota** ca pseudo-linia de discount.
-- **`cbc:Percent`**: `(proc_tva - 1) * 100` al pseudo-liniei — adica **cota maxima de pe factura**
- (sectiunea 1.2). *Aici e raspunsul la intrebarea lui Marius: cota exista in XML, dar sursa ei e
- un `Max()`, nu o alegere.*
-- **`cbc:AllowanceChargeReason`**: literalul `"Discount"` (`:776`), **hardcodat**;
- **`cbc:AllowanceChargeReasonCode`**: `"95"` (`:774`), hardcodat. Textul real din program
- (`"Discount 10.00 % Factura"`) **nu** ajunge in XML — ramane doar in cursorul de listare.
- Deci "explicatia" pe care o cauta Marius nu exista: e o constanta.
-
-### 2.2. Cote mixte: se sparge in mai multe `AllowanceCharge`?
-
-**Mecanismul exista** (`GROUP BY proc_tva`, `:761` -> cate un `AllowanceCharge` per cota), dar
-**nu se activeaza pentru discountul de document**, pentru ca acesta e prin constructie o **singura**
-pseudo-linie cu o **singura** cota (`Max`). Gruparea foloseste efectiv doar cand
-`discount_evidentiat = 1`, unde exista mai multe pseudo-linii de discount **pe articol**, fiecare cu
-cota articolului ei.
-
-Deci, pe o factura cu 21% si 11% si un discount de document: **un singur** `AllowanceCharge`, cu
-`Percent = 21`.
-
-### 2.3. Riscuri identificate in acest bloc (nedovedite pe rulare)
-
-- **`currencyID` hardcodat `"RON"`** la `:778`, in timp ce tot restul documentului foloseste
- `mmoneda` (`:820, 827, 873, 876, ...`, definit la `:266-267`). Pe o factura in valuta cu discount
- de document, `AllowanceCharge/cbc:Amount` iese cu `currencyID="RON"` iar
- `LegalMonetaryTotal/cbc:AllowanceTotalAmount` cu `currencyID="EUR"`. Acelasi tipar la acciza
- (`:803`). **Testat cu validatorul local** (sectiunea 4.3): DUKIntegrator **nu** respinge
- neconcordanta. Ramane o inconsecventa de cod, dar nu doar teoretica: sectiunea 4.1 arata un XML
- real de productie cu exact aceasta neconcordanta, confirmat pe SHA256 ca a plecat la ANAF si a
- fost **acceptat**.
-- **`Select ... Into Array agettipcota` fara garda pe `_Tally`** (`:782-786`): daca gruparea nu
- gaseste randul (egalitate pe numere in virgula mobila: campul `C_TVA_FACTURA.proc_tva` e stocat
- rotunjit, comparatia se face cu `(lnProcTva-1)*100` calculat la rulare), `agettipcota(1)` da
- eroare de variabila inexistenta. *Risc teoretic — nu l-am putut reproduce; il semnalez ca "de
- verificat", nu ca defect.*
-- **`Str((lnProcTva-1)*100, 2, 0)`** — latime 2. Pentru cotele romanesti (0, 5, 9, 11, 19, 21) e in
- regula; o cota de trei cifre ar da `**`.
-
----
-
-## 3. Coerenta cu `TaxTotal` / `TaxSubtotal`
-
-**Da, baza impozabila din XML tine cont de discount** — si o face corect aritmetic.
-
-`C_TVA_FACTURA` se construieste **peste toate randurile** din `C_IES_FORM`, **inclusiv**
-pseudo-linia de discount (nu exista `WHERE discount = 0`), `xmlefactura.prg:242-248`:
-
-```
-242 Select(proc_tva - 1) * 100 As proc_tva, intracomunitar, taxare_inversa, scutit, expltva, ;
-243 Sum(valtva) As tva, ;
-244 Sum(valftva) As valoare, ... ;
-245 From C_IES_FORM ;
-246 Group By proc_tva, intracomunitar, taxare_inversa, scutit, expltva ;
-247 Into Cursor C_TVA_FACTURA
-```
-
-`valftva`/`valtva` ale pseudo-liniei sunt negative -> grupul cotei maxime iese **deja net de
-discount**. `cbc:TaxableAmount` = `C_TVA_FACTURA.valoare` (`:828`), `cbc:TaxAmount` =
-`C_TVA_FACTURA.tva` (`:831`).
-
-Totalurile inchid corect (`:863-898`):
-
-```
-864 Sum valftva To mtotalnet For discount = 0 && numai liniile reale
-867 mtotalnetliniifactura = mtotalnet && BT-106 LineExtensionAmount
-869 mtotalnet = mtotalnet + mtotalcharges - mtotalallowances && BT-109 TaxExclusiveAmount
-870 mtotalbrut = mtotalnet + mtotaltva && BT-112 TaxInclusiveAmount
-882 ... AllowanceTotalAmount = mtotalallowances && BT-107
-```
-cu `mtotalallowances = mdiscounturi = Sum(-1*valftva) For discount = 1` (`:282-287`).
-
-Verificare: `Σ TaxSubtotal/TaxableAmount` = suma peste toate randurile = `mtotalnetliniifactura −
-mdiscounturi` = `mtotalnet` = `TaxExclusiveAmount`. Deci **BR-CO-13** (`TaxExclusiveAmount =
-LineExtensionAmount − AllowanceTotalAmount + ChargeTotalAmount`) si **BR-CO-15** se respecta.
-
-**Concluzie**: pe **factura obisnuita**, suma liniilor minus discount **da** `TaxableAmount`-ul
-declarat; discrepanta nu e aritmetica, ci **de atribuire pe cote** (sectiunea 4). Pe **factura
-scutita / cu taxare inversa / intracomunitara**, concluzia nu tine — vezi 3.1-3.3.
-
-Rationamentul de mai sus presupune ca pseudo-linia de discount **cade in acelasi grup** cu liniile
-de la cota maxima. Asta e adevarat doar daca cele patru chei suplimentare din `GROUP BY`
-(`intracomunitar`, `taxare_inversa`, `scutit`, `expltva`, `xmlefactura.prg:246`) ies **egale** pe
-pseudo-linie si pe liniile reale. Subsectiunile care urmeaza verifica exact asta, prin masuratoare,
-nu prin deductie.
-
-### 3.1. Verificat prin masuratoare: `IIF()` peste NULL nu se propaga ca `.NULL.` in VFP
-
-Pseudo-linia are `id_jtva_coloana = 0` (randul-sentinela e `Append Blank` la
-`ofacturare_comun.prg:1890` si campul nu e setat la `:1891-1896`). Daca LEFT JOIN-ul de la
-`xmlefactura.prg:226-232` nu gaseste rand in `cJTVAVanzariTemp` pentru `id = 0`, `b.coloana_jv` iese
-`.NULL.`, si intrebarea e ce intoarce `Iif(Left(.Null.,2) = 'CE', 1, 0)` — daca s-ar propaga ca
-`.NULL.`, cheia de grupare a pseudo-liniei ar diferi de a liniilor reale pe **orice** factura.
-
-Am rulat o sonda headless (`vfp9.exe -A -T`, `probe_null.prg`) care reproduce exact acest `LEFT
-JOIN` si `GROUP BY`, cu o pseudo-linie de discount pe `id_jtva_coloana = 0`:
-
-```
-1) IIF(.NULL.="CE",1,0) -> tip=N isnull=.F.
-2) IIF(LEFT(.NULL.,2)="CE",1,0) -> tip=N isnull=.F.
-3) IIF(INLIST(.NULL.,...),1,0) -> tip=N isnull=.F.
- linie=ARTICOL A | coloana_jv nul=.F. | intracom=0 | scutit=0
- linie=ARTICOL B | coloana_jv nul=.F. | intracom=0 | scutit=0
- linie=Discount 10.00 % Factura | coloana_jv nul=.T. | intracom=0 | scutit=0
-4) grupuri in C_TVA_FACTURA = 1
- grup: cota=21 baza=1350 tva=283.50 (1500 - 150, corect)
-```
-
-**`IIF()` intoarce ramura falsa, nu `.NULL.`**, chiar daca conditia e nula. Deci pe o factura
-interna obisnuita pseudo-linia primeste `intracomunitar=0, taxare_inversa=0, scutit=0` — exact ca
-liniile reale — si **se contopeste in grupul cotei maxime**. Sonda ramane pe disc in
-`%TEMP%\claude\...\scratchpad\probe_null.prg`, nu depinde de baza de date si se poate reface
-oricand.
-
-### 3.2. Dar pe factura scutita / taxare inversa / intracomunitara, gruparea chiar se rupe
-
-Contopirea de la 3.1 tine doar cat timp **si liniile reale** au `scutit=0` si `expltva` gol. Pe o
-factura scutita nu e asa:
-
-| camp din cheia `Group By` (`xmlefactura.prg:246`) | liniile reale (scutite) | pseudo-linia de discount de document |
-|---|---|---|
-| `id_jtva_coloana` | id real (ex. 11) | **0** — `prelucreaza_facturacrs` nu-l seteaza niciodata pe randul `ZZZZ` (`ofacturare_comun.prg:1891-1896`) |
-| `coloana_jv` (din `LEFT JOIN`) | `'WRSCDD'` | `.NULL.` — `cJTVAVanzariTemp` e incarcat cu `where afisat > 0 and id_jtva_coloana > 0` (`updateserver.prg:578`), deci **nu exista rand cu id 0** |
-| `scutit` | **1** | **0** |
-| `expltva` | `'Scutit cu drept de deducere'` | **gol** |
-
-Ultimul rand merita explicat, pentru ca e contraintuitiv: `completeaza_explicatie_tva`
-(`ofacturare_comun.prg:2077-2137`) chiar **include** pseudo-linia in lista de id-uri cautate — scanul
-de la `:2094` e `For proc_tva = 1 And Nvl(id_jtva_coloana,-1) <> -1`, iar pseudo-linia are
-`proc_tva = 1` (cota 0) si `id_jtva_coloana = 0`, deci trece filtrul. Dar interogarea de la `:2108`
-e `where id_jtva_coloana in (...)` pe `jtva_coloane`, unde id-ul 0 nu exista, asa ca `Replace expltva
-... For NVL(id_jtva_coloana,0) = m.lnIdJtva` (`:2129`) nu o atinge niciodata. Ramane goala.
-
-Doua campuri diferite din cinci => **doua grupuri**. XML-ul iese cu:
-
-```xml
-
- ... Discount
- 539.82
- Z0...
-
-0.00
- -539.82
- 0.00
- Z0...
- 4410.00
- 0.00
- E0
- Scutit cu drept de deducere...
-
-```
-
-Categoria `Z` a grupului orfan vine din `GetTipTaxa` ramura cu ramura (`xmlefactura.prg:1116-1140`):
-`intracomunitar=0` sare peste `'K'`, `taxare_inversa=0` sare peste `'AE'`, `scutit=0` sare peste
-`'E'`, si cade pe `Case m.lcTipFactura = 'F' And m.lnProcTva = 0` -> **`'Z'`** (`:1128-1129`).
-
-In plus, cautarea categoriei pentru `AllowanceCharge` (`xmlefactura.prg:782-786`) devine ambigua:
-`Select tip From C_TVA_FACTURA Where proc_tva = 0 Into Array agettipcota` gaseste acum **doua**
-randuri (`E` si `Z`), iar codul ia neconditionat `agettipcota(1)` — primul in ordinea cursorului, nu
-cel corect prin vreun criteriu. Ordinea nu e garantata de VFP si nu a fost fixata experimental;
-categoria alocarii poate iesi `E` sau `Z` dupa caz — oricare din ele e gresita ca modelare, doar in
-mod diferit.
-
-**Nu s-a reprodus scenariul end-to-end prin program** (ar fi cerut o factura scutita cu discount de
-document, iar in baza de dev nu exista — sectiunea 4.2). Ramane stabilit din citirea codului plus
-semantica `IIF`/NULL masurata la 3.1, nu dintr-o factura rulata efectiv prin program.
-
-### 3.3. Validare offline: XML-ul cu grup orfan nu e respins, dar controlul negativ functioneaza
-
-XML-urile de mai sus au fost construite pornind de la o factura reala acceptata de ANAF ca schelet
-si trecute prin validatorul local `DUKIntegrator.jar` (acelasi apel ca la 4.3):
-
-| scenariu | ce contine | rezultat |
-|---|---|---|
-| `scutit_bug` | scutit + discount de document, **cu grupul orfan** (ce produce codul azi) | **ok** |
-| `scutit_corect` | scutit + discount, un singur `TaxSubtotal` net (varianta corecta) | **ok** |
-| `control_stricat` | `TaxExclusiveAmount` stricat intentionat, ca martor ca validatorul chiar valideaza | **eroare `BR-CO-13` + `BR-CO-15`** |
-
-Controlul negativ conteaza: fara el, un „ok" pe `scutit_bug` n-ar dovedi nimic — ar putea insemna
-ca validatorul nu verifica deloc coerenta totalurilor. Cu el, e clar ca validatorul **chiar
-verifica**, si totusi trece grupul orfan.
-
-**De ce trece**: regulile EN16931 pe categorii (`BR-S-08`, `BR-E-08`, `BR-Z-08`) cer ca baza
-declarata pe o categorie sa fie egala cu *suma liniilor din acea categorie minus alocarile din
-aceeasi categorie*. Grupul orfan respecta asta trivial (`0 - 539.82 = -539.82`), iar grupul `E` la
-fel (`4410.00 - 0`). Aritmetica inchide; **modelarea fiscala e cea gresita**, si asta niciun
-schematron nu prinde.
-
-Aceeasi rezerva ca in 4.3: validatorul local e din ianuarie 2022 (`ro16931-ubl-1.0.8`); validatorul
-online curent al ANAF nu a fost apelat (interdictie explicita).
-
-> **Verdict sectiunea 3**: contopirea corecta descrisa mai sus e confirmata prin masuratoare pentru
-> factura obisnuita (3.1) si infirmata pentru factura scutita / taxare inversa / intracomunitara
-> (3.2), unde discountul de document formeaza un `TaxSubtotal` orfan cu baza negativa si categorie
-> ambigua (`E` sau `Z`). Pe niciuna din cele doua forme validatorul local nu respinge XML-ul (3.3,
-> si 4.3 pentru cazul cu cote mixte) — deci ramane, ca si defectul din sectiunea 4, o eroare
-> **tacuta**, nu una care blocheaza factura.
-
----
-
-## 4. Defect real sau gol de proiectare
-
-**Verdict: NU s-a putut dovedi un defect de VALIDARE — nici pe factura obisnuita, nici pe cea
-scutita cu grupul orfan (sectiunea 3.2-3.3), validatorul local nu respinge XML-ul. S-a dovedit in
-schimb un defect de ATRIBUIRE FISCALA: pe facturi cu cote mixte, tot TVA-ul discountului de
-document se scade din cota maxima, si pe facturi scutite/taxare inversa/intracomunitare, o
-modelare fiscala gresita (grup orfan) care trece neobservata.** Adica exact ce banuia Marius, dar
-consecinta stabilita nu e "factura respinsa", ci "TVA colectat gresit sau baza modelata gresit,
-tacut".
-
-> **Nuanta ramasa, dupa inchiderea ipotezei din sectiunea 3**: ipoteza grupului orfan **s-a
-> confirmat** pentru facturile scutite/taxare inversa/intracomunitare (3.2), dar validatorul local
-> **nu** o respinge (3.3) — deci nu devine, cum s-ar fi putut anticipa, un defect de validare
-> propriu-zis, ci ramane in aceeasi categorie cu restul sectiunii 4: o eroare de modelare care nu
-> blocheaza factura. Testele din 4.3 (cote mixte) si cele din 3.3 (factura scutita) acopera acum
-> ambele forme.
-
-### 4.1. Dovada ca mecanismul chiar produce `AllowanceCharge` de document in productie
-
-Am cautat in cele ~250 de XML-uri eFactura salvate pe disc (`D:\ROA\Efactura`, `D:\ROA\ROAEFACTURA`,
-`D:\ROA\ROAFACTURARE\Utile\efactura`) blocurile `cac:AllowanceCharge` care contin `cac:TaxCategory`
-(marca alocarii **de document**; cele de linie nu au `TaxCategory`, au `MultiplierFactorNumeric`).
-Exemple reale:
-
-| fisier | Amount | TaxCategory | Percent |
-|---|---|---|---|
-| `D:\ROA\Efactura\2024_01\VENDING_MASTER_SRL\efactura_20240125_1526_BEST_POWER_DANCE_S_R_L_.xml` | 13.84 / 25.02 (doua) | S / S | 9 / 19 |
-| `D:\ROA\Efactura\2024_02\VENDING_MASTER_SRL\efactura_20240216_2885_IT_BUL_PLAST_LTD.xml` | 539.82 | E | 0 |
-| `D:\ROA\Efactura\2024_03\VENDING_MASTER_SRL\efactura_20240301_3736_BRIANA_ALIMENT_SRL.xml` | 411.01 | S | 9 |
-| `D:\ROA\Efactura\2024_07\VENDING_MASTER_SRL\efactura_20240426_7446_CIA_TRADE_POSSIBLE_SRL.xml` | 176.15 | S | 9 |
-
-Forma emisa (exemplu real, `...2885...`):
-```xml
-false
- 95
- Discount
- 539.82
- E0
- VAT
-```
-
-**Precizare de onestitate**: niciunul dintre aceste patru nu pot sa-l atribui sigur discountului de
-**document**. Dimpotriva — la `...7446...` factura are linii pe 9% (2016.51) si pe 19% (1477.11),
-iar unica alocare cade pe **9%**; daca ar fi fost discount de document, `Max(proc_tvav)` ar fi dat
-**19%**. Deci acolo sunt discounturi **pe linie** cu `discount_evidentiat = 1` (sectiunea 1.4). La
-fel `...1526...`, unde cele doua alocari sunt exact 2.00% din baza fiecarei cote. **Nu am gasit pe
-disc un XML in care sa pot identifica pozitiv un discount de document.** Ce dovedesc aceste fisiere
-e ca **traseul cod -> `AllowanceCharge` cu `TaxCategory` chiar functioneaza in productie** si ca
-gruparea pe cote e reala cand exista mai multe pseudo-linii de discount.
-
-**Al treilea indiciu, pe acelasi fisier `...2885...`, in sens invers.** Factura e integral **scutita
-cu drept de deducere**: toate cele trei linii sunt `E` / `Percent 0` cu `TaxExemptionReason =
-"Scutit cu drept de deducere"`, `DocumentCurrencyCode = EUR`, si are `AllowanceCharge` la nivel de
-document de 539.82 cu `TaxCategory ID = E`. Are **un singur `TaxSubtotal`**: `TaxableAmount =
-3870.18`, adica exact `4410.00 − 539.82` — **net de discount, fara grup orfan**.
-
-Asta e semnificativ dupa sectiunea 3.2: `expltva` face parte din cheia de grupare, iar grupul unic
-de aici poarta `TaxExemptionReason` completat. Daca pseudo-linia de discount ar fi avut `expltva`
-gol si `id_jtva_coloana = 0` (cazul discountului de **document**, descris la 3.2), gruparea nu s-ar
-fi putut contopi — ar fi iesit doua grupuri, ca in `scutit_bug` (3.3). Contopirea observata aici
-dovedeste deci ca pseudo-linia purta un `id_jtva_coloana` real, adica era un discount **pe linie**
-(`discount_evidentiat = 1`), nu de document — un al treilea indiciu, independent de cele doua de mai
-sus (alocare pe cota minima la `...7446...`; doua alocari la `...1526...`), care coroboreaza aceeasi
-concluzie: cele patru XML-uri de productie gasite sunt discounturi pe linie, nu de document.
-
-Fisierul arata insa **pozitiv forma corecta** pentru o factura scutita cu discount de document: cand
-pseudo-linia poarta `id_jtva_coloana` corect, grupul iese unul singur si net — exact forma
-recomandata la sectiunea 6, punctul 1. Deci recomandarea are un precedent real in productie, nu doar
-o constructie sintetica de test. **Rezerva onesta**: fisierul e din februarie 2024, iar inferenta
-presupune ca traseul de cod e neschimbat de atunci; ramane adevarat ca **nu exista niciun XML de
-productie identificat pozitiv ca discount de DOCUMENT**.
-
-**Identitatea fisierului, verificata pe SHA256.**
-`D:\ROA\Efactura\2024_02\VENDING_MASTER_SRL\efactura_20240216_2885_IT_BUL_PLAST_LTD.xml` (5922
-octeti) are acelasi SHA256 (`3303AFE34BC9E3E84DA9B3527C435DD9B8CB0BC7881D7D2F660A250237E23C64`) cu
-`4172939206.xml` din `...\TRIMISE\4172939206_3250292036.zip` — deci e exact ce a plecat la ANAF, si
-a fost **acceptat**. Continutul din `...\ERORI\4172675286_3249814520.zip` e un mesaj de eroare de
-446 octeti pentru o incarcare **anterioara**, cu alt index de incarcare, si listeaza exact doua
-reguli: `BR-CO-15` si `BR-CL-04` (cod de moneda invalid). Deci respingerea aceea **nu** e a
-fisierului cu `currencyID="RON"` discutat la sectiunea 2.3 — acela a trecut.
-
-### 4.2. Datele din baza de dev — putine, dar arata ca situatia e posibila
-
-`MARIUSM_AUTO@ROA_CENTRAL`, doar `SELECT`:
-- facturi nesterse cu `VANZARI.DISCOUNT <> 0`: **3** (id_vanzare 165 / 575 / 576;
- `discount_evidentiat` = 1 / 1 / 0). Toate trei au **o singura cota** pe linii (1.19, 1.24, 1.24).
-- facturi nesterse cu **cote mixte** pe linii: **34**.
-
-Deci in dev nu exista intersectia "discount de document + cote mixte". **Asta nu dovedeste nimic** —
-volumele de dev sunt mici, iar ambele ingrediente exista separat. In productie combinatia e banala
-(orice comerciant cu alimente 9%/11% + nealimentare 21% care da un discount global).
-
-### 4.3. Ce am testat efectiv cu validatorul ANAF, offline
-
-Am folosit **validatorul local** `D:\ROA\COMUNROA\dist_efactura\DUKIntegrator.jar` (`-v FACT1`,
-reguli `ro16931-ubl-1.0.8`), acelasi pe care il apeleaza `xmlefactura.prg:1166-1194`. **Nu s-a
-trimis nimic catre ANAF; nu s-a apelat niciun serviciu web.** XML-urile de test sunt in
-`%TEMP%\claude\...\scratchpad\` (base/scenA/scenB/scenC_*), construite plecand de la un XML real
-valid.
-
-| test | ce contine | rezultat |
-|---|---|---|
-| `base` | XML-ul real `...7446...`, nemodificat (martor) | **ok** |
-| `scenA` | cote mixte 21% + 11%, discount 200 lei atribuit **integral** cotei 21% (exact ce genereaza programul) | **ok** |
-| `scenB` | 100 lei @21% + 5000 lei scutit, discount 510 lei la 21% -> `TaxableAmount = -410.00`, `TaxAmount = -86.10` | **ok** |
-| `scenC_corect` | acelasi ca scenA, in EUR, cu `AllowanceCharge/Amount currencyID="EUR"` | **ok** |
-| `scenC_bug` | idem, dar cu `currencyID="RON"` pe alocare (ce face codul la `:778`) | **ok** |
-
-**Concluzii, inclusiv cele care imi infirma ipotezele:**
-1. Atribuirea intregului discount cotei maxime **trece validarea** — deci nu e o eroare pe care ANAF
- sa o prinda. E o eroare **tacuta**.
-2. Ipoteza mea ca o `TaxableAmount` **negativa** ar fi respinsa e **infirmata** de validatorul local.
-3. Ipoteza ca neconcordanta de moneda (`currencyID="RON"` pe factura in EUR) ar fi respinsa e tot
- **infirmata** de validatorul local.
-4. **Rezerva**: validatorul instalat e din **ianuarie 2022** (`DUKIntegrator.jar`, 19.01.2022,
- reguli 1.0.8). Regulile ANAF s-au inasprit de atunci. Punctele 2 si 3 raman "neinfirmate de
- validatorul disponibil local", nu "garantat acceptate azi de ANAF".
-
-### 4.4. Scenariul reproductibil al defectului REAL (fiscal)
-
-**Factura**: client intern, in lei, `discount_evidentiat = 0`.
-- Linia 1: marfa cota standard, 1 buc x 1000.00 lei, **21%**
-- Linia 2: marfa cota redusa, 1 buc x 1000.00 lei, **11%**
-- Discount de document: **10%** -> `VANZARI.DISCOUNT = 200.00`
-
-**Ce face programul**:
-- `Max(proc_tvav)` = 1.21 -> pseudo-linia de discount primeste **21%**
- (`oproceduri_facturare.prg:1387` / `ofacturare_comun.vc2:4495`)
-- `valdiscounttva = Round(200 * 0.21, 2) = 42.00` (`ofacturare_comun.prg:1893`)
-
-**Ce iese in XML** (verificat ca valid — `scenA`):
-```
-AllowanceCharge: Amount 200.00, TaxCategory S, Percent 21
-TaxSubtotal S/21: TaxableAmount 800.00 TaxAmount 168.00
-TaxSubtotal S/11: TaxableAmount 1000.00 TaxAmount 110.00
-TaxAmount total 278.00 ; LineExtension 2000.00 ; TaxExclusive 1800.00 ; TaxInclusive 2078.00
-```
-
-**Ce ar fi trebuit** (discount repartizat proportional cu baza: 100 lei pe fiecare cota):
-```
-AllowanceCharge #1: 100.00, S, 21 AllowanceCharge #2: 100.00, S, 11
-TaxSubtotal S/21: 900.00 / 189.00
-TaxSubtotal S/11: 900.00 / 99.00
-TaxAmount total 288.00 ; TaxInclusive 2088.00
-```
-
-**Diferenta: 10.00 lei TVA colectat in minus**, adica 5% din TVA-ul facturii — si creste cu ecartul
-dintre cote si cu marimea discountului. **Sensul e mereu acelasi**: cota maxima absoarbe tot
-discountul, deci TVA-ul declarat e **prea mic**. Riscul e al emitentului (TVA colectat
-subdeclarat), nu al ANAF-ului care respinge documentul. Aceeasi valoare gresita ajunge si in nota
-contabila si in jurnalul de TVA, pentru ca `valdiscounttva` e acelasi camp.
-
-**Caz-limita, tot valid dupa validator dar clar absurd** (`scenB`): factura cu 100 lei la 21% si
-5000 lei scutit, discount de document 10% (510 lei). Tot discountul intra pe cota 21%, unde baza e
-100 lei -> `TaxSubtotal S/21` iese cu `TaxableAmount = -410.00` si `TaxAmount = -86.10`. Factura
-declara **TVA negativ** pe o livrare normala. Nu e nevoie de cote diferite de zero pe ambele parti:
-ajunge o factura in care liniile de la cota maxima sunt o mica parte din total.
-
-### 4.5. Gol de proiectare, distinct de defect
-
-**Explicatia ("reason") nu exista ca notiune in program.** In XML `AllowanceChargeReason` e literalul
-`"Discount"` si `ReasonCode` e `"95"`, ambele hardcodate (`xmlefactura.prg:774-776`). Textul construit
-in VFP — `"Discount 10.00 % Factura"` (`ofacturare_comun.prg:1370`) — **nu ajunge in XML**. Nu exista
-nicio coloana pe `VANZARI` pentru motivul discountului si niciun control in formular. Deci raspunsul
-la a doua jumatate a intrebarii lui Marius: **nu, discountul de document nu are azi explicatie —
-are o constanta.**
-
----
-
-## 5. Recomandare pentru formularul unificat (#13)
-
-**Sa NU ceara utilizatorului cota. Sa sparga discountul automat, proportional cu baza fiecarei cote,
-si sa expuna doar un camp optional de motiv.** Argumentul e ca discountul de document nu *are* o cota
-proprie de ales: prin definitie e un procent aplicat bazei intregii facturi (`lnTotalBaza =
-Sum(valdiminuatftva)` peste toate liniile, `ofacturare_comun.prg:1888`), deci natura lui de TVA e
-determinata de liniile pe care le reduce, nu de o optiune. A pune operatorul sa aleaga o cota inseamna
-a-i cere sa ia o decizie fiscala pe care datele o dau deja, si a deschide o a doua cale de a gresi —
-azi `Max()` greseste consecvent, un camp liber ar greseste imprevizibil. Repartizarea proportionala e
-si singura care satisface modelul EN16931, unde `TaxableAmount`-ul fiecarei categorii se calculeaza ca
-*net de linii al categoriei minus alocarile de document ale aceleiasi categorii*. **Costul de
-implementare e mic, dar atinge doua locuri, nu unul** (sectiunea 1.5): `prelucreaza_facturacrs`
-(`ofacturare_comun.prg:1886-1897`) trebuie sa insereze cate un rand-sentinela **per cota** in loc de
-unul singur, cu `tnDiscount` repartizat pe baza fiecarei cote (ultima cota preia diferenta de
-rotunjire, ca suma sa fie exact `VANZARI.DISCOUNT`), **si** `recalculeaza_totaluri_vanzari`
-(`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16081-16092`) trebuie sa inlocuiasca `MAX(...)` cu suma
-repartizarii, altfel `VANZARI.TOTAL_TVA` ramane pe regula veche si diverge de XML; **eFactura nu are
-nevoie de nicio modificare structurala** —
-`xmlefactura.prg:758-792` grupeaza deja `GROUP BY proc_tva` si emite cate un `AllowanceCharge` per
-cota, iar `C_TVA_FACTURA` include deja pseudo-liniile in `TaxSubtotal`. Doua consecinte de decis
-explicit cu Marius: **factura tiparita** va arata N randuri "Discount X % Factura" in loc de unul (pe
-cote mixte), si **nota contabila** primeste TVA-ul discountului spart pe cote. Pentru "explicatie",
-recomand un singur camp text optional pe document, folosit ca `AllowanceChargeReason` in locul
-constantei `"Discount"` (`ReasonCode` ramane `95`) — util si pe hartie, si e singura bucata care chiar
-cere UI nou.
-
-**Precizare, dupa sectiunea 3.2**: "eFactura nu are nevoie de modificare" e adevarat doar daca
-fiecare pseudo-linie noua, per cota, primeste si `id_jtva_coloana` **al grupului pe care il reduce**,
-nu doar `proc_tva` al lui. Cota singura nu ajunge — cheia de grupare din `xmlefactura.prg:246` are
-cinci campuri, iar `expltva` se completeaza tot prin `id_jtva_coloana` (sectiunea 3.2). O
-implementare care seteaza doar `proc_tva` pe randul-sentinela ar lasa grupul orfan exact acolo unde
-e azi, pe facturile scutite / cu taxare inversa / intracomunitare. Fisierul `...2885...` de la
-sectiunea 4.1 e dovada pozitiva ca, atunci cand `id_jtva_coloana` e setat corect, forma iese unul
-singur si net — deci reparatia are deja un precedent real in productie, nu doar o constructie de
-test.
-
----
-
-## Verificat direct vs. dedus
-
-**Verificat direct (citit in cod, cu `fisier:linie`)**
-- randul-sentinela `ZZZZ` si campurile lui — `ofacturare_comun.prg:1886-1897`
-- transformarea in pseudo-linia `"Discount % Factura"` — `ofacturare_comun.prg:1361-1392`
-- `Max(proc_tvav)` pe toate cele patru cai de apel — `oproceduri_facturare.prg:1387`,
- `ofacturare_comun.vc2:4495` si `:7294`, `ofacturare_stoc.prg:582`
-- a doua implementare a aceleiasi reguli, in PL/SQL, si campurile pe care le scrie —
- `ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16024` (procedura), `:16081-16092` (`MAX(...)`),
- `:16049-16062` (`TOTAL_TVA`/`TOTAL_CU_TVA` derivate din el), `:16214-16227` (`update vanzari`)
-- euristica de detectie in eFactura — `xmlefactura.prg:230`
-- generarea `AllowanceCharge` de document, cu `GROUP BY proc_tva` — `xmlefactura.prg:756-795`
-- sursa lui `TaxCategory/ID` (`GetTipTaxa`, `xmlefactura.prg:1103-1143`) si a lui `Percent`
-- includerea pseudo-liniei in `C_TVA_FACTURA` -> `TaxSubtotal` — `xmlefactura.prg:242-248, 822-851`
-- inchiderea totalurilor `LegalMonetaryTotal` — `xmlefactura.prg:863-898`
-- ca generatorul viu e `xmlefactura.prg`, nu `anaf_efactura` — `oexport.prg:1586-1594`,
- `ofacturare.prg:2107-2126`
-- ca ramura "pret cu TVA" (unde pseudo-linia iese cu `valftva = 0`) nu poate ajunge in eFactura —
- `ofacturare.prg:1112, 1856-1861` + filtrul `tip_doc_394` din `xmlefactura.prg:276-279`
-- semantica `LEFT JOIN` + `IIF`/`INLIST` peste `.NULL.` in cheia de grupare (sectiunea 3.1/3.2) —
- `xmlefactura.prg:226-248`
-- de ce grupul orfan nu poate fi completat prin `completeaza_explicatie_tva` — filtrul de scan vs.
- filtrul de update (`ofacturare_comun.prg:2094` vs. `:2108, 2129`, sectiunea 3.2)
-- sursa categoriei `Z` a grupului orfan, ramura cu ramura in `GetTipTaxa` — `xmlefactura.prg:1116-1140`
- (sectiunea 3.2)
-- incarcarea `cJTVAVanzariTemp` doar cu `id_jtva_coloana > 0`, motivul pentru care randul 0 nu se
- gaseste — `updateserver.prg:578` (sectiunea 3.2)
-
-**Verificat prin rulare**
-- 4 XML-uri reale de productie cu `AllowanceCharge` de document (sectiunea 4.1)
-- 3 facturi cu discount in baza de dev, 34 cu cote mixte (`SELECT`, sectiunea 4.2)
-- 5 validari DUKIntegrator offline pe cote mixte (sectiunea 4.3) — **au infirmat doua dintre
- ipotezele initiale**
-- semantica `IIF()` peste `.NULL.` masurata cu o sonda headless (`probe_null.prg`, sectiunea 3.1) —
- intoarce ramura falsa, nu `.NULL.`
-- 3 validari DUKIntegrator offline pe scenariul grupului orfan (`scutit_bug`, `scutit_corect`,
- plus `control_stricat` ca martor negativ, sectiunea 3.3) — grupul orfan **nu** e respins
-- identitatea SHA256 a XML-ului EUR de productie fata de fisierul chiar trimis la ANAF, si citirea
- celor doua zip-uri (`TRIMISE`/`ERORI`) care arata ca respingerea gasita e a unei incarcari
- anterioare, pentru alte reguli (sectiunea 4.1)
-
-**Dedus, NEverificat prin rulare**
-- calculul numeric din scenariul 4.4 (aritmetica pe formulele citite, nu o factura rulata efectiv
- prin program)
-- riscul `agettipcota(1)` fara garda pe `_Tally` (`xmlefactura.prg:782-786`) — n-am reusit sa-l
- provoc si nu-l afirm ca defect
-- ce se intampla in nota contabila / jurnalul de TVA cu `valdiscounttva` — am dedus din faptul ca e
- acelasi camp, n-am urmarit consumatorii
-- scenariul "factura scutita + discount de document" **end-to-end prin program** (sectiunea 3.2):
- gruparea separata e stabilita din cod + semantica `IIF`/NULL masurata, nu dintr-o factura reala
- rulata prin program — in baza de dev nu exista intersectia (sectiunea 4.2)
-- ordinea randurilor in `C_TVA_FACTURA` dupa `GROUP BY` (deci daca `agettipcota(1)` alege `E` sau
- `Z` in cazul grupului orfan) — nu e garantata de VFP si nu a fost fixata experimental
-
-**Neacoperit — si stiut ca neacoperit**
-- daca `VANZARI.TOTAL_TVA` (Oracle, sectiunea 1.5) si TVA-ul din XML sunt confruntate undeva si care
- primeaza — am constatat doar ca ambele exista si folosesc aceeasi regula
-- daca un discount de document **negativ** e posibil din UI (ar inversa `MAX`-ul din Oracle, 1.5)
-- calea in **valuta** (`crsfacturafinalaval` / `prelucreaza_factura_valuta`,
- `ofacturare_comun.prg:1540+`) — am presupus simetrie cu cea in lei pe baza campurilor `v*`
- paralele de la `:1894-1895`, n-am parcurs-o linie cu linie
-- daca `Max(proc_tvav)` e cota corecta si pentru **proforme** in vreun sens special
-- comportamentul validatorului ANAF **curent** (cel local e din 2022, atat pentru cote mixte cat si
- pentru grupul orfan)
-
----
-
-## Intrebari ramase pentru Marius
-
-1. **Repartizarea proportionala se aplica retroactiv la relistare?** O factura veche relistata sau
- retrimisa in eFactura ar genera alt XML decat cel trimis initial. Se accepta, sau noul
- comportament se leaga de o data / de un flag?
-2. **Pe factura tiparita**: e in regula sa apara N randuri "Discount X % Factura" (unul pe cota), sau
- vrei un singur rand vizibil si spargerea doar in XML / nota contabila?
-3. **Rotunjirea**: pe cine cade diferenta de rotunjire cand discountul nu se imparte exact
- (ex. 100 lei pe trei cote)? Propunerea mea: pe cota cu baza cea mai mare.
-4. **Discountul care depaseste baza unei cote** (cazul din 4.4, factura majoritar scutita): dupa
- repartizarea proportionala problema dispare de la sine — confirmi ca nu mai e nevoie de nicio
- garda separata?
-5. **Campul de motiv**: il vrei per document (un singur text), sau e suficient sa ramana constanta
- `"Discount"` si sa nu adaugam UI?
-6. **`discount_evidentiat`**: mai e folosit in productie? Schimba semnificativ ce se tipareste
- (sectiunea 1.4) si e a doua sursa de pseudo-linii "Discount" in XML.
-7. **Cele doua implementari ale regulii** (VFP + Oracle, sectiunea 1.5): se schimba amandoua in
- aceeasi livrare, sau Oracle ramane pe regula veche o vreme? Daca raman desincronizate,
- `VANZARI.TOTAL_TVA` si TVA-ul din eFactura vor diferi pe facturile cu cote mixte si discount.
-8. **Discount de document negativ** (majorare): e posibil din UI? Daca da, `MAX`-ul din Oracle alege
- cota cea mai **mica**, iar `Max(proc_tvav)` din VFP tot pe cea mai mare — adica cele doua
- implementari ar diverge deja azi, inainte de orice modificare.
-
diff --git a/docs/cercetare/discount_document_cota_tva_b.md b/docs/cercetare/discount_document_cota_tva_b.md
deleted file mode 100644
index 10dece3..0000000
--- a/docs/cercetare/discount_document_cota_tva_b.md
+++ /dev/null
@@ -1,189 +0,0 @@
-# Supliment: gruparea pseudo-liniei de discount in `C_TVA_FACTURA`
-
-Completare la `discount_document_cota_tva.md`, scrisa de al doilea agent pe aceeasi intrebare.
-**Nu repeta** raportul principal — acopera exact punctul pe care acela il lasa deschis la finalul
-sectiunii 3 („ipoteza gruparii separate — nu am atins-o deloc, o verifica alt agent"), plus doua
-verificari prin rulare pe care raportul principal nu le are.
-
-Cercetare read-only: niciun fisier de cod atins, zero write-back, pe Oracle numai `SELECT`, niciun
-apel catre ANAF (validarea s-a facut **offline**, cu DUKIntegrator din `D:\ROA\COMUNROA\dist_efactura`).
-
-## Verdict in 5 randuri
-
-Ipoteza pe care o ridicasem — ca pseudo-linia de discount de document, avand `id_jtva_coloana = 0`,
-iese din `LEFT JOIN` cu `coloana_jv` NULL si formeaza propriul grup in `C_TVA_FACTURA`, cu
-`TaxableAmount` negativ — este **infirmata pentru factura obisnuita** si **confirmata pentru factura
-scutita / cu taxare inversa / intracomunitara**. In al doilea caz XML-ul chiar iese cu doua
-`TaxSubtotal`-uri pe cota 0, unul cu baza negativa si categoria `Z`. **Dar validatorul nu-l
-respinge** — l-am rulat. Deci: comportament gresit ca modelare, nu defect care blocheaza factura.
-
----
-
-## 1. Ce am masurat, nu dedus: `IIF()` peste NULL in VFP
-
-Toata ipoteza atarna de o singura intrebare: ce intoarce `Iif(Left(.Null.,2) = 'CE', 1, 0)`. Daca ar
-intoarce `.NULL.`, cheia de grupare a pseudo-liniei ar diferi de a liniilor reale si gruparea s-ar
-rupe pe **orice** factura.
-
-Am rulat o sonda headless (`vfp9.exe -A -T`) care reproduce exact `LEFT JOIN`-ul si `GROUP BY`-ul din
-`xmlefactura.prg:226-248`, cu o pseudo-linie de discount pe `id_jtva_coloana = 0`:
-
-```
-1) IIF(.NULL.="CE",1,0) -> tip=N isnull=.F.
-2) IIF(LEFT(.NULL.,2)="CE",1,0) -> tip=N isnull=.F.
-3) IIF(INLIST(.NULL.,...),1,0) -> tip=N isnull=.F.
- linie=ARTICOL A | coloana_jv nul=.F. | intracom=0 | scutit=0
- linie=ARTICOL B | coloana_jv nul=.F. | intracom=0 | scutit=0
- linie=Discount 10.00 % Factura | coloana_jv nul=.T. | intracom=0 | scutit=0
-4) grupuri in C_TVA_FACTURA = 1
- grup: cota=21 baza=1350 tva=283.50 (1500 - 150, corect)
-```
-
-**`IIF()` intoarce ramura falsa, nu `.NULL.`**, chiar daca conditia e nula. Deci pe o factura
-interna obisnuita pseudo-linia primeste `intracomunitar=0, taxare_inversa=0, scutit=0` — exact ca
-liniile reale — si **se contopeste in grupul cotei maxime**. Sectiunile 3 si 4 din raportul principal
-raman valabile.
-
-Sonda: `...\scratchpad\probe_null.prg`. Nu depinde de baza de date si se poate reface oricand.
-
-## 2. Unde ipoteza se confirma totusi: facturile scutite / taxare inversa / intracomunitare
-
-Egalitatea de mai sus tine doar cat timp **si liniile reale** au `scutit=0` si `expltva` gol. Pe o
-factura scutita nu e asa:
-
-| camp din cheia `Group By` (`xmlefactura.prg:246`) | liniile reale (scutite) | pseudo-linia de discount de document |
-|---|---|---|
-| `id_jtva_coloana` | id real (ex. 11) | **0** — `prelucreaza_facturacrs` nu-l seteaza niciodata pe randul `ZZZZ` (`ofacturare_comun.prg:1891-1896`) |
-| `coloana_jv` (din `LEFT JOIN`) | `'WRSCDD'` | `.NULL.` — `cJTVAVanzariTemp` e incarcat cu `where afisat > 0 and id_jtva_coloana > 0` (`updateserver.prg:578`), deci **nu exista rand cu id 0** |
-| `scutit` | **1** | **0** |
-| `expltva` | `'Scutit cu drept de deducere'` | **gol** |
-
-Ultimul rand merita explicat, pentru ca e contraintuitiv: `completeaza_explicatie_tva`
-(`ofacturare_comun.prg:2077-2137`) chiar **include** pseudo-linia in lista de id-uri cautate — scanul
-de la `:2094` e `For proc_tva = 1 And Nvl(id_jtva_coloana,-1) <> -1`, iar pseudo-linia are
-`proc_tva = 1` (cota 0) si `id_jtva_coloana = 0`, deci trece filtrul. Dar interogarea de la `:2108`
-e `where id_jtva_coloana in (...)` pe `jtva_coloane`, unde id-ul 0 nu exista, asa ca `Replace expltva
-... For NVL(id_jtva_coloana,0) = m.lnIdJtva` (`:2129`) nu o atinge niciodata. Ramane goala.
-
-Doua campuri diferite din cinci => **doua grupuri**. XML-ul iese cu:
-
-```xml
-
- ... Discount
- 539.82
- Z0...
-
-0.00
- -539.82
- 0.00
- Z0...
- 4410.00
- 0.00
- E0
- Scutit cu drept de deducere...
-
-```
-
-Categoria `Z` a grupului orfan vine din `GetTipTaxa` ramura cu ramura (`xmlefactura.prg:1116-1140`):
-`intracomunitar=0` sare peste `'K'`, `taxare_inversa=0` sare peste `'AE'`, `scutit=0` sare peste
-`'E'`, si cade pe `Case m.lcTipFactura = 'F' And m.lnProcTva = 0` -> **`'Z'`** (`:1128-1129`).
-
-In plus, cautarea categoriei pentru `AllowanceCharge` (`xmlefactura.prg:782-786`) devine ambigua:
-`Select tip From C_TVA_FACTURA Where proc_tva = 0 Into Array agettipcota` gaseste acum **doua**
-randuri (`E` si `Z`), iar codul ia neconditionat `agettipcota(1)` — primul in ordinea cursorului, nu
-cel corect prin vreun criteriu.
-
-**Nu am reprodus scenariul end-to-end prin program** (ar fi cerut o factura scutita cu discount de
-document, si in baza de dev nu exista — vezi punctul 4). Il stabilesc din citirea codului plus
-semantica `IIF`/NULL masurata la punctul 1.
-
-## 3. Validare offline: XML-ul gresit **nu** e respins
-
-Am construit XML-urile si le-am trecut prin DUKIntegrator
-(`java -jar DUKIntegrator.jar -c -v FACT1 `, exact apelul din
-`xmlefactura.prg:1192`), pornind de la o factura reala acceptata de ANAF ca schelet:
-
-| scenariu | fisier | rezultat |
-|---|---|---|
-| scutit + discount de document, **cu grupul orfan** (ce produce codul azi) | `scutit_bug.xml` | **ok** |
-| scutit + discount, un singur `TaxSubtotal` net (varianta corecta) | `scutit_corect.xml` | **ok** |
-| cote mixte 21%+11%, tot discountul pe 21% (ce produce codul azi) | `mixt_azi.xml` | **ok** |
-| cote mixte 21%+11%, discount repartizat proportional | `mixt_proportional.xml` | **ok** |
-| discount mai mare decat baza cotei maxime -> `TaxableAmount = -400.00` si `TaxAmount = -84.00` pe grupul 21% | `mixt_baza_negativa.xml` | **ok** |
-| **control negativ**: `TaxExclusiveAmount` stricat intentionat | `control_stricat.xml` | **eroare BR-CO-13 + BR-CO-15** |
-
-Controlul negativ conteaza: fara el, cele cinci „ok" n-ar dovedi nimic. Validatorul chiar valideaza.
-
-**De ce trec**: regulile EN16931 pe categorii (BR-S-08, BR-E-08, BR-Z-08) cer ca baza declarata pe o
-categorie sa fie egala cu *suma liniilor din acea categorie minus alocarile din aceeasi categorie*.
-Grupul orfan respecta asta trivial (`0 - 539.82 = -539.82`), iar grupul `E` la fel (`4410.00 - 0`).
-Aritmetica inchide; **modelarea fiscala e cea gresita**, si asta niciun schematron nu prinde.
-
-Avertisment onest: validatorul local e din 2022 (`ro16931-ubl-1.0.8`, jar-ul din ianuarie 2022).
-Validatorul online curent al ANAF poate fi mai strict. **Nu l-am apelat** — interdictie explicita.
-
-## 4. De ce nu am putut proba pe date reale
-
-- In baza accesibila (`MARIUSM_AUTO@ROA_CENTRAL`) exista **3** facturi cu discount de document, toate
- cu **o singura cota** si toate anterioare eFacturii (2008, 2014 x2), niciuna cu `efactura = 1`.
- Separat exista 34 de facturi cu cote mixte, dar **niciuna** cu discount de document. Deci
- intersectia care ne intereseaza e goala.
- **Asta nu inseamna ca nu apare in productie** — baza de dev are 712 facturi in total.
-- Cele 4 XML-uri de productie cu `AllowanceCharge` de document pe care le-am examinat sunt, dupa
- toate semnele, **discounturi pe linie** cu `discount_evidentiat = 1`, nu discounturi de document:
- cel de la `2024_07\...CIA_TRADE_POSSIBLE` are cote 9% si 19%, iar alocarea unica e pe **9%** —
- adica pe cota **minima**, ceea ce regula `Max(proc_tvav)` nu poate produce; iar
- cel de la `2024_01\...BEST_POWER_DANCE` are **doua** alocari (9% si 19%), ceea ce discountul de
- document, fiind o singura pseudo-linie, nu poate produce nici el.
- Nu am gasit niciun XML de productie care sa fie sigur discount de **document**.
-- Firmele din `D:\ROA\Efactura` (VENDING_MASTER, CLEVER_MOTORS, ...) nu au scheme in baza accesibila
- (`select ... from all_users` — zero potriviri), deci nu am putut confrunta XML-ul cu antetul lui.
-
-## 5. Un lucru dovedit pe un fisier real, nu dedus
-
-Pe `D:\ROA\Efactura\2024_02\VENDING_MASTER_SRL\efactura_20240216_2885_IT_BUL_PLAST_LTD.xml`:
-
-```
-BT-5 DocumentCurrencyCode = EUR
- ... 539.82
-539.82
-```
-
-Aceeasi suma apare o data ca `RON` si o data ca `EUR` — `currencyID` e hardcodat `"RON"` la
-`xmlefactura.prg:778`, in timp ce restul documentului foloseste `mmoneda`. Doua precizari care
-schimba interpretarea:
-
-- fisierul de pe disc este **identic pe SHA256** cu cel din
- `...\TRIMISE\4172939206_3250292036.zip`, deci e exact ce a plecat la ANAF;
-- si a fost **acceptat**. Respingerea din `...\ERORI\4172675286_3249814520.zip` e a unei incarcari
- *anterioare* si e pentru alte doua reguli (`BR-CO-15` si `BR-CL-04` — cod de moneda invalid,
- probabil `EURO` in loc de `EUR`, ceea ce explica linia de corectie `xmlefactura.prg:267`).
-
-Deci `currencyID="RON"` pe factura in valuta e o **neconformitate reala si activa in cod azi**, dar
-nu am dovada ca ar cauza o respingere.
-
-## 6. Ce inseamna pentru #13
-
-Repartizarea proportionala pe cote — recomandarea din raportul principal — **rezolva si problema de
-aici**, fara nicio garda in plus: daca discountul se sparge pe cotele care exista efectiv pe factura,
-fiecare bucata mosteneste `id_jtva_coloana` si `expltva` ale grupului ei, grupul orfan dispare, iar
-`agettipcota(1)` nu mai poate fi ambiguu. Subscriu, cu doua completari:
-
-1. **Pseudo-liniile de discount trebuie sa primeasca `id_jtva_coloana` al grupului pe care il reduc**,
- nu doar cota. Cota singura nu ajunge — cheia de grupare are cinci campuri, iar `expltva` se
- completeaza tot prin `id_jtva_coloana`. O implementare care seteaza doar `proc_tva` ar lasa
- grupul orfan exact acolo unde e azi.
-2. **Regula traieste in doua locuri** — VFP (`Calculate Max(proc_tvav)`) si PL/SQL
- (`MAX(ROUND(discount * (proc_tvav - 1), ...))` in `recalculeaza_totaluri_vanzari`). Daca se
- schimba doar una, `VANZARI.TOTAL_TVA` si TVA-ul din XML vor diferi pe facturile cu cote mixte.
-
-## 7. Ce ramane deschis
-
-- Scenariul de la punctul 2 **nu e reprodus prin program**, ci dedus din cod + semantica `IIF`
- masurata. O confirmare ar cere o factura scutita cu discount de document, introdusa manual.
-- Ordinea randurilor in `C_TVA_FACTURA` dupa `GROUP BY` (deci ce alege `agettipcota(1)` intre `E` si
- `Z`) nu e garantata de VFP si nu am fixat-o experimental. Am presupus `scutit=0` inaintea lui
- `scutit=1`; daca e invers, categoria alocarii iese `E` in loc de `Z` — tot gresita, dar altfel.
-- Validatorul ANAF **online** curent nu a fost testat (interdictie). Tot ce spun despre „nu e
- respins" se refera la DUKIntegrator 2022 de pe disc.
-- Nu am verificat calea in **valuta** (`prelucreaza_factura_valuta`) linie cu linie.
diff --git a/docs/cercetare/discount_in_rapoarte_si_efactura.md b/docs/cercetare/discount_in_rapoarte_si_efactura.md
deleted file mode 100644
index dd63570..0000000
--- a/docs/cercetare/discount_in_rapoarte_si_efactura.md
+++ /dev/null
@@ -1,216 +0,0 @@
-# Discount pe linie (DISCOUNT_UNITAR) in afara formularului de facturare — rapoarte .frx, eFactura, SAF-T
-
-Cercetare read-only pentru S4c (plan_13). Nu s-a modificat niciun fisier, nu s-a rulat git_sync.
-
-## Verdict (5-10 randuri)
-
-Niciun raport tiparit de factura (`factura.fr2`, `facturatip*.fr2`, `factura_val*.fr2`,
-`invoice*.fr2`, `proforma*.fr2`) nu afiseaza discountul pe linie ca coloana separata — nici ca
-valoare, nici ca procent. Rapoartele tiparesc `pretftva` (pret unitar) si `valftva` (valoare linie)
-care sunt **deja nete de discount** (calculate ca `pretftva-discountftva` / `Sum(valdiminuatftva)`
-in cursorul intermediar `crsfacttemp`, construit de `prelucreaza_factura`/`creeaza_crsfacttemp` din
-`ofacturare_comun.prg`). eFactura (`xmlefactura.prg`) foloseste **exact acelasi cursor** —
-comentariul din cod chiar spune asta explicit — deci `LineExtensionAmount`/`PriceAmount` trimise la
-ANAF sunt aceleasi valori nete, cu optiunea (dezactivata implicit, din flag-uri globale) de a
-adauga si un `cac:AllowanceCharge` informativ pe linie. SAF-T (D406): **nu exista niciun generator
-D406/SAF-T in ROAFACTURARE** — exista doar tabele de nomenclator cu prefix `saft_` (coduri TVA/plata)
-folosite pe partea de achizitii, fara legatura cu `DISCOUNT_UNITAR`.
-
-**Raspuns la intrebarea care conteaza**: daca discountul pe linie devine editabil direct in grid,
-**nu se strica nimic in codul rapoartelor/eFacturii** — ele citesc oricum campurile finale
-(`valdiminuatftva`/`discountftva`/`discount_unitar`) din cursor, indiferent cum au fost populate
-(dialog separat vs. editare in grid). **Riscul real e in alta parte**: exista deja azi o cale prin
-care discountul e editabil direct in grid (`vdiscountftva`, pe factura in valuta) care **nu
-declanseaza recalcularea** lui `valdiminuatftva`/`valdiminuatctva` — vezi `docs\cercetare\discount_verificare2.md`
-punctul 3, ultimul paragraf. Daca S4c extinde editarea in grid la toate coloanele de discount fara
-sa cablaje si recalculul, rapoartele si eFactura vor tipari/trimite **valori vechi** (stale), pentru
-ca ambele citesc `valdiminuatftva`, nu `discount_unitar` direct.
-
-## 1. Rapoartele .frx/.fr2 tiparite
-
-**Cautare**: `Grep 'DISCOUNT'` si apoi `Grep 'disc'` (case-insensitive) in toate `.fr2` din
-`COMUN\Rapoarte` cu glob `*factur*.fr2`, `*proforma*.fr2`, `*invoice*.fr2` — **zero potriviri** in
-toate cele (factura.fr2, facturatip.fr2, facturatip_a5.fr2, facturatip_cuchit.fr2, factura_a5.fr2,
-factura_chit.fr2, factura_val.fr2, factura_val_a5.fr2, invoice.fr2, invoice_a5.fr2, proforma.fr2,
-proforma_orig.fr2, proforma_val.fr2, proforma_val_orig.fr2). Singurele 2 fisiere `.fr2` din toata
-`COMUN\Rapoarte` care contin "DISCOUNT" sunt `rap_nir_materiale.fr2` si `rap_nir_marfuri.fr2` —
-rapoarte de NIR (receptie), nu facturi emise.
-
-**Ce se tipareste per linie** (confirmat in `factura.fr2`):
-```
-1002:
-1014:
-1026:
-1062: -- procent TVA, nu discount
-```
-Deci: cantitate, pret unitar, valoare linie, procent TVA. Nici discount valoric, nici procent
-discount.
-
-**De unde vin `pretftva`/`valftva` — si de ce sunt deja nete**: cursorul de tiparire
-(`crsfacttemp`) e construit de `Procedure prelucreaza_factura` (`COMUN\programe\ofacturare_comun.prg:1055-1059`),
-apelata din `COMUN\programe\ofacturare.prg:1887`:
-```
-prelucreaza_factura([crsfactura], [crsfacturaset], [crsfacturafinala], poDate.discount_evidentiat, poDate.in_valuta, lnPretListAviz, poDate.nListareDetaliata)
-```
-In interior, `Do Case` pe `tnDiscountEvidentiat`/`lnPretListAviz` (`ofacturare_comun.prg:1156-1248`).
-Cazul comun, `tnDiscountEvidentiat = 0` (checkbox-ul "Se pune in evidenta discount-ul..." NEBIFAT —
-comportamentul implicit):
-```
-1182: Sum(cantitate) As cantitate,pretftva-discountftva As pretftva,;
-...
-1186: Sum(valdiminuatftva) As valftva,Sum(valdiminuattva) As valtva,;
-```
-adica pretul tiparit = pret brut minus discountul pe unitate, iar valoarea tiparita = suma
-`valdiminuatftva` (deja calculata la adaugarea articolului ca `pretftva - discount_unitar`, cf.
-`ofacturare.vc2:13126`, deja documentat in `discount_pe_articol.md` sectiunea 3). Simetric pentru
-varianta cu TVA la `:1226-1230`.
-
-**Cazul `tnDiscountEvidentiat = 1`** (checkbox bifat — discountul "se pune in evidenta"):
-```
-1165: pretftva,Nvl(codbare,... -- pretftva RAMANE brut, nu se scade discountftva
-1166-1167: Sum(valftva) As valftvai,... Sum(valftva) As valftva,Sum(valtva) As valtva,
-1168: discountftva,Sum(valdiscountftva) As valdiscountftva,Sum(valdiscounttva) As valdiscounttva,
-```
-Aici `pretftva`/`valftva` tiparite raman **brute** (neta de discount), iar `discountftva`/
-`valdiscountftva`/`valdiscounttva` sunt calculate in cursor **dar nu sunt tiparite de niciun .frx**
-(confirmat, zero hit pe "disc" in .fr2). Practic, cand discountul e "pus in evidenta", pretul si
-valoarea linie tiparite pe factura NU reflecta discountul per linie — discountul apare doar ca linie
-separata de document (randul-sentinela `denumire = Replicate('Z',20)`, populat din
-`Thisform.nbazafdiscount`/`nbazafdiscountval` la `ofacturare.vc2:14534,14591,18532,18602` si
-`ofacturare_comun.prg:1891`) — asta e insa discountul **de document** (`VANZARI.DISCOUNT`), nu
-`DISCOUNT_UNITAR` pe linie. Nu am gasit nicio dovada ca acest mod (`discount_evidentiat=1`) ar fi
-folosit uzual — e o optiune existenta, documentata deja in `discount_pe_articol.md` punctul 3 ca
-schimband "doar mecanismul aritmetic", dar aici se vede consecinta suplimentara: **si ce se
-tipareste**.
-
-**Fara impartiri la pret zero pe randul de discount**: unde raportul calculeaza procent
-(`proc_disc`), sursa e protejata explicit:
-```
-1184-1185 (ofacturare_comun.prg): Iif(cu_tva=0,Iif(pretftva<>0,Round(discountftva/pretftva*100,2),0),;
- Iif(pretctva<>0,Round(discountctva/pretctva*100,2),0))
-```
-deci nu exista risc de impartire la zero — dar, ca observat mai sus, `proc_disc` nu e tiparit
-nicaieri in .frx-urile de factura verificate (e calculat doar pentru consum intern/eFactura).
-
-## 2. eFactura (ANAF/UBL) — `xmlefactura.prg`
-
-**Concluzie**: eFactura foloseste **acelasi cursor de linii ca cel de la tiparire**, explicit
-documentat in cod:
-```
-oexport.prg:1590: * tcCursorLiniiFactura = numele cursorului cu liniile facturii, asa cum arata la listare
-```
-Lantul: `ofacturare.prg:2126` -> `goExport.export2xml_efactura(poDate, m.lcCursoreFactura, ...)` cu
-`lcCursoreFactura` = `lcCursorFacturaTemp` (= `'crsFacturaFinala'`, `ofacturare.prg:1892`, sau
-`'crsfacturafinalaval'` pentru valuta) -> `xmlefactura.prg:231`:
-```
-Select a.*, ... From (m.tcCursorLiniiFactura) a Left Join cJTVAVanzariTemp b ... Into Cursor C_IES_FORM Readwrite
-```
-Deci `C_IES_FORM` (sursa liniilor XML) e construit direct din cursorul de tiparire — aceleasi
-`pretftva`/`pretftvai`/`valftva`/`valftvai`/`proc_disc` descrise la punctul 1, cu aceeasi dependenta
-de `poDate.discount_evidentiat`.
-
-**Ce se trimite pe linie**:
-- `cbc:LineExtensionAmount` (BT-131) = `C_IES_FORM.valftva` — `xmlefactura.prg:935-937`.
-- `cbc:PriceAmount` = `C_IES_FORM.pretftva` — `xmlefactura.prg:1043-1046`.
-- Optional (doar daca flag global `gnEFACTURA_XML_DISC_PLISTA_LINIE = 1` SI `pretftvai > pretftva`):
- un `cac:AllowanceCharge` la nivel de linie cu `Amount = valftvai-valftva`,
- `BaseAmount = valftvai`, `MultiplierFactorNumeric = proc_disc` — `xmlefactura.prg:952-971`.
-- Optional (flag separat `gnEFACTURA_XML_DISC_PLISTA_ART = 1`): un `cac:AllowanceCharge` la nivel de
- `cac:Price` cu discountul unitar (`ABS(pretftvai-pretftva)`) — `xmlefactura.prg:1054-1067`.
-
-Ambele flag-uri sunt verificate cu `TYPE(...) = 'N' AND ... = 1` — daca variabila globala nu exista
-sau e 0 (implicit), **nu se trimite niciun `AllowanceCharge` pe linie**; discountul e vizibil pentru
-ANAF doar implicit, prin faptul ca `PriceAmount * InvoicedQuantity = LineExtensionAmount` (adica
-pretul e deja net). Nu am gasit unde sunt setate global aceste doua variabile (`gnEFACTURA_XML_DISC_PLISTA_LINIE`/`_ART`) —
-posibil optiuni de firma necautate in acest fisier; nu afecteaza concluzia principala.
-
-**Discount de document, separat**: exista o eticheta euristica in `C_IES_FORM`
-(`Iif('DISCOUNT' $ Upper(a.denumire) And a.pretftva < 0, 1, 0) As discount`, `xmlefactura.prg:230`)
-care detecteaza randuri-pseudo-articol de discount/taxa (denumire contine "DISCOUNT", pret negativ)
-si le exclude din liniile normale (`Scan For discount = 0`, `:901`), agregandu-le separat intr-un
-`cac:AllowanceCharge` la nivel de document (`:756-793`, motiv "Discount", cod 95). Acesta e
-discountul de document, nu `DISCOUNT_UNITAR` pe linie — mecanism diferit de randul-sentinela
-`Replicate('Z',20)` folosit la tiparire (punctul 1).
-
-**Nicio validare care ar respinge discount > pret**: n-am gasit nicio verificare explicita in
-`xmlefactura.prg` care sa blocheze o linie cu `discount_unitar` mai mare ca pretul (ar rezulta
-`pretftva` negativ pe linie individuala; codul are doar o corectie generala pentru
-`pretftva < 0` la nivel de linie completa, `xmlefactura.prg:236-239`, care inverseaza semnul
-cantitate/pret — nu specifica pentru discount).
-
-## 3. SAF-T (D406)
-
-**Concluzie: nu exista implementare SAF-T/D406 in ROAFACTURARE.** Cautat explicit:
-- `Grep 'SAF-T|SAFT|D406|declaratie406|GenereazaSAFT|GenereazaD406'` in tot `COMUN\programe` si
- `COMUN` — nicio potrivire pe un generator de fisier D406/SAF-T XML.
-- `Glob '**/*saft*'` pe tot proiectul si pe `COMUN` — zero fisiere cu "saft" in nume.
-- Singurele aparitii reale (nu fals-pozitive de tip "safe") sunt:
- - `oinit_optiuni.prg:523-524`: `gl406 = (TYPE('gnD406') = 'N' and m.gnD406 = 1)` — un flag "firma
- are activata SAFT 406", comentat "Firma are activata SAFT 406".
- - `oproceduri_comune.prg:889-896,6083,6151`, `ointroduceri.prg:1597`: `saft_taxtable` si
- `saft_mecanisme_plati` — tabele de nomenclator (coduri de TVA/mecanism de plata compatibile
- SAF-T) folosite pe **partea de achizitii** (limitare deducere TVA la introducerea facturilor de
- achizitie), nu pe vanzari/facturare.
- - `oproceduri_comune.prg:6066-6067,6137-6138,6195`: comentarii care mentioneaza "Taxa SAFT tip"
- ca denumire pentru codurile de TVA, tot pe achizitii.
-- Niciuna din aceste aparitii nu are legatura cu `DISCOUNT`/`DISCOUNT_UNITAR` — cautarea `DISCOUNT`
- in fisierele care contin "saft" (`oproceduri_comune.prg`, `ointroduceri.prg`, `pmenu.prg`,
- `oinit_optiuni.prg`) nu a gasit nicio intersectie intre cele doua seturi de rezultate.
-
-**Interpretare**: `gl406` pare sa activeze doar validari/coduri suplimentare pentru conformitate
-SAF-T pe partea de achizitii (poate pentru ca alt produs din suita, ROACONT, genereaza efectiv
-D406 din datele contabile) — ROAFACTURARE nu produce singur un fisier D406.
-
-## 4. Alte consumatori care ar presupune discount uniform pe document
-
-Nu am gasit vreun raport/export care sa presupuna un discount unic pe tot documentul in sensul de
-"aceeasi valoare/procent pe toate liniile" — mecanismul de discount de document
-(`VANZARI.DISCOUNT`, randul `Replicate('Z',20)`) e tratat ca **valoare agregata separata**, adaugata
-ca linie proprie (in tiparire) sau ca `AllowanceCharge` de document (in eFactura), nu redistribuita
-implicit pe liniile existente — cu o exceptie: `xmlefactura.prg` are logica de **distribuire**
-explicita a discountului/taxelor de document pe articole cand bifa `chkDistribuieDiscount`/
-`llDistribuieDiscountTaxe` e activa (`xmlefactura.prg:12189-12320`, `:12534-12790`) — asta insa
-opereaza pe discountul de document, nu presupune ca discountul de linie (`DISCOUNT_UNITAR`) e
-uniform; dimpotriva, distribuie proportional cu valoarea fiecarei linii, deci suporta discount
-diferit per linie din start.
-
-## Ce ar strica S4c, concret
-
-**Nu se strica codul rapoartelor sau al eFacturii** — ambele citesc valori finale din cursor
-(`valdiminuatftva`, `discountftva`, `pretftva` deja net), indiferent de sursa UI a discountului.
-
-**Se poate strica invariantul pe care se bazeaza**, daca editarea in grid nu recalculeaza:
-- **Dovada ca gaura exista deja azi**: pe factura in valuta, coloana `vdiscountftva` e editabila
- direct in grid (`ofacturare.vc2:12340-12345`, fara `ReadOnly`) dar **fara niciun handler
- `Valid`/`InteractiveChange`** care sa recalculeze `vvaldiminuatftva`/totalurile — confirmat cautat
- explicit in `docs\cercetare\discount_verificare2.md` punctul 3, ultimul paragraf ("editarea directa
- in grid NU declanseaza recalcularea automata a `vvaldiminuatftva`/totaluri, doar modifica valoarea
- bruta in `crsfactura`").
-- **De ce conteaza pentru rapoarte/eFactura**: `valdiminuatftva`/`valdiminuatctva` (nu
- `discount_unitar` brut) sunt campurile citite de `prelucreaza_factura`/`creeaza_crsfacttemp`
- pentru `valftva` tiparit si trimis la ANAF (punctele 1 si 2 de mai sus). Daca operatorul modifica
- discountul direct in grid si acel camp nu se recalculeaza, factura tiparita si XML-ul ANAF vor
- arata **valoarea veche** (dinainte de editare) — o discrepanta reala intre ce vede operatorul in
- grid si ce se tipareste/trimite.
-- **Concluzie pentru plan**: daca S4c extinde editarea de discount la toate coloanele din grid
- (inclusiv `discountctva`, azi read-only pe lei), trebuie cablat un recalcul echivalent cu
- `frm_articol_factura.do_calculeaza_discount` (`ofacturare.vc2:1874-1976`) pe evenimentul de editare
- din grid — altfel riscul de mai sus (deja prezent azi doar pe valuta) se extinde la toate
- facturile in lei.
-
-## Ramas de verificat
-
-- Valorile implicite ale flag-urilor globale `gnEFACTURA_XML_DISC_PLISTA_LINIE` si
- `gnEFACTURA_XML_DISC_PLISTA_ART` (unde sunt setate ca optiune de firma) — nu am cautat sursa lor,
- doar am confirmat ca cu `TYPE(...) <> 'N'` (nedefinite) comportamentul e "fara AllowanceCharge pe
- linie".
-- Nu am verificat pe date reale (Oracle/XML generat) un caz cu `discount_evidentiat=1` si
- `DISCOUNT_UNITAR` populat simultan, ca sa confirm empiric (nu doar din citirea codului) ca factura
- tiparita arata pretul brut.
-- Nu am urmarit `crsfacturafinalaval` (varianta valuta a cursorului final) linie cu linie — am
- presupus ca urmeaza acelasi patron ca `crsfacturafinala`/`crsfacttemp` (cursorul in lei), pe baza
- simetriei campurilor `vpretftva`/`vvalftva`/`vdiscountftva` gasite deja documentate in
- `discount_verificare2.md` si `discount_pe_articol.md`; n-am reverificat separat sursa SQL pentru
- varianta valuta.
-- Nu am identificat un al doilea produs (ROACONT?) care sa genereze efectiv D406 din datele scrise
- de ROAFACTURARE — presupunerea din sectiunea 3 e speculativa, nu confirmata cu cod.
diff --git a/docs/cercetare/factura_retur_document.md b/docs/cercetare/factura_retur_document.md
deleted file mode 100644
index 1d5003b..0000000
--- a/docs/cercetare/factura_retur_document.md
+++ /dev/null
@@ -1,185 +0,0 @@
-# Cercetare: factura de retur ca document de sine statator (tip 8/9) + aviz retur (24)
-
-Corectie fata de `retur_si_lista_preturi.md`: acea cercetare a documentat corect `But_retur`
-(retur de articole *in interiorul* unei facturi normale, tip 1/5/7/10 — selectie **per articol**).
-Aici e documentat mecanismul **separat**: factura de retur ca document propriu (tip 8 = retur lei,
-tip 9 = retur valuta), unde utilizatorul alege **facturile sursa la nivel de document**, iar linia
-de articole se populeaza integral din acele facturi.
-
-## 1. Punctul de intrare si cursorul Oracle
-
-Tile-ul de pe ecranul principal de facturare, `Page2.Cw1` (`COMUN\clase\ofundal_facturare.vc2:882-884`):
-```
-PROCEDURE Page2.Cw1.do_actiune
- DO facturare_lista_de_preturi IN oproceduri_facturare.prg
-ENDPROC
-```
-`facturare_lista_de_preturi` (`COMUN\programe\oproceduri_facturare.prg:114-116`) = `Do politica.mpr`,
-care ruleaza meniul shortcut generat din `Meniuri\politica.mn2:14-15,45-46`:
-```
-DEFINE BAR 2 OF Shortcut PROMPT "\ cate un camp cu acelasi nume in cursorul VFP `crsarticole` (maparea VFP
-exacta camp-cu-camp nu a fost trasata pana in `crsfactura`; nu era necesara pentru raspuns).
-
-## 4. Ce se poate face manual (`frm_facturare_articole`, `COMUN\clase\ofacturare.vc2:10968`)
-
-- **Stergere linie**: `do_sterge` (`:14608-14693`) nu e restrictionat pe tip; pentru retur
- (`Case Inlist(poDate.tip,8,9,24)`, `:14658-14659`) cantitatea stearsa se reintoarce in cursorul
- sursa (`Replace cantitate With cantitate - poArticol.cantitate For id_c = poArticol.id_c`) — deci
- **da, se pot sterge linii aduse**, iar cantitatea redevine disponibila pentru re-adaugare.
-- **Retur partial (modificare cantitate)**: coloana de cantitate din grila sursa isi schimba titlul
- in "Cant. max. de returnat" pentru tip 8/9 (`:15236-15239`); validarea in `do_verifica_articol`
- (`:14743-14754`, `llRetur = Inlist(poDate.tip,8,9,24)`) respinge doar cazul in care cantitatea
- ceruta ar depasi maximul returnabil — utilizatorul poate introduce orice cantitate <= maxim,
- deci **da, retur partial e posibil**. `do_modifica` (`:13746-13914`) trateaza explicit
- `Inlist(poDate.tip,8,9,24)` la `:13788,13895` fara blocaj suplimentar.
-- **Adaugare linie care NU e in facturile sursa**: `do_adauga_articol` (`:12813-13086`) preia
- articolul mereu din cursorul sursa al gridului (`lcCursor = [crsarticole]`, apoi
- `Select (lcCursor) / Scatter Name poArticol`, `:12843-12851`) — pentru tip 8/9 acest `crsarticole`
- e chiar rezultatul `cursor_retur` de la punctul 3, deci contine **doar** liniile facturilor alese.
- Nu exista pe acest formular o cale de a alege un articol din lista de preturi completa cand
- `poDate.tip` e 8/9 (spre deosebire de contract/comanda unde `crsarticole` ramane lista de preturi
- libera) — **nu se poate adauga o linie in afara facturilor sursa**, prin design-ul continutului
- cursorului, nu printr-o validare explicita de interzicere.
-
-## 5. Aviz de retur (tip 24)
-
-Acelasi mecanism de baza: `Inlist(tnTip,8,9,24)` la `ofacturare.prg:306-307` (acelasi
-`pack_facturare.cursor_retur`) si aceleasi ramuri `Inlist(poDate.tip,8,9,24)` in
-`frm_facturare_articole` (`do_adauga_articol:12863`, `do_alege_stoc:13230`, `do_modifica:13788,13895`,
-`do_verifica_articol:14743`, `do_sterge:14658`). Diferenta: la antet, `nIdTipDoc` = 6 (AVIZ, ramura
-`Otherwise` la `ofacturare.prg:194-195`, pentru ca 24 nu e `<21` si nu e in `Inlist(45,48,49,51,52)`),
-iar formularul de date e `frm_date_aviz` (`ofacturare.prg:225`, ramura `Otherwise`), nu
-`frm_date_factura`. Punctul de intrare pentru tip 24: `emitere_aviz_clienti` cu `tnTip=7`
-(`COMUN\programe\oproceduri_facturare.prg:221-222`, `factureaza(24) && Retur aviz`), apelat din
-tile-ul `Page3.Cw1` -> `aviz_clienti.mpr` (neverificat detaliat, nu s-a insistat conform cerintei).
-
-## 6. Relatia cu `But_retur`
-
-Mecanisme **complet separate**, confirmate pe cod:
-- **Vizibilitate**: `but_retur` e vizibil doar pentru tip 1/5/7/10 (`ofacturare.vc2:15127`,
- `This.but_retur.Visible = .T.` in ramura `Case Inlist(poDate.tip,1,5,7,10)`) — pe un document
- tip 8/9 acest buton nu exista deloc in UI (ramura lui la `Init` e alta, `:15236`).
-- **Formular de alegere a facturii sursa**: `But_retur` foloseste `caut_facturi_multiple_client_articol`
- (`oproceduri_facturare.prg:2124-2159`, filtrat suplimentar pe `b.id_articol = ?pnIdArticol` —
- cautare per-articol, cu titlu simplu "Alegeti factura"), tip 8/9 document foloseste
- `caut_facturi_multiple_client` (`:2091-2121`, fara filtru pe articol, multi-select, titlu
- "Alegeti facturile ..."). Doua functii diferite, in acelasi fisier, cu semnaturi aproape identice
- dar interogari SQL diferite.
-- **Procedura Oracle de populare a liniilor**: documentul tip 8/9 foloseste
- `pack_facturare.cursor_retur` la nivel de document intreg (populeaza `crsarticole` cu toate
- liniile facturilor alese, punctul 3 de mai sus). `But_retur` nu apeleaza `cursor_retur`/
- `cursor_retur_document` deloc — foloseste `pack_facturare.cursor_gestiuni_articol_retur`
- (`ofacturare.vc2:13230`, per articol individual, in `do_alege_stoc`) pentru a alege
- gestiunea/seria/lotul de returnat pentru articolul deja selectat din lista de preturi a facturii
- normale curente.
-- **Punct comun**: niciunul direct. Singurul element comun e conventia de semn a cantitatii
- (`Iif(Inlist(poDate.tip,8,9,24),(-1),1)`, folosita si in `do_alege_stoc` al `But_retur`,
- `:13279-13309`, si pe formularul `frm_facturare_articole2`, `:17574-17585`) si textul UI
- ("cant. max. de returnat"). Concluzie: sunt doua fluxuri de cod independente care ating aceeasi
- clasa de formular (`frm_facturare_articole`) dar prin metode si proceduri Oracle diferite.
diff --git a/docs/cercetare/garda_aviz_facturat.md b/docs/cercetare/garda_aviz_facturat.md
deleted file mode 100644
index 569b65f..0000000
--- a/docs/cercetare/garda_aviz_facturat.md
+++ /dev/null
@@ -1,235 +0,0 @@
-# Garda "aviz deja facturat" — verificare pe cod
-
-Verificare pe cod, fara nicio modificare de fisier. Sursele citate:
-
-- export pachet: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`
- (mai jos: `EXPORT:`);
-- corpul **desfasurat pe DB** (`MARIUSM_AUTO@ROA_CENTRAL`, `all_source`), citit ca sa se confirme ca
- ce e in export e si ce ruleaza (mai jos: `DB PACK_FACTURARE:`). **Numerotarea difera**:
- `sterge_factura` incepe la `EXPORT:5432`, dar la `DB PACK_FACTURARE:4192`. Nu exista offset
- constant; textul insa e identic cuvant cu cuvant pe zona gardelor.
-
----
-
-## 1. Blocheaza garda de azi si un AVIZ care are deja factura generata din el?
-
-**DA.** Nu e nevoie de nicio garda noua pentru cazul asta — este exact ce testeaza a doua garda din
-`sterge_factura`, prin `TIP IN (1, 2)`.
-
-`EXPORT:5464-5476` = `DB PACK_FACTURARE:4224-4236`:
-
-```
- -- ptr. un aviz normal:
- -- verific daca exista facturi sau avize de retur pe avizul resp.
- SELECT COUNT(*)
- INTO V_NR_AVIZE_FACT
- FROM VANZARI_CORESP
- WHERE STERS = 0
- AND ID_VANZARE_AVIZ = V_ID_VANZARE
- AND TIP IN (1, 2);
-
- IF V_NR_AVIZE_FACT > 0 THEN
- RAISE_APPLICATION_ERROR(-20000,
- 'Pe acest aviz s-au emis facturi / aviz de retur. Trebuie sa stergeti mai intai facturile / avizul de retur!');
- END IF;
-```
-
-Cheia e semantica lui `TIP`, citita din **singurul scriitor** al tabelei, ramura cu ramura
-(`finalizeaza_factura`, `EXPORT:14818-14839`):
-
-| `VANZARI_CORESP.TIP` | scris cand | `ID_VANZARE_FACT` | `ID_VANZARE_AVIZ` | e retur? |
-|---|---|---|---|---|
-| **1** | `ntip = 4` — facturare din aviz (`EXPORT:14823-14826`) | factura | avizul-sursa | **NU** |
-| 2 | `ntip = 24` — aviz de retur (`EXPORT:14828-14830`) | avizul de retur | avizul original | DA |
-| 3 | `ntip in (8, 9)` — factura de retur (`EXPORT:14834-14836`) | factura de retur | factura originala | DA |
-
-Deci `TIP = 1` este **corespondenta aviz -> factura normala**, nu retur. Garda de la `EXPORT:5473`
-prinde ambele cazuri; textul mesajului chiar o spune ("s-au emis **facturi** / aviz de retur").
-Formularea din brief ("garda de azi blocheaza documentul care are facturi/avize **de retur**") vine
-dintr-o citire a comentariului `-- verific daca exista facturi sau avize de retur` in care "de retur"
-se distribuie si peste "facturi"; codul zice altceva.
-
-Deci: la ora asta, **exact regula ceruta de decizia 50 este deja implementata pentru avize**
-(document cu urmasi = blocat; capatul lantului = liber).
-
-### Ce NU citeste garda
-
-- **`VANZARI.FACTURAT` nu e citit de nicio garda.** Pe calea de stergere e doar **scris**
- (`EXPORT:5504-5510` pentru `V_TIP = 24`, `EXPORT:5527-5533` pentru `V_TIP = 4` — resetare la 0
- cand dispare factura/avizul de retur), iar la facturare e **pus** de `marcheaza_facturat`
- (`EXPORT:15381-15418`). Niciun `IF` / `RAISE` nu il interogheaza. Semnalul autoritar este
- `VANZARI_CORESP`, `FACTURAT` e derivat redundant.
-- **`ID_VANZARE_SURSA` / `ID_VANZARE_DEST` nu exista.** `VANZARI_CORESP` are exact 5 coloane
- (interogare pe `all_tab_columns`): `ID_VANZARE_CORESP`, `ID_VANZARE_FACT`, `ID_VANZARE_AVIZ`,
- `STERS`, `TIP`. Nici `VANZARI` nu are coloane `*_SURSA` / `*_DEST` (aceeasi interogare).
-
----
-
-## 2. Exista alte garzi pe calea de stergere / modificare?
-
-### 2a. Oracle — nu exista alta, dar garda e **atinsa pe ambele ramuri** de stergere
-
-Interogare pe `all_source` (owner curent): singurele obiecte care contin `VANZARI_CORESP` sunt
-**`PACK_FACTURARE` (package body)** si **`TRG_VANZARI_CORESP_BEFOINS`**. Deci nu exista o a doua
-garda ascunsa in alt pachet.
-
-**Triggerele nu contin garzi** (sursa citita integral din `all_source`):
-
-| trigger | tabela | eveniment | ce face |
-|---|---|---|---|
-| `TRG_VANZARI_BEFOUPD` | `VANZARI` | UPDATE | 4 apeluri `pack_audit.verifica_val` (NR_ACT, SERIE_ACT, DATA_ACT, DATA_SCAD) — audit, nu blocare |
-| `TRG_VANZARE_BEFOINS` | `VANZARI` | INSERT | — |
-| `TRG_VANZARI_DET_BEFOINS` | `VANZARI_DETALII` | INSERT | — |
-| `TRG_VANZARI_CORESP_BEFOINS` | `VANZARI_CORESP` | INSERT | doar `SEQ_VANZARI_CORESP.nextval` |
-
-**Punct important de verificat, pentru ca la prima citire pare o portita:** in
-`frm_facturi.do_sterge` apelul direct `pack_facturare.sterge_factura` e **comentat** pe ramura
-documentelor cu note contabile — `ofacturare_comun.vc2:4807-4809` (`*!* modificare v 2.2.5`), iar
-ramura activa (`:4810-4811`) cheama numai `pack_contafin.finalizeaza_stergere_nota`. **Nu e o
-portita**: lantul se inchide in Oracle.
-
-```
-PACK_CONTAFIN:8322-8326 SELECT COUNT(*) INTO lnEInVanzari FROM vanzari WHERE cod = tnCod;
- IF lnEInVanzari > 0 THEN
- pack_facturare.sterge_din_vanzari(tnCod, tnAn, tnLuna, tnIdUtil);
-PACK_FACTURARE:14996-14998 SELECT ID_VANZARE INTO V_ID_VANZARE FROM VANZARI WHERE COD = V_COD;
- pack_facturare.sterge_factura(V_ID_VANZARE, V_LUNA, V_AN, V_ID_UTIL);
-```
-
-Apelantii lui `sterge_factura` in baza (cautare pe `all_source`) sunt exact doi:
-`PACK_FACTURARE.sterge_din_vanzari` (`DB PACK_FACTURARE:14998`) si procedura standalone
-`STERGE_DOCUMENT` (`DB STERGE_DOCUMENT:416`). Ambele cai trec prin garda.
-
-### 2b. VFP — pe calea de stergere: nicio garda pe urmasi
-
-`frm_facturi.do_sterge` (`COMUN\clase\ofacturare_comun.vc2:4661-4877`) verifica, inainte de apel:
-luna inchisa (`:4676`), `sters = 1` (`:4689`), confirmare (`:4694`), luna curenta (`:4701`) si
-referinte de incasari/plati (`ReferinteDocumenteNota`, `:4723-4727`). **Nimic despre `FACTURAT`,
-`VANZARI_CORESP` sau urmasi** — verificarea lantului e delegata integral Oracle-ului.
-
-### 2c. VFP + Oracle — pe calea de **modificare**: nicio garda, nici pe urmasi, nici pe lant
-
-`frm_facturi.do_modifica` (`ofacturare_comun.vc2:4541-4640`) blocheaza doar doua lucruri
-(`:4590`, `:4635`):
-
-```
- If poRec.sters = 0 AND NVL(m.pnEFactura,0) = 0
- ...
- amessagebox("Nu puteti face modificari pe inregistrarile sterse sau facturile trimise in eFactura!", 48, "Atentie")
-```
-
-`pack_facturare.modifica_date_factura` (`EXPORT:14439-14509`) e un lant de `UPDATE`-uri fara niciun
-`IF` de validare si fara niciun `RAISE_APPLICATION_ERROR`. Ceea ce e coerent cu ce modifica azi
-(ruta, delegat, agent, masina, dataora exp., text aditional, tip SAFT, eFactura, serie/numar/data act,
-data scadenta) — campuri de antet care nu ating lantul aviz -> factura.
-
----
-
-## 3. Concluzia operationala pentru decizia 50 / S7
-
-**Regula ceruta de decizia 50 exista deja, si nu are gol pe aviz.** `sterge_factura` implementeaza
-azi, in trei garzi consecutive, exact "documentul cu urmasi e blocat, capatul lantului e liber":
-
-| garda | `EXPORT` | ce blocheaza |
-|---|---|---|
-| 1 | 5452-5462 | **factura** care are facturi de retur peste ea (`TIP = 3`) |
-| 2 | 5466-5476 | **aviz** care are factura (`TIP = 1`) sau aviz de retur (`TIP = 2`) peste el |
-| 3 | 5480-5494 | **factura din aviz** ale carei avize-sursa au primit intre timp aviz de retur |
-
-A treia garda merita subliniata pentru decizia 50: factura din aviz e editabila **doar** cat timp
-niciunul dintre avizele ei nu are aviz de retur; nu e "capat de lant" neconditionat.
-
-**Deci S7 nu are nevoie de o garda noua ca regula — dar are nevoie de o citire noua a aceleiasi
-conditii, ca moment.** Garda de azi e in interiorul lui `sterge_factura`, adica se manifesta ca
-`ORA-20000` **in mijlocul** pasului de stergere din regenerare, dupa ce utilizatorul a completat
-formularul si dupa ce s-a deschis tranzactia. Pentru un flux de editare asta e o esuare tarzie.
-Ce lipseste e un **pre-flight read-only**, inainte de intrarea in formular, pe exact aceeasi
-conditie (fara reimplementarea regulii):
-
-```sql
-select count(*) from vanzari_coresp
- where sters = 0 and id_vanzare_aviz = :id_vanzare and tip in (1, 2, 3)
-```
-
-plus, pentru cazul "factura din aviz", subinterogarea din garda 3 (`EXPORT:5480-5488`). Garda din
-`sterge_factura` ramane pe loc ca plasa de siguranta — nu se muta, nu se slabeste.
-
-Interogarea se face pe `VANZARI_CORESP`, **nu** pe `VANZARI.FACTURAT`: `FACTURAT` e un marcaj
-redundant, derivat, scris/resetat de `marcheaza_facturat` / `sterge_factura`, si necitit de nicio
-garda; `VANZARI_CORESP` e semnalul autoritar.
-
----
-
-## 4. Inventar: ce tipuri de documente-parinte produc urmasi prin `VANZARI_CORESP`?
-
-**Doar trei, toate scrise din acelasi `CASE` din `finalizeaza_factura` (`EXPORT:14818-14839`), prin
-singurul scriitor `scrie_corespondente_vanzari` (`EXPORT:15481-15516`, singurul `INSERT INTO
-VANZARI_CORESP` din tot pachetul — si din toata baza, cf. `all_source`).**
-
-| parinte | urmas | `TIP` | de unde vine lista parintilor |
-|---|---|---|---|
-| **aviz** (`VANZARI.TIP in 21, 22, 26, 42`) | factura din aviz (`ntip = 4`) | 1 | `clistaid_avize`, setat la `EXPORT:7037` in `scrie_factura_avize`; lista o construieste VFP prin `caut_avize`, filtrata `a.tip in (21,22,26,42) and a.facturat = 0` — `COMUN\programe\oproceduri_facturare.prg:2036-2038` |
-| **aviz** | aviz de retur (`ntip = 24`) | 2 | `clistaid` |
-| **factura** | factura de retur (`ntip in 8, 9`) | 3 | `clistaid` |
-
-**Ce NU produce urmasi prin `VANZARI_CORESP`** (deci decizia 50 nu are acoperire acolo prin garda
-existenta):
-
-- **proforma -> factura.** Proforma sta in `VANZARI` cu `EPROFORMA = 1`; `finalizeaza_factura` nu are
- ramura care sa scrie corespondenta pentru ea. `TIP = 4` este o **propunere** de la S5c, nu cod
- existent. Mai mult, `pack_facturare.sterge_proforma` (`EXPORT:5610-5635`) **nu are nicio garda** —
- corpul ei e doar doua `UPDATE ... SET STERS = 1` pe `VANZARI` si `VANZARI_DETALII`. O proforma din
- care s-a emis factura se poate sterge azi fara niciun avertisment. (Calea VFP:
- `ofacturare_comun.vc2:4707-4719`, care iese din `do_sterge` inainte de restul verificarilor.)
-- **comanda -> factura.** Legatura e `VANZARI.ID_COMANDA` + `pack_facturare.inchide_comanda`
- (`EXPORT:5769`), nu `VANZARI_CORESP`. `COMENZI` **nu are coloana `FACTURAT`** (verificat pe
- `all_tab_columns`) — flagul `facturat` din grid vine din view-ul de incarcare. Garda exista, dar e
- **in VFP si pe comanda**, nu pe factura: `COMUN\clase\ocomenzi.vc2:1806-1807` la modificare
- ("Aceasta comanda a fost facturata si nu mai poate fi modificata!") si `:2065-2066` la stergere.
-- **contract -> factura.** Legatura e `VANZARI.ID_CTR` + `CTR_RATE_FACTURI`
- (atinsa de `sterge_factura` la `EXPORT:5566-5580` pentru `V_TIP IN (2, 6, 52)`); nicio linie in
- `VANZARI_CORESP`, nicio garda de tip "are urmasi".
-
----
-
-## 5. Ce am verificat direct vs. ce am dedus
-
-**Verificat direct pe cod / pe metadate:**
-
-- textul celor trei garzi din `sterge_factura`, in export **si** desfasurat din `all_source` (identice);
-- `CASE`-ul din `finalizeaza_factura` care da semantica lui `TIP`, ramura cu ramura;
-- corpul lui `scrie_corespondente_vanzari` si `marcheaza_facturat`;
-- ca `INSERT INTO VANZARI_CORESP` exista intr-un singur loc (grep pe export + `all_source` pe toata baza);
-- sursa integrala a celor 4 triggere de pe `VANZARI` / `VANZARI_DETALII` / `VANZARI_CORESP`;
-- lista completa a apelantilor lui `sterge_factura` (`all_source`), inclusiv lantul
- `finalizeaza_stergere_nota -> sterge_din_vanzari -> sterge_factura`;
-- coloanele reale ale `VANZARI_CORESP`, `PROFORME`, si absenta lui `FACTURAT` din `COMENZI`
- (`all_tab_columns`);
-- `frm_facturi.do_sterge` si `frm_facturi.do_modifica` integral, plus `modifica_date_factura`;
-- filtrul `caut_avize` din `oproceduri_facturare.prg`.
-
-**Dedus / cu limite declarate:**
-
-- Ca `TIP = 1` inseamna "factura normala din aviz" e o deductie din singurul punct de scriere
- (`ntip = 4` -> `scrie_corespondente_vanzari(1)`) — solida, dar e deductie, nu o eticheta declarata
- intr-un nomenclator.
-- Ca setul tipurilor-parinte pentru `TIP = 1` e `{21, 22, 26, 42}` vine din filtrul VFP `caut_avize`,
- nu dintr-o restrictie in Oracle. Pachetul insereaza **orice** `ID_VANZARE` primit in
- `clistaid_avize`, fara filtru pe tip (`EXPORT:15494-15504`). Alt apelant (alt produs ROA, un import)
- ar putea introduce alte tipuri.
-- Nu am verificat daca vreun **alt produs ROA** (ROACONT / ROAGEST / ...) are o cale proprie de
- stergere care ocoleste `sterge_factura`. Am verificat doar ca in Oracle nu exista alt apelant si
- ca in ROAFACTURARE ambele ramuri din `do_sterge` ajung acolo.
-
-**Din date, deci nedovaditor:** interogarea pe `VANZARI_CORESP` din baza de dev arata `TIP=1` cu
-parinti de tip 21 si 22, `TIP=2` cu parinte 22, `TIP=3` cu parinte 1 — consistent cu tabelul de mai
-sus, dar volumul e de ordinul unitatilor (8 randuri in total). **Nu e dovada**; concluziile de mai
-sus vin din cod.
-
-## 6. Ce nu s-a putut stabili
-
-Nimic din cele 4 intrebari nu a ramas nedeterminat. Singurul punct pe care l-as lasa explicit
-deschis pentru S7 este cel de la §4: **golul real nu e pe aviz, e pe proforma** —
-`sterge_proforma` nu are absolut nicio garda, iar daca S5c chiar introduce `TIP = 4`
-(proforma -> factura), garda din `sterge_factura` **nu se aplica automat**, pentru ca `sterge_proforma`
-e o procedura complet separata care nu o apeleaza.
diff --git a/docs/cercetare/gol_ntip4_factura_din_avize.md b/docs/cercetare/gol_ntip4_factura_din_avize.md
deleted file mode 100644
index c59822b..0000000
--- a/docs/cercetare/gol_ntip4_factura_din_avize.md
+++ /dev/null
@@ -1,231 +0,0 @@
-# Golul ntip=4 (facturare din avize) fata de proiectarea parametrului de cont contabil
-
-Cercetare read-only, continua `canal_cont_venit_fara_politica.md` (sectiunea "Proiectarea
-parametrului de cont contabil", liniile 13-227). Confirma si extinde golul deja semnalat, mai
-succint, in `parametru_cont_contabilizeaza_articol.md:49-56,167-168`.
-
-Sursa Oracle: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`
-(17217 linii). **Toate liniile citate mai jos sunt verificate direct pe acest fisier in aceasta
-runda** — numerele din cererea initiala (7520-7537, 5096) s-au dovedit **identice**, fara offset,
-fata de fisierul curent (nu +17 cum se anticipa).
-
-## Verdict, in cinci randuri
-
-**Ramura `ntip=4` e EXCLUSA STRUCTURAL, dar nu prin mecanismul presupus initial** (nu prin garda
-`id_pol` din `cursor_articol`/FACT-024 a lui `contabilizeaza_articol`). Blocajul real e **cu o
-functie mai devreme**: `adauga_articol_factura`, ramura `WHEN pack_facturare.ntip = 4`
-(`:5080-5103`), cauta randul original din avizul sursa prin `A.ID_POL = V_ID_POL` **fara niciun
-handler de exceptie** — daca `V_ID_POL` e `NULL` (exact cazul "articol fara politica"), `NULL =
-NULL` nu se potriveste niciodata in SQL, deci `SELECT ... INTO` **cade mereu cu `NO_DATA_FOUND`
-neprins**, la momentul **adaugarii articolului in factura** (`adauga_articol_factura`), cu mult
-inainte ca linia sa ajunga vreodata la `contabilizeaza_articol`. Practic, un articol fara politica
-**nu poate fi adaugat deloc** pe un document `ntip=4` — eroarea apare la primul pas, nu la scriere.
-**Gol sora mai important, gasit in aceasta cercetare**: ramurile de **aviz** (`ntip` in afara
-bucket-ului "factura") — `28`/`29` (SCD hardcodat `461`) si toate celelalte (SCD hardcodat `418`)
-— **raman perfect accesibile** cu `cont_venit` populat, iar ramura noua propusa hardcodeaza
-`SCD='4111'` necondiționat de `ntip`, ceea ce ar scrie contul gresit pe orice aviz cu articol fara
-politica. Vezi sectiunea "Ramuri sora" mai jos — mai grav decat golul `ntip=4` insusi, pentru ca
-e efectiv atins, nu doar teoretic.
-
-## 1. Lantul de dovezi pentru "ntip=4 e exclus" — pas cu pas
-
-### 1.1. `ntip` e o variabila de pachet, setata o singura data per document
-
-```
-ff_...:165 ntip NUMBER(2); -- declarata in spec, variabila publica de pachet
-ff_...:1882 pack_facturare.ntip := V_TIP; -- in initializeaza_date_factura (una din cele 4 supraincarcari, ~1650-1918)
-```
-
-`V_TIP` vine din `poDate.Tip` la apelul VFP `pack_facturare.initializeaza_date_factura(...)`
-(`COMUN\clase\ofacturare.vc2:13981-13999`, argumentul `Alltrim(Str(poDate.Tip))` pozitionat ca
-`V_TIP`). O data setat, `pack_facturare.ntip` ramane valabil pentru toate apelurile ulterioare
-din aceeasi tranzactie (`adauga_articol_factura`, apoi `scrie_factura2`/`scrie_factura_avize_retur`/
-`scrie_aviz_retur` -> `contabilizeaza_articol`) — **e o singura valoare per document, nu per linie**.
-
-### 1.2. Apelanti VFP care produc `poDate.Tip = 4`
-
-Comentat consecvent `&& factura din aviz` / `&& aviz` in tot codul VFP:
-```
-COMUN\clase\ofacturare_comun.vc2:4347 If poDate.tip = 4 && factura din aviz
-COMUN\programe\oproceduri_facturare.prg:1253 If poDate.tip = 4 && factura din aviz
-COMUN\programe\ofacturare.prg:1512 Case poDate.tip = 4
-COMUN\clase\ofacturare.vc2:9534,9636,9674,14301,15151,18299,19022 Case poDate.tip = 4 (afisare/validare)
-```
-`ofacturare.prg:1268,1488,1504` trateaza si combinatia `poDate.tip = 4 And Not
-Empty(poDate.id_comanda_aviz)` alaturi de `ntip IN (3,21,28,42,47)` — confirma ca `ntip=4` e
-categoria distincta "facturare pe baza de avize existente" (formularul dedicat de facturare din
-avize), separata de facturarea directa sau din comenzi.
-
-### 1.3. `adauga_articol_factura`, ramura `ntip=4` — blocajul real
-
-```
-ff_...:4989-5015 PROCEDURE adauga_articol_factura(..., V_ID_POL IN NUMBER, ...)
-```
-`V_ID_POL` e parametru direct (nu derivat), trimis de VFP la
-`COMUN\clase\ofacturare.vc2:14072` (si identic `:18107`):
-```
-Nvl(Alltrim(Str(poArt.id_pol)),[NULL])
-```
-Daca `poArt.id_pol` e `.NULL.` in VFP (cazul "articol fara politica" — premiza intregului
-proiect #13), `Str()` propaga `.NULL.`, iar `Nvl(...)` trimite literalul SQL `NULL` — deci
-`V_ID_POL` ajunge `NULL` in Oracle exact cand articolul n-are politica.
-
-In corpul `adauga_articol_factura`, CASE-ul care determina pretul/TVA/valuta ramurii (`:5052-5220`)
-are, pentru `ntip=4`:
-```
-ff_...:5080-5103
- WHEN pack_facturare.ntip = 4 THEN
- -- facturare din avize
- SELECT DISTINCT A.PRET, A.PROC_TVAV, A.ID_VALUTA, A.PRET_CU_TVA, B.IN_STOC
- INTO V_PRET, V_PROC_TVAV, V_ID_VALUTA, V_PRETURI_CU_TVA, V_IN_STOC
- FROM VANZARI_DETALII A
- LEFT JOIN NOM_ARTICOLE B ON A.ID_ARTICOL = B.ID_ARTICOL
- WHERE A.ID_ARTICOL = V_ID_ARTICOL
- AND A.ID_POL = V_ID_POL
- AND NVL(A.ID_GESTIUNE, -1000) = V_ID_GESTIUNE
- AND A.DISCOUNT_UNITAR = V_DISCOUNT_UNITAR
- AND NVL(A.CONT, 'XXXX') = V_CONT
- AND A.ID_VANZARE IN (SELECT X FROM table(cast(CHARN2COLLECTION(pack_facturare.clistaid, ',') AS num_tab)));
-```
-**Fara niciun `EXCEPTION WHEN NO_DATA_FOUND`** — spre deosebire de ramurile vecine din acelasi
-CASE: `ntip=45` are handler cu `FACT-018` (`:5140-5145`), `V_OPT_FACTURARE=3` are handler cu
-fallback + `FACT-012` (`:5167-5185`), `ELSE` are handler cu `FACT-013` (`:5188-5198`). Doar ramurile
-`ntip IN (3,21,28,42,47)` (`:5053-5078`, cauta in `COMENZI_ELEMENTE` dupa comanda, nu dupa politica)
-si `ntip=4` sunt fara plasa de siguranta.
-
-Cu `V_ID_POL = NULL`, `A.ID_POL = V_ID_POL` **nu se poate potrivi niciodata** (semantica SQL: orice
-comparatie cu `NULL` da `UNKNOWN`, niciodata `TRUE`, indiferent ce e stocat in `A.ID_POL`) —
-`SELECT ... INTO` (fara `DISTINCT`+agregat care sa tolereze zero randuri) **arunca mereu
-`NO_DATA_FOUND`**. Neprinsa aici, exceptia se propaga necaptata pana la apelantul PL/SQL (blocul
-anonim generat de VFP), care se intoarce la `goExecutor` ca eroare Oracle bruta (`ORA-01403: no
-data found`), **nu ca `FACT-024`** — vezi punctul 3 mai jos pentru diferenta.
-
-**Concluzie pas 1.3**: un articol fara politica (`V_ID_POL=NULL`, exact scenariul `cont_venit`)
-**nu poate fi adaugat pe un document `ntip=4`** — apelul `adauga_articol_factura` insusi esueaza,
-inainte ca `VANZARI_DETALII_TEMP` sa primeasca randul, deci **cu mult inainte** ca
-`contabilizeaza_articol` (unde e ramura noua `cont_venit`) sa vada vreodata acea linie.
-
-### 1.4. Blocajul secundar (daca 1.3 n-ar exista): `contabilizeaza_articol` insusi
-
-Chiar daca ipotetic linia ar ajunge in `VANZARI_DETALII_TEMP` cu `id_pol=NULL`, funcia care scrie
-efectiv factura are propria garda, **inaintea oricarui ntip**:
-```
-ff_...:7278-7302 BEGIN
- SELECT COMPUS, ID_POL_ART INTO V_COMPUS, V_ID_POL_ART
- FROM VCRM_POLITICI_PRET_ART
- WHERE ID_ARTICOL = detalii_articol.id_articol
- AND ID_POL = detalii_articol.id_pol;
- EXCEPTION
- WHEN NO_DATA_FOUND THEN
- ... RAISE_APPLICATION_ERROR(-20000, '... (FACT-024)');
- END;
-```
-Aceasta ruleaza **la inceputul functiei, inainte de `OPEN cursor_articol`** (`:7393`) si deci
-inainte de CASE-ul pe `ntip` (`:7398-7423`) si de IF-ul `ntip<>4` (`:7472`). Cu `id_pol=NULL`,
-`FACT-024` cade aici, indiferent de `ntip` — **confirma independent ca ramura `ntip=4` de la
-`:7520-7537` (`scrie_fact_aviz_custodie`) e neatinsa azi de o linie fara politica**, e a doua
-plasa de siguranta, redundanta cu 1.3 dar pe alt strat.
-
-**Ramura propusa `cont_venit IS NOT NULL`** (proiectare `canal_cont_venit_fara_politica.md`
-sectiunea 3) se planteaza "inainte de `:7278`" — deci **inlocuieste ambele garda de mai sus** cand
-`cont_venit` e populat. Asta e sigur (design-ul insusi), dar devine irelevant pentru `ntip=4`
-pentru ca linia nu ajunge niciodata aici (blocata la 1.3).
-
-## 2. Ce se intampla defensiv daca cineva ajunge totusi acolo
-
-Doua scenarii distincte, cu raspunsuri diferite:
-
-**(a) Scenariul normal — `cont_venit` populat, `id_pol` NULL (cum cere premiza proiectului)**:
-esec **la adaugarea articolului**, nu la scrierea facturii. Eroare Oracle bruta
-(`ORA-01403: no data found`), aparuta din `adauga_articol_factura` (`:5080-5103`), propagata prin
-`goExecutor` catre VFP ca `oPrelucrareEroare()` — **nu `FACT-024`** (acela e alt cod, alta functie,
-alt moment). Utilizatorul vede un mesaj Oracle generic, nu un mesaj de business explicativ. Nu
-exista azi niciun cod care sa traduca acest caz intr-un mesaj prietenos — e un gol de UX, nu de
-integritate a datelor (nu se scrie nimic gresit, doar esueaza fara explicatie buna).
-
-**(b) Scenariul defensiv real — `cont_venit` SI `id_pol` populate simultan pe aceeasi linie**
-(nimic in schema nu impune exclusivitate reciproca; `VANZARI_DETALII_TEMP.CONT_VENIT` e o coloana
-noua, fara `CHECK` care sa lege de `ID_POL`). Daca cineva (bug in VFP, sau folosire deliberata
-combinata pe viitor) ar trimite ambele populate pe un document `ntip=4`: pasul 1.3 ar reusi
-(`V_ID_POL` nu mai e NULL, deci `SELECT` din `VANZARI_DETALII` isi gaseste randul), linia intra in
-`VANZARI_DETALII_TEMP` cu `cont_venit` **si** `id_pol` completate. La `contabilizeaza_articol`,
-ramura noua (`detalii_articol.cont_venit IS NOT NULL`) preia controlul complet — **fara sa
-verifice `ntip`** — si executa necondiționat `scrie_nota` + `descarca_gestiune` + discount, exact
-ca pentru o factura normala. **Nu cade cu nicio eroare. Scrie tacut date gresite**: sare complet
-peste `scrie_fact_aviz_custodie` (`:7521-7536`), care exista tocmai pentru ca marfa a iesit deja
-din gestiune cand s-a scris avizul sursa — rularea `descarca_gestiune` in loc de acea functie
-**descarca stocul a doua oara** pentru aceeasi marfa, fara nicio garda care sa prinda dubla
-scadere. Acesta e raspunsul relevant pentru textul de plan: nu un crash, un **defect tacut de
-date** daca vreodata cele doua canale se intalnesc pe aceeasi linie.
-
-## 3. Toate valorile `ntip` relevante in zona `contabilizeaza_articol` (`:7173-7547`) — verdict per valoare
-
-Ramura noua (`cont_venit IS NOT NULL`) inlocuieste tot ce e listat mai jos, necondiționat de `ntip`
-(design-ul, sectiunea 3, nu mentioneaza `ntip` deloc in continutul ramurii noi). Verdictul de mai
-jos e "atinsa" = poate ajunge cu `cont_venit` populat prin `adauga_articol_factura` fara sa esueze
-la pasul 1.3-echivalent; "neatinsa" = blocata structural inainte de a ajunge aici (ca `ntip=4`);
-"ambigua" = depinde de alt cod neverificat complet in aceasta runda.
-
-| `ntip` | Comportament azi in `contabilizeaza_articol` | Atinsa de linie `cont_venit`? | Verdict fata de ramura noua |
-|---|---|---|---|
-| `<=20` sau `IN (43,44,45,46,48,49,51,52)` (`:7400-7412`) | SCD/ASCD din politica (`crs_rand_articol.scd`) — bucket "factura" | **DA** — `adauga_articol_factura` pentru aceste `ntip` foloseste calea generica (`ELSE`, `:5187-5203`, fara cerinta de `id_pol`) sau ramuri proprii (`2,6,26,52`→contract, `45`→restaurant) care oricum accepta `V_PRET_TEMP` cand nu gasesc potrivire | **E cazul acoperit de design** — SCD='4111' hardcodat e gandit exact pentru acest bucket. Fara probleme noi, cu exceptia sub-cazurilor de mai jos. |
-| `= 46` (`nTipNotaPlata`), sub-caz al bucketului "factura" | `scrie_nota` **NU se apeleaza** (`:7441`, `IF ntip <> nTipNotaPlata`) | DA (e in bucketul de mai sus) | **GOL SORA nou, neconsemnat in proiectare**: ramura noua apeleaza `scrie_nota` necondiționat — pentru un document `NotaPlata` cu linie `cont_venit`, s-ar scrie o nota care azi e sarita intentionat. De adaugat aceeasi garda in ramura noua. |
-| `= 7`, sub-caz al bucketului "factura" | `EXPLICATIE` primeste sufix `' INVOICE:' + cdescriere` (`:7431-7433`) | DA | **Gol cosmetic**: ramura noua foloseste direct `detalii_articol.explicatia`, fara sufix. Probabil acceptabil (design-ul il numeste "mai bun"), dar e o schimbare de continut pe documente de export, de confirmat. |
-| `IN (8,9)`, sub-caz al bucketului "factura" | `EXPLICATIE` primeste sufix `' RETUR FACTURA:' + cdescriere` (`:7434-7436`) | DA | Acelasi gol cosmetic ca mai sus. |
-| `IN (28,29)` (`:7413-7417`) | SCD hardcodat `'461'` — aviz catre clienti debitori | **DA** — `adauga_articol_factura` pentru `28` intra pe ramura `ntip IN (3,21,28,42,47)` (`:5053-5078`), care cauta in `COMENZI_ELEMENTE` dupa comanda+pret, **nu dupa `id_pol`** — un articol fara politica poate gasi potrivire aici daca exista element de comanda corespunzator | **GOL SORA, mai grav decat `ntip=4`**: ramura noua ar scrie `SCD='4111'` in loc de `'461'` pe un aviz catre client debitor — cont contabil gresit, atins efectiv. |
-| toate celelalte (`ELSE`, `:7418-7422`: `21,22,23,24,25,27,30,41,42,47,...`) | SCD hardcodat `'418'` — aviz generic | **DA, pentru aceleasi motive** (multe din aceste `ntip` — `3,21,42,47` — trec prin ramura "din comenzi" fara cerinta de `id_pol`; altele avansate direct din bucket implicit `ELSE` din `adauga_articol_factura`, `:5187-5203`, care nu cere `id_pol` deloc) | **Acelasi gol SCD hardcodat**, aplicabil la orice document de tip aviz (nu doar 28/29). |
-| `= 4` (`:7472,7520-7537`) | `scrie_fact_aviz_custodie` in loc de `descarca_gestiune`+discount | **NU** — exclus structural la pasul 1.3 (`adauga_articol_factura` esueaza inainte) | Neatins in scenariul normal (a); atins doar in scenariul defensiv (b) daca cineva forteaza `id_pol` si `cont_venit` simultan — vezi sectiunea 2. |
-
-**Cel mai important rezultat al acestui tabel**: golul cerut explicit (`ntip=4`) e cel **mai putin
-grav** dintre cele gasite, pentru ca e singurul exclus structural. Golurile reale, efectiv atinse,
-sunt hardcodarea `SCD='4111'` pe orice document de tip **aviz** (`28`,`29` si bucket-ul `ELSE`) si
-omisiunea gardei `ntip=46` pentru `scrie_nota`.
-
-## 4. Text propus pentru plan (sectiunea deciziei 34)
-
-```
-**Ramura `ntip=4` (facturare din avize, `:7520-7537`) — exclusa structural, nu necesita cod
-suplimentar.** `adauga_articol_factura`, ramura `WHEN ntip=4` (`:5080-5103`), cauta randul sursa
-din `VANZARI_DETALII` prin `A.ID_POL = V_ID_POL`, fara handler de exceptie — cu `V_ID_POL=NULL`
-(exact cazul liniei fara politica), comparatia nu se poate potrivi niciodata, deci apelul cade cu
-`ORA-01403` la adaugarea articolului, inainte ca linia sa ajunga la `contabilizeaza_articol`. Un
-articol fara politica nu poate fi, structural, adaugat pe un document `ntip=4`; ramura noua
-`cont_venit` nu are nimic de tratat aici.
-
-**Gol descoperit, de acoperit inainte de implementare**: ramurile de **aviz** (`ntip IN (28,29)` →
-`SCD='461'`, celelalte → `SCD='418'`, `:7413-7422`) **raman accesibile** cu `cont_venit` populat —
-`adauga_articol_factura` nu cere `id_pol` pentru aceste `ntip` (foloseste calea "din comenzi" sau
-calea implicita). Ramura noua trebuie sa aleaga `SCD` in functie de `ntip` (pastrand `'461'`/`'418'`
-pentru avize), nu sa hardcodeze `'4111'` necondiționat — altfel orice aviz cu articol fara politica
-primeste contul de clienti in loc de contul de aviz. Similar, ramura noua trebuie sa pastreze garda
-`IF ntip <> nTipNotaPlata` inainte de a apela `scrie_nota` (azi sarita pentru `ntip=46`).
-
-**Defensiv (opțional)**: daca se doreste o garda explicita in loc de a te baza pe imposibilitatea
-structurala de mai sus, se poate adauga `IF detalii_articol.cont_venit IS NOT NULL AND
-pack_facturare.ntip = 4 THEN RAISE_APPLICATION_ERROR(...)` la inceputul ramurii noi — util doar
-daca cineva ar reusi vreodata sa populeze simultan `id_pol` si `cont_venit` pe o linie `ntip=4`
-(azi imposibil pe caile VFP cunoscute), caz in care ramura noua ar rula altfel tacut
-`descarca_gestiune` in loc de `scrie_fact_aviz_custodie`, riscand dubla descarcare de gestiune.
-```
-
-## 5. Ce nu s-a putut stabili in aceasta runda
-
-- **Daca exista vreo cale VFP care sa populeze simultan `poArt.id_pol` si viitorul `cont_venit`**
- (scenariul defensiv (b)) — cercetarea de fata arata doar ca schema/codul Oracle nu o impiedica;
- n-am gasit (si nici n-am cautat exhaustiv) un loc in VFP care ar genera aceasta combinatie azi.
- Probabil imposibil pe fluxurile curente (proiectarea de baza presupune `cont_venit` populat
- **doar** cand `id_pol` lipseste), dar nu demonstrat exhaustiv pe tot codul VFP.
-- **Comportamentul exact `oExecute`/`oPrelucrareEroare` la o exceptie Oracle neprinsa** (scenariul
- (a)) — presupus ca ajunge la utilizator ca mesaj Oracle brut prin mecanismul general de eroare al
- `goExecutor`, dar nu am urmarit codul `oPrelucrareEroare()` in aceasta runda pentru a confirma
- formatarea exacta.
-- **Daca `ntip IN (23,25,30,41)` (transfer subunitati) si `IN (42,47)` (custodie) pot, in practica,
- sa primeasca un articol fara politica** prin ramura "din comenzi" a `adauga_articol_factura`
- (`:5053-5078`) — argumentat structural posibil (nu cere `id_pol`), dar nu testat pe date, nu
- urmarit pana la capat daca `COMENZI_ELEMENTE` insusi ar putea contine un rand fara politica.
-
-## Handoff
-
-Cercetare incheiata, toate cele 5 livrabile cerute de team-lead sunt in sectiunile 1-4 de mai sus.
-Niciun cod atins, nicio scriere Oracle, doar `SELECT`/`Read`/`Grep`. Context consumat moderat —
-nu a fost necesara predarea de context.
diff --git a/docs/cercetare/handoff_s4_runda1.md b/docs/cercetare/handoff_s4_runda1.md
deleted file mode 100644
index 3bc124f..0000000
--- a/docs/cercetare/handoff_s4_runda1.md
+++ /dev/null
@@ -1,191 +0,0 @@
-# Handoff — S4 runda 1 (PAGE3 doar afisare), predare pe prag de context
-
-Sesiune intrerupta la prag de context (`monitorizare-context.md`). Stare **stabila si consistenta**
-(text = binar), dar cu schele de diagnostic inca in cod — de scos inainte de livrare.
-
-## 1. Ce am modificat, unde, si write-back-ul
-
-Toate in `COMUN` (cross-proiect).
-
-- **`COMUN\programe\ofacturare_editare.prg`** — **write-back N/A (e `.prg`, nu `.vcx`, se ruleaza direct)**.
- Antet actualizat (linia cu `*!* helpere...`) + doua functii noi, adaugate la coada fisierului:
- - `IncarcaVanzareNota(tnCod, tnNract, tcSerieAct, tdDataAct)` — gaseste randul din `VANZARI`
- corespunzator notei curente, in cursorul `tvanz`.
- - `IncarcaArticoleFactura(tnIdVanzare)` — incarca liniile active din `VANZARI_DETALII` (+ denumire
- articol/gestiune/valuta) in cursorul `tvd`.
- Fisier ASCII (fara diacritice), editat direct cu Edit tool — fara riscul de corupere cp1252.
-
-- **`COMUN\clase\omodificari.vc2`** (clasa `frm_modific2024`) — **text si binar SINCRONIZATE**,
- ambele includ inca **cod de diagnostic care trebuie scos**:
- - PAGE3 nou pe `pgfArticole` (`PageCount=3`, `PAGE3.Caption="Articole factura"`) — linia cu
- `PageCount = 3, ;` in blocul `ADD OBJECT 'pgfArticole'`.
- - Grid nou `pgfArticole.PAGE3.grdArticoleFactura` (13 coloane, `RecordSource="tvd"`,
- `ReadOnly=.T.` la nivel de grid si pe fiecare `Text1`), plus intrarile `OBJECTDATA`
- corespunzatoare (cautabile dupa `grdArticoleFactura`).
- - Proprietati noi pe clasa: `lAreArticoleVanzari`, `nIdVanzare`, `nTipVanzare` (in blocul
- `*`, cautabile dupa `lareaarticolevanzari`/`nidvanzare`/`ntipvanzare`).
- - `Load()`: placeholder `CREATE CURSOR tvd (...)` daca nu e deja deschis — **necesar**, altfel
- grid-ul incearca `USE tvd` la constructie si pica pe dialog nativ "Open" (vezi sectiunea 4).
- - `Show()`: bloc nou (cautabil dupa `This.lAreArticoleVanzari`) care apeleaza
- `IncarcaVanzareNota`/`IncarcaArticoleFactura` si comuta `pgfArticole.PageCount` intre 2 si 3.
- - **DE SCOS inainte de livrare**: 5 linii `STRTOFILE(...'diag_class.txt'...)` inserate ca
- checkpoint-uri de depanare in `Init()` (3 linii: inceput, dupa `DoDefault()`, sfarsit) si
- `Load()` (2 linii: inceput, sfarsit) — cautabile dupa `diag_class`. Nu au efect functional
- (doar scriu intr-un fisier de log), dar nu trebuie sa ramana in cod livrat.
- - **Fidelity check txt2vcx: OK** la ultimul write-back (cel CU liniile de diagnostic inca in el).
- `.vcx`/`.vct` au mtime 12:10, exact dupa acel write-back — deci **binarul reflecta exact
- `.vc2`-ul curent**, inclusiv diagnosticul.
-
-### Backup-uri pe disc (`COMUN\clase\`)
-
-| Fisier | Continut |
-|---|---|
-| `omodificari.vc2.pre_s4runda1.bak` | Originalul, dinaintea oricarei modificari S4 |
-| `omodificari.vc2.pre_diag.bak` | Versiunea mea **curata** (fara cele 5 linii de diagnostic) — **asta e sursa de folosit pentru versiunea finala** |
-| `omodificari.vc2.mine_s4_full.bak` | Identic cu `pre_diag.bak` (copie facuta in timpul unui test de izolare) |
-| `omodificari.vcx.mine_s4.bak` / `omodificari.vct.mine_s4.bak` | **Binarul** corespunzator lui `pre_diag.bak`, copiat direct (fara compilare) — restaurare instantanee |
-
-**Pasul urmator recomandat**: `Copy-Item omodificari.vc2.pre_diag.bak -> omodificari.vc2`,
-`Copy-Item omodificari.vcx.mine_s4.bak -> omodificari.vcx` (+ `.vct`) — restaurare **instantanee**
-(fara `txt2vcx`) la versiunea curata cu PAGE3 functional, fara schela de diagnostic. Verifica dupa
-aceea cu un `diff` ca `omodificari.vc2` chiar nu mai contine `diag_class`.
-
-## 2. Ce mai ramane din runda 1
-
-Din sectiunea E / runda 1 a planului (A.2 PageCount + A.3 detectie + B.1 incarcare + B.2 marcaje):
-
-- **A.2 (PageCount)** — FACUT, testat static (fidelity OK), **netestat live pe formular** (vezi
- sectiunea 3 — blocaj de mediu, nu s-a ajuns sa vad `PageCount` pe formularul instantiat real).
-- **A.3 (detectie)** — FACUT, testat **direct** (fara UI) cu rezultate PASS pe date reale (sectiunea
- 3). Deviaza de la recomandarea planului (cauta si de ce, sectiunea 4).
-- **B.1 (incarcare cursoare)** — FACUT, testat direct, PASS.
-- **B.2 (marcaje stare linii)** — **NU e in scope runda 1** (grid-ul e strict readonly, fara
- editare — marcajele `_modificat`/`sters`/`id_vanzare_det=0` sunt pentru runda 2). Nu e inceput.
-
-**Ce lipseste efectiv**: verificarea end-to-end ca, pe formularul REAL (`Createobject('frm_modific2024')`
-+ `.Show()`), `PageCount` chiar ajunge 3 pe o factura si 2 pe o nota fara `VANZARI` — blocata de
-problema de mediu din sectiunea 3. Codul e scris si compilat curat; ramane doar confirmarea live.
-
-## 3. Ce am testat, cu ce rezultat
-
-Suita: `COMUN\utile\Teste\editare_factura\test_page3_articole.prg` (headless, `vfp9.exe -A -T`,
-conexiune reala `MARIUSM_AUTO`). Log: `test_page3_articole_log.txt` in acelasi folder.
-
-**PASS, pe date reale, testat direct (apel functie, fara formular)**:
-- `cod=1140888` → `IncarcaVanzareNota` gaseste `id_vanzare=1050`, `tip=1`; `IncarcaArticoleFactura`
- incarca 4 linii — coincide exact cu baza de regresie din `progres.md` (`TOTAL_CU_TVA=1924.59`).
-- `cod=1140885` → gaseste `id_vanzare=1047`, `tip=-12` (nu e factura, e alt tip de document) —
- confirma ca detectia functioneaza pe **orice** tip din `VANZARI`, nu doar facturi (decizia 19).
-- `cod=1125486` (an=2008, luna=2, notă contabila fara nicio legatura cu `VANZARI`) → 0 randuri
- gasite — cazul negativ cerut de criteriul de "gata" al rundei.
-- **Coliziune pe `cod=1139934`** (patru randuri active in `VANZARI`, acelasi cod): filtrul compus
- (cod+nract+serie_act+data_act) gaseste EXACT randul cerut (`nract=375/SSS` → `id_vanzare=882`) si
- NU gaseste nimic pentru un `nract` fara corespondent (`nract=13`) — vezi sectiunea 4, e important.
-
-**NETESTAT live (formular real)**: `verifica_pagecount_form` (in acelasi fisier de test) instantiaza
-`frm_modific2024` exact ca `do_editare_factura` (`Createobject`+`Show`) si verifica `PageCount` —
-**se blocheaza intr-un dialog nativ VFP "View Parameter"** in timpul `Createobject`, inainte sa
-apuce sa ruleze vreo linie din `Show()`. Vezi sectiunea 4 pentru diagnosticul facut si o pista noua,
-neexplorata inca, primita de la team-lead.
-
-**`test_baseline_isolation.prg`** (in acelasi folder) — **fisier temporar de diagnostic, se poate
-sterge** dupa ce cineva confirma diagnosticul de mai jos independent; nu face parte din suita
-finala (antetul lui o spune explicit). L-am folosit ca sa demonstrez ca **binarul ORIGINAL (dinainte
-de S4) NU are acest blocaj** in acelasi mediu de test (`PageCount=2`, `done`, fara dialog) — deci
-problema e din diff-ul meu, nu un gol preexistent de mediu.
-
-## 4. Descoperiri care nu trebuie pierdute
-
-### `VANZARI.COD` NU e unic — dovedit pe date, nu presupus
-
-Contrar recomandarii A.3 din plan ("`SELECT ... FROM vanzari WHERE cod = tact.cod`"), am verificat
-direct pe `MARIUSM_AUTO`:
-- Indexul `IDX_VANZARI_04` e pe `(STERS, COD)` si e **NONUNIQUE** — schema insasi nu garanteaza
- unicitate.
-- `cod=1139934` are **4 randuri active** (`STERS=0`) in `VANZARI`, cu `TIP`/`NUMAR_ACT` diferite
- (375/SSS, 24/PF, 25/PF, 26/PF). `cod=1139555` are 2 randuri cu `TIP` diferit (43 si 1).
-- Filtrarea suplimentara pe `NUMAR_ACT`+`SERIE_ACT`+`DATA_ACT` (toate disponibile pe cursorul `tact`
- ca `nract`/`serie_act`/`dataact`, din `vact_tot`) rezolva ambiguitatea: `(COD, NUMAR_ACT,
- SERIE_ACT, DATA_ACT)` verificat **fara nicio dublura** pe toata tabela `VANZARI`.
-- `ID_FACT` (alternativa mentionata in `progres.md` — "toate legaturile trec prin ID_FACT sau
- ID_VANZARE, niciodata prin cod") **nu e utilizabil ca filtru unic aici**: e `NULL` pe o fractie
- mare de randuri chiar si pentru facturi normale (`tip=1`: 58 din 183 `NULL`; `tip=51`: 58 din 74
- `NULL`), deci n-ar gasi avizele/tipurile fara facturare clasica — ar incalca decizia 19.
-
-**Concluzie aplicata in cod**: `IncarcaVanzareNota` filtreaza pe cele 4 coloane compuse, nu doar pe
-`cod`. Aceasta e o **corectie de fond fata de A.3 din plan**, nu o improvizatie — sectiunea C.1 din
-`plan_06_s4_proiectare.md` ar trebui sa mentioneze asta daca cineva o rescrie.
-
-### Blocaj "View Parameter" la `Createobject('frm_modific2024')` — cauza NECONFIRMATA
-
-Simptom: procesul `vfp9.exe` ramane blocat (CPU~0, Responding=True) intr-un dialog nativ **"View
-Parameter"** exact in timpul liniei `Createobject([frm_modific2024], lnIdSet)`, inainte sa ajunga
-la orice linie din `Show()` — confirmat cu checkpoint-uri `STRTOFILE` in `Init()`/`Load()` (niciunul
-nu s-a scris, deci blocajul e chiar mai devreme decat `Load()`, sau checkpoint-urile nu s-au atins
-din alt motiv neexplicat).
-
-**Exclus cu dovezi** (nu pierde timp re-verificand):
-- **Nu e cursorul `tvd` lipsa** — am incercat atat placeholder in `Load()`, cat si pre-creare in
- scriptul de test inainte de `Createobject`; blocajul a persistat identic.
-- **Nu e un gol de mediu preexistent** — binarul ORIGINAL (`omodificari.vcx.mine_s4.bak` restaurat
- temporar) ruleaza curat in ACELASI mediu de test (`test_baseline_isolation.prg`, `PageCount=2`,
- fara dialog). Deci e ceva din diff-ul meu.
-- **Un blocaj anterior, diferit** (`File 'crsjtvatemp.dbf' does not exist`, dialog "Open") era
- intr-adevar preexistent — cerut de `Column63` din `grdRulaje` (PAGE1, cod netusat de mine),
- rezolvat in scriptul de test cu `update_jtva_coloane("", "crsJtvaTemp", 0)` inainte de
- `Createobject` (nu in clasa — e o lipsa de mediu de test, nu de productie: in productie,
- `crsJtvaTemp` e populat pe alte cai inainte sa ajunga un utilizator la acest formular).
-- Am citit `_pageframe.Init()` (`_baza.vc2:514-523`, itereaza `For i = 1 To PageCount` si cheama
- `tradu(.Caption)`) ca prim suspect — **`tradu()` (`oproceduri_comune.prg:1746`) e confirmat
- inofensiv** (doar `STRTRAN` pe diacritice, fara Oracle/View). Nu e cauza, dar ramane singurul cod
- DEPENDENT de `PageCount` gasit prin cautare in `_baza.vc2`/`_frm_base.vc2`/`_grd_base.vc2`.
-- Am cautat "CREATE SQL VIEW" / `USE ... VIA` in toata ierarhia de clase (`omodificari`, `_baza`,
- `_frm_base`, `_grd_base`, `gridextras`) — **zero rezultate**. Niciun view local gasit static.
-
-**Pista noua, neexplorata** (primita de la team-lead, nu verificata de mine inca): dialogul "View
-Parameter" apare tipic cand o variabila referita prin `?variabila` (SQL passthrough) sau intr-un
-view parametrizat e declarata `LOCAL` in loc de `PRIVATE` intr-un harness de test — `LOCAL` nu e
-vizibil in rutinele apelate. Exemplu citat: `do_editare_factura` declara
-`Private pnAn, pnLuna, lnCod, lnIdFact, lnIdVanzare` (`ofacturare_comun.vc2:3742`). **Nu am apucat
-sa verific** daca `test_page3_articole.prg` foloseste `LOCAL` unde codul original ar cere `PRIVATE`
-undeva in lantul `IncarcaCursoareModificareNota`/`Createobject` — e primul lucru de incercat inainte
-de a relua sapatul cu `EnumWindows`/`PrintWindow` (costisitor, ~15 cicluri de test in aceasta
-sesiune doar pentru asta).
-
-## 5. Capcane de mediu platite in aceasta sesiune
-
-- **Sterge intotdeauna `.fxp`-ul vechi inainte de fiecare rulare de test** — m-a pacalit o data:
- am editat `.prg`-ul dar am uitat sa sterg `.fxp`, iar VFP a rulat tacut codul VECHI compilat,
- dand rezultate inconsistente intre rulari identice in aparenta. Simptom: log-ul arata alt
- comportament decat sursa curenta ar trebui sa produca.
-- **FoxBin2Prg NU pastreaza ordinea textuala la scriere-citire (roundtrip)** pentru ADD OBJECT
- multiple si proprietati custom — le REGENEREAZA in ordine proprie (alfabetica pentru
- coloane/obiecte fii, alta regula neclara pentru proprietati custom simple — `nidvanzare` a iesit
- INAINTEA lui `nid_set`, desi `_` < `v` in ASCII). Fidelity-check-ul compara text-sursa cu
- text-regenerat, deci **orice ordine "naturala" (alfabetica presupusa de mine) poate pica fidelity**.
- Solutie aplicata: dupa primul fidelity FAIL, am adoptat ca sursa noua textul regenerat din
- `\verify\*.vc2` (e deja in forma canonica), nu am incercat sa ghicesc ordinea corecta.
- Confirma exact indicatia din `flux-editare-vfp-text.md`.
-- **`InputMask` cu literal (nu `get_mask(...)`)** trebuie **ghilimeluit** (`"9.99"`), nu bar (`9.99`)
- — altfel VFP il interpreteaza numeric, nu ca string de format. Prins abia la inspectia manuala a
- textului regenerat, fidelity-check-ul NU l-a semnalat separat (a picat impreuna cu reordonarea).
-- **Grid nou cu `RecordSource` pe un cursor care nu exista inca la constructia formularului** →
- VFP incearca `USE ` ca fisier fizic si arata dialogul nativ "Open" daca nu-l
- gaseste pe disc — exact acelasi tipar deja documentat in clasa pentru `saft_taxtable`/
- `saft_mecanisme_plati` (`Load()`, verificat `If !Used(...)` inainte de orice altceva). Solutia
- e aceeasi: placeholder gol creat in `Load()`, INAINTE ca framework-ul sa construiasca grid-urile.
-- **Query-uri Oracle multiple rulate manual (sqlplus) au fost esentiale** pentru validarea empirica
- a filtrului compus pe `VANZARI` — nu s-ar fi descoperit coliziunea pe `cod` doar din cod static.
-
-## 6. Ce recomand pentru urmatorul agent
-
-1. Restaureaza versiunea curata (sectiunea 1, pasul recomandat) — 2 copieri de fisier, fara
- compilare, verifica cu `grep diag_class` ca a disparut.
-2. Incearca pista `LOCAL`/`PRIVATE` din sectiunea 4 pe `test_page3_articole.prg` inainte de orice
- 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 (diff aplicat (sters), `git diff --no-index `) 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.
diff --git a/docs/cercetare/idfact_refolosire_si_documente.md b/docs/cercetare/idfact_refolosire_si_documente.md
deleted file mode 100644
index 53d6b3c..0000000
--- a/docs/cercetare/idfact_refolosire_si_documente.md
+++ /dev/null
@@ -1,337 +0,0 @@
-Cercetare S9: reemiterea unui document cu acelasi ID_FACT (SET_IDFACT + DOCUMENTE)
-====================================================================================
-
-Verdict (rezumat)
-------------------
-**DA, dar cu conditii — nu e o schimbare izolata.** `SET_IDFACT` activ (`PACK_CONTAFIN.pck:3037-3040`)
-ia neconditionat un `ID_FACT` nou din `SEQ_IdFact`; niciun apelant din toata suita (~25-30 copii
-identice ale `oscrie_in_fisiere.prg`, cate una per produs) ii impune un `ID_FACT`. Varianta comentata
-(`:3016-3035`, cauta pe `NRACT+SERIE_ACT+DATAACT+ID_CTR` cu `STERS=0`) **nu rezolva S9** ca atare:
-dupa stergerea soft a documentului vechi, `STERS` e deja 1, cautarea nu-l gaseste, si cade tot pe
-secventa — plus riscul de coliziune cu un document viitor neinrudit care are aceleasi 4 campuri.
-Blocajul real nu e in `SET_IDFACT`, ci in scrierea din `DOCUMENTE`: acolo e un `INSERT` simplu
-(`:796-817`) pe `ID_DOC`, care e **PRIMARY KEY** (`PK_DOCUMENTE`, unic, `fn_script.sql:5192-5198`).
-Stergerea (`STERGE_DIN_ACT:1835-1855`) e soft-delete pur — `ACT.STERS=1`, apoi `DOCUMENTE.STERS=1`
-pentru id_fact-urile gasite pe acel `COD` — randul vechi **nu se sterge fizic**. Deci reemiterea cu
-acelasi `ID_FACT`, cu codul de azi neschimbat, ar arunca `ORA-00001` la insertul in `DOCUMENTE`,
-pentru ca randul cu acel `ID_DOC` inca exista (doar marcat `STERS=1`). Varianta `MERGE` deja
-comentata (`:818-847`) nu ajuta din prima: are doar `WHEN NOT MATCHED`, fara `WHEN MATCHED`, deci
-daca randul exista deja l-ar ignora tacit — documentul reemis ar ramane cu `DOCUMENTE.STERS=1`.
-Concluzie operationala: reutilizarea e posibila, dar cere trei schimbari simultane (detaliate la C.7),
-nu doar reactivarea codului comentat din `SET_IDFACT`.
-
-A. SET_IDFACT
---------------
-
-### A.1 — Ramura activa vs. ramura comentata
-
-Cod integral, `PACK_CONTAFIN.pck:3014-3040`:
-
-```
- ------------------------------------------------------------------------------------
- /* -- 25.02.2013 : am comentat pentru ca se face unirea id_fact pe listarea din JC/JV
- PROCEDURE SET_IDFACT(tdDataAct ACT_TEMP.DATAACT%TYPE,
- tcSerie_Act ACT_TEMP.SERIE_ACT%TYPE,
- tnNrAct ACT_TEMP.NRACT%TYPE,
- tnId_Ctr ACT_TEMP.ID_CTR%TYPE) IS
- V_ID_FACT DOCUMENTE.ID_DOC%TYPE;
- BEGIN
- BEGIN
- SELECT ID_DOC
- into pack_contafin.nIdFact
- FROM DOCUMENTE
- WHERE NRACT = tnNrAct
- AND NVL(SERIE_ACT, '+-') = NVL(tcSerie_Act, '+-')
- AND DATAACT = tdDataAct
- AND NVL(ID_CTR, 0) = NVL(tnId_Ctr, 0)
- AND STERS = 0;
- EXCEPTION
- WHEN NO_DATA_FOUND THEN
- SELECT SEQ_IdFact.NEXTVAL into pack_contafin.nIdFact FROM DUAL;
- END;
- END SET_IDFACT;*/
- ------------------------------------------------------------------------------------
- PROCEDURE SET_IDFACT(V_GCS IN VARCHAR2) IS
- BEGIN
- SELECT SEQ_IdFact.NEXTVAL into pack_contafin.nIdFact FROM DUAL;
- END SET_IDFACT;
-```
-
-Diferenta de comportament daca s-ar reactiva varianta comentata: in loc sa genereze mereu un
-`ID_FACT` nou, ar cauta intai in `DOCUMENTE` un document **nesters** (`STERS=0`) cu aceeasi
-combinatie `NRACT + SERIE_ACT + DATAACT + ID_CTR`, si doar daca nu gaseste nimic ar cere secventa.
-Doua probleme pentru S9:
-- **nu se aplica la reemitere**: documentul vechi e deja marcat `STERS=1` inainte de rescriere
- (vezi B.6), asa ca filtrul `STERS=0` nu-l gaseste — cade tot pe `SEQ_IdFact.NEXTVAL`, exact ca azi;
-- **risc de coliziune**: daca NRACT/SERIE_ACT/DATAACT/ID_CTR ar coincide intamplator cu alt document
- nesters (nu neaparat cel pe care il reemitem), i-ar imprumuta ID_FACT-ul aceluia.
-Semnatura veche are 4 parametri de identitate diferiti de semnatura activa (1 parametru `V_GCS`,
-folosit doar ca "user"/context, nefolosit in corp) — deci reactivarea ar cere fie o supraincarcare,
-fie schimbarea semnaturii peste tot unde e chemata (vezi A.2).
-
-### A.2 — Apelanti
-
-**Un singur punct de apel in PL/SQL**: `PACK_CONTAFIN.pck:721`, in bucla din `SCRIE_IN_ACT`:
-
-```
- pack_contafin.set_idfact(V_GCS);
- /* 25.02.2013 : se face cumularea id_fact pe listarea din RC/RJ
- PACK_CONTAFIN.SET_IDFACT(itemfact.dataact, itemfact.serie_act, itemfact.nract, itemfact.id_ctr);*/
- lnIdFact := get_idFact();
-```
-
-buclat pe grupuri distincte `(NRACT, DATAACT, DATAIREG, SERIE_ACT, ID_CTR, ID_SET)` extrase din
-`ACT_TEMP WHERE ID_FACT = -1` (`:713`) — deci `-1` e sentinela "acest rand cere un `ID_FACT` nou".
-
-`SCRIE_IN_ACT` insusi e apelat **doar pe drumul de scriere**, niciodata pe cel de stergere —
-in `finalizeaza_scriere_act_rul` (`:8449-8459`):
-
-```
- if tnScrieSterge <> 2 then
- pack_contafin.SCRIE_IN_ACT(user);
- ...
- else
- pack_contafin.STERGE_DIN_ACT(user, lnAn, lnLuna, tnCod, tnIdUtil, tnModificareNota);
- ...
-```
-
-Deci `SET_IDFACT` nu se atinge deloc la stergere — confirma ca azi cele doua operatii (stergere +
-reemitere) sunt independente unele de altele in privinta ID_FACT.
-
-**Cine cheama `final_scriere_act_rul_local` / `SCRIE_IN_ACT` din VFP**: acelasi fisier
-`COMUN\programe\oscrie_in_fisiere.prg`, replicat identic in ~25-30 produse ROA (verificat prin grep
-pe `*.prg` in tot `D:\ROA`): `ROAFACTURARE`, `ROACONT` (output), `ROAGEST`, `ROAIMOB`, `ROAEFACTURA`,
-`ROADEVIZE`, `ROAVIN`, `ROACASA`, `ROASAL`, `ROAPRETURI`, `ROAOBINV`, `ROARESTAURANT`,
-`ROACOMENZI`, `ROAAPROV`, `ROASITOP`, `ROASITFIN`, `ROADECL`, `ROASALSPEC`, `ROABAVERT`,
-`ROACONIMPORT`, `ROAPRINT`, s.a. — plus doua variante care apeleaza `SCRIE_IN_ACT` direct, fara
-wrapper-ul local: `CONTAFIN2ORA\VFP2ORA\Programe\oscrie_in_fisiere.prg:367`,
-`ROADEFSALARII\COMUN\programe\oscrie_in_fisiere.prg:141`,
-`ROARESTAURANTCONFIG\COMUN_ROA\programe\oscrie_in_fisiere.prg:135`.
-Un al doilea import vechi (`COMUN\datemenu\xold\import_xdbf\oscrie_in_fisiere.prg`) apare in multe
-produse dar e **comentat integral** (`*!*`) — inactiv.
-
-**Niciun apelant nu impune un `ID_FACT`.** Toti trimit `ID_FACT = -1` in `ACT_TEMP` (via
-`sql_temp_insert` in `oscrie_in_fisiere.prg:126-137`, care copiaza direct campurile din cursorul VFP,
-inclusiv `id_fact`) si lasa `SCRIE_IN_ACT` sa-l completeze din secventa. Confirmare suplimentara in
-`COMUN\clase\omodificari.vc2:4131-4132`: `"daca se schimba partenerul, se pune id_fact = -1 in loc
-de 0 pentru a se putea genera un nou id_fact"` — exact sentinela pe care se bazeaza bucla din
-`SCRIE_IN_ACT`.
-
-### A.3 — Variabila/parametru existent pentru un ID_FACT dorit
-
-**Nu exista azi.** `PACK_CONTAFIN` are o variabila de pachet `nIdFact` (setata de `SET_IDFACT`,
-citita de `GET_IDFACT`), dar e scrisa neconditionat de fiecare apel al lui `SET_IDFACT` — nu poate
-fi folosita ca "intrare" fara sa se schimbe corpul procedurii. Nu exista niciun `nid_...` global, nici
-alt parametru de sesiune care sa transmita un `ID_FACT` dorit lui `SET_IDFACT` sau lui `SCRIE_IN_ACT`.
-Ar trebui adaugata o variabila noua de pachet (ex. un "ID_FACT fortat", implicit `NULL`), citita
-**doar** in corpul activ al lui `SET_IDFACT`, consumata si resetata la prima folosire — vezi C.8.
-Acelasi diagnostic e deja notat in planul de proiect, `plan_13_unificare_formular_facturare.md:1717-1719`:
-`"ID_FACT. Se citeste inainte de stergere ... si se impune documentului nou, printr-un comutator
-folosit numai de regenerare. SET_IDFACT nu se schimba neconditionat — e cod comun intregii suite."`
-
-B. DOCUMENTE la reemitere cu acelasi ID_FACT
-----------------------------------------------
-
-### B.4 — INSERT sau UPDATE/MERGE azi
-
-`PACK_CONTAFIN.pck:788-817`, in interiorul buclei din `SCRIE_IN_ACT`, cod activ (INSERT simplu):
-
-```
- -- SCRIE IN DOCUMENTE
- lnTvaIncasare := case when itemfact.tva_incasare > 0 then 1 else 0 end;
- -- 25.02.2013 : am repus insertul pentru ca se face cumularea id_fact pe listarea din RC/RJ
- INSERT INTO DOCUMENTE
- (ID_DOC, ID_UTIL, DATAORA, TVA_INCASARE, SERIE_ACT, NRACT, DATAACT, DATAIREG, ID_CTR, ID_SET)
- VALUES
- (lnIdFact, lnID_Util, LD_DATAORA, lnTvaIncasare, itemfact.serie_act, itemfact.nract,
- itemfact.dataact, itemfact.dataireg, decode(itemfact.id_ctr, 0, NULL, itemfact.id_ctr),
- itemfact.id_set);
- /*
- -- modificare ROACONT v 2.4.0 (27.12.2012): am adaugat serie_act, nract, dataact
- -- modificare 21.02.2013: am adaugat id_ctr
- MERGE INTO DOCUMENTE A
- USING (SELECT lnIdFact as ID_DOC, itemfact.serie_act as SERIE_ACT, itemfact.nract as NRACT,
- itemfact.dataact as DATAACT,
- decode(itemfact.id_ctr, 0, NULL, itemfact.id_ctr) AS ID_CTR
- FROM DUAL) B
- ON (A.ID_DOC = B.ID_DOC)
- WHEN NOT MATCHED THEN
- INSERT (ID_DOC, ID_UTIL, DATAORA, TVA_INCASARE, SERIE_ACT, NRACT, DATAACT, ID_CTR)
- VALUES (B.ID_DOC, lnID_Util, LD_DATAORA, lnTvaIncasare, B.SERIE_ACT, B.NRACT, B.DATAACT, B.ID_CTR);*/
-```
-
-Deci **azi e mereu un INSERT nou** — pe drumul normal (ID_FACT vine din secventa, mereu inexistent
-in `DOCUMENTE`) asta e corect, dar pentru cazul S9 (ID_FACT reutilizat, deja existent — chiar si
-soft-sters) INSERT-ul ar da eroare de unicitate (vezi B.5). Varianta `MERGE` comentata are doar
-`WHEN NOT MATCHED` — daca s-ar reactiva neschimbata, un `ID_DOC` deja existent ar fi pur si simplu
-ignorat (fara `WHEN MATCHED`), documentul reemis ramanand cu randul vechi din `DOCUMENTE`
-(cu `TVA_INCASARE`/`ID_SET` nemodificate si, mai grav, cu `STERS` neresetat — vezi B.6).
-
-### B.5 — Constrangere de unicitate pe DOCUMENTE
-
-DDL gasit in `D:\ROA\DATABASE\ALTELE\Creare_server_scripturi\FirmaNoua\fn_script.sql:5162-5198`:
-
-```
-CREATE TABLE "DOCUMENTE" ("ID_DOC" NUMBER(20, 0) NOT NULL ENABLE, "DATAORA" DATE NOT NULL ENABLE,
- "ID_UTIL" NUMBER(5, 0) NOT NULL ENABLE, "STERS" NUMBER(1, 0) NOT NULL ENABLE,
- "DATAORAS" DATE, "ID_UTILS" NUMBER(5, 0) NOT NULL ENABLE) ...
-...
-CREATE UNIQUE INDEX "PK_DOCUMENTE" ON "DOCUMENTE" ("ID_DOC") ...
-ALTER TABLE "DOCUMENTE" ADD CONSTRAINT "PK_DOCUMENTE" PRIMARY KEY ("ID_DOC") USING INDEX ... ENABLE
-```
-
-**Da: `ID_DOC` e PRIMARY KEY, unic.** (Coloanele `SERIE_ACT/NRACT/DATAACT/DATAIREG/ID_CTR/ID_SET/
-TVA_INCASARE` din INSERT-ul de la B.4 nu apar in acest script — script vechi de firma noua,
-probabil tabela a fost alterata ulterior cu `ALTER TABLE ADD COLUMN`; constrangerea de PK insa e
-stabila si nu are motiv sa fi fost scoasa.) Un `INSERT INTO DOCUMENTE (ID_DOC=...)` cu o valoare de
-`ID_DOC` care exista deja (chiar si `STERS=1`) arunca `ORA-00001: unique constraint (PK_DOCUMENTE)
-violated`. Nu am gasit alta constrangere de unicitate pe `DOCUMENTE`; nici FK de la `ACT.ID_FACT`
-catre `DOCUMENTE.ID_DOC` (`ACT.ID_FACT` e doar indexat, `IDX_ID_FACT`, `fn_script.sql:1637`, fara
-constrangere de integritate referentiala gasita) — deci reinserarea de randuri in `ACT` cu
-`ID_FACT` reutilizat **nu** e blocata de vreo constrangere pe `ACT` insusi; blocajul e exclusiv pe
-`DOCUMENTE`.
-
-### B.6 — Randurile vechi la stergere: fizic sterse, STERS=1, sau raman
-
-**Soft-delete pur, pe toate cele patru tabele relevante — nimic nu se sterge fizic.**
-
-`STERGE_DIN_ACT` (`PACK_CONTAFIN.pck:1815-1859`), apelata din `finalizeaza_scriere_act_rul` cand
-`tnScrieSterge = 2`:
-
-```
- PROCEDURE STERGE_DIN_ACT(V_GCS VARCHAR2, tnAn in number, tnLuna in number, tnCod in number,
- tnId_utils in number, tnTip IN NUMBER) is
- -- tnTip : 0 = modificare ; 1 = stergere
- ...
- BEGIN
- ...
- UPDATE /*+ index(ACT IDX_COD) */ ACT
- SET STERS = 1, DATAORAS = LD_DATAORA, ID_UTILS = lnId_util
- WHERE COD = tnCod and an = tnAn and luna = tnLuna;
-
- IF lnTip = 1 THEN
- UPDATE DOCUMENTE
- SET STERS = 1, ID_UTILS = LNID_UTIL, DATAORAS = LD_DATAORA
- WHERE ID_DOC IN
- (SELECT /*+ index(ACT IDX_COD) */ DISTINCT ID_FACT
- FROM ACT
- WHERE COD = tnCod and an = tnAn and luna = tnLuna
- AND ID_FACT <> 0
- and ID_SET not in (90501, 90021)
- AND NOT (SCD = '4426' AND SCC = '4428')
- AND NOT (SCD = '4428' AND SCC = '4427'));
- END IF;
-
- update act_temp set suma = -suma, suma_val = -suma_val;
- END STERGE_DIN_ACT;
-```
-
-`ACT` -> `STERS=1` (randurile raman fizic, pe acelasi `COD`). Cand `tnTip=1` (stergere, nu simpla
-modificare), **`DOCUMENTE` primeste si el `STERS=1`**, pentru toate `ID_FACT` distincte gasite pe
-acel `COD` in `ACT` (cu exceptiile de mai sus pentru seturi/conturi speciale). Nicaieri nu am gasit
-un `UPDATE DOCUMENTE ... SET STERS = 0` — cautare exhaustiva in `PACK_CONTAFIN.pck` (`grep -i
-"UPDATE DOCUMENTE"`) a dat un singur rezultat, cel de mai sus. Deci nu exista azi niciun mecanism
-care sa "reinvie" un rand din `DOCUMENTE`.
-
-La fel, `STERGE_DIN_RUL` / `STERGE_DIN_RUL_OBINV` (`:1861-1893`) fac `UPDATE ... SET STERS = 1` pe
-`RUL`/`RUL_OBINV`, fara stergere fizica.
-
-Pentru `IREG_PARTENERI` si `JV2007` situatia e diferita in mod util pentru S9: acestea nu sunt copii
-1:1 ale documentului, ci **agregate recalculate prin `MERGE`** pe chei de business (an, luna, cont /
-`ID_FDOC`, `ID_FACT`, `NRACT`, `SERIE_ACT`, `DATAACT`, `DATAIREG`, `ID_PART`, ...) — vezi
-`SCRIE_JV_2007` (`:3328-3373+`) si `SCRIE_IN_IREG_PARTENERI`/`EXECUTA_SCRIE_IN_IREG` (`:7030+`,
-`:7607+`). Ambele sunt apelate **si pe drumul de scriere, si pe cel de stergere**
-(`finalizeaza_scriere_act_rul:8495-8578`, fara conditie pe `tnScrieSterge` in afara sursei: `act_temp`
-la scriere/stergere, `act` la refacere). La stergere, `sterge_document` (`:7699-8118`) reinsereaza in
-`ACT_TEMP` copii ale randurilor vechi din `ACT`/`RUL`/`RUL_OBINV`, **cu acelasi `ID_FACT` ca inainte**
-(coloana `id_fact` e copiata direct din sursa, nu resetata la `-1`), asa ca `MERGE`-ul din
-`SCRIE_JV_2007`/`SCRIE_IN_IREG_PARTENERI` recalculeaza (compenseaza) exact randul cu acel `ID_FACT`
-— nu creeaza duplicate. Deci reutilizarea `ID_FACT`-ului **nu produce dubluri in `JV2007`/
-`IREG_PARTENERI`**; problema e strict izolata la `DOCUMENTE`.
-
-Nota din plan, care confirma independent aceasta zona de risc:
-`plan_13_unificare_formular_facturare.md:1737`: `"De verificat si daca DOCUMENTE primeste un al
-doilea rand pe acelasi ID_DOC sau il refoloseste."` — raspunsul, dupa aceasta cercetare: **niciuna
-din cele doua, in starea actuala a codului — ar arunca eroare de unicitate**, nu ar produce liniste
-tacuta cu duplicat sau refolosire.
-
-C. Verdictul care conteaza
-----------------------------
-
-### C.7 — Se poate reemite cu acelasi ID_FACT fara sa se strice nimic?
-
-**DA, dar cu conditii** — niciuna dintre ele nu e implementata azi:
-
-1. **Nu folosi varianta comentata a lui `SET_IDFACT` ca atare.** Cautarea `STERS=0` nu gaseste
- documentul (deja sters soft inainte de rescriere) si e vulnerabila la coliziuni pe chei de
- business partajate cu alt document. In loc de cautare, ID_FACT-ul trebuie **citit explicit
- inainte de stergere** (VFP il are deja in cursorul documentului editat) si **transmis** pe drumul
- de scriere — exact ce zice planul S9.
-2. **`SET_IDFACT` are nevoie de o cale de intrare noua, inerta implicit.** O variabila de pachet
- noua (ex. "ID_FACT fortat", `NULL` default) + o procedura noua de setat-o explicit inainte de
- scriere; corpul activ al `SET_IDFACT` verifica intai variabila, o consuma si o reseteaza; daca e
- `NULL` (cazul general — toate celelalte ~25-30 apeluri din suita), comportamentul e identic cu
- azi (secventa). Nu se toarna in semnatura existenta `SET_IDFACT(V_GCS)`, ca sa nu se schimbe
- apelul de la niciun alt caller.
-3. **Scrierea in `DOCUMENTE` trebuie sa devina un upsert real, cu `WHEN MATCHED`.** Nici INSERT-ul
- activ, nici MERGE-ul comentat (fara `WHEN MATCHED`) nu revigoreaza un rand soft-sters. E nevoie de
- un `MERGE ... WHEN MATCHED THEN UPDATE SET STERS = 0, DATAORA = ..., ID_UTIL = ..., TVA_INCASARE
- = ..., SERIE_ACT = ..., NRACT = ..., DATAACT = ..., DATAIREG = ..., ID_CTR = ..., ID_SET = ...`
- pe langa `WHEN NOT MATCHED THEN INSERT` (cazul normal, ID_FACT nou din secventa).
-4. **Succesiunea corecta**, in aceeasi tranzactie (deja planificata in S9 la nivel de VFP — vezi
- `plan_13...md:1713-1719`, mutarea stergerii in tranzactia deschisa de scriere): sterge documentul
- vechi (soft-delete, ca azi) -> seteaza variabila de la punctul 2 cu `ID_FACT`-ul citit inainte de
- stergere -> scrie documentul nou prin drumul obisnuit (`ACT_TEMP` cu `ID_FACT = -1` ca de obicei,
- dar acum grupul respectiv va primi ID_FACT-ul fortat in loc de unul nou) -> commit doar dupa ce
- ambele operatii au avut succes; orice eroare -> rollback total, documentul vechi ramane intact.
-
-- **NU** (fara aceste conditii): `INSERT INTO DOCUMENTE` cu `ID_DOC` reutilizat, cat timp randul vechi
- e inca prezent cu `STERS=1`, arunca `ORA-00001` pe `PK_DOCUMENTE` — asta e dovada, nu presupunere
- (B.5 + B.4).
-
-### C.8 — Suprafata de risc pentru restul suitei
-
-- **~25-30 cai de apel** trebuie sa ramana neafectate: toate copiile `COMUN\programe\
- oscrie_in_fisiere.prg` din fiecare produs ROA (listate in A.2), plus cele 3 variante care apeleaza
- `SCRIE_IN_ACT` direct. Toate trec prin acelasi punct final: `SET_IDFACT(V_GCS)` in
- `PACK_CONTAFIN.pck:3037`.
-- **Garantia structurala propusa**: variabila de pachet noua, default `NULL`/inert, citita **doar**
- in interiorul corpului activ al lui `SET_IDFACT` (nu in semnatura, nu in vreun parametru propagat
- de apelanti); se seteaza explicit **doar** de codul de regenerare din ROAFACTURARE, chiar inainte
- de a incepe scrierea documentului reemis, si se consuma/reseteaza la prima citire (fie in
- `SET_IDFACT`, fie la finalul tranzactiei, ca sa nu "scurgi" valoarea catre urmatoarea scriere
- neinrudita din aceeasi sesiune Oracle — relevant daca `goExecutor`/conexiunea e reutilizata intre
- operatii ale aceluiasi utilizator in acelasi produs). Cu default inert si citire localizata strict
- in corpul lui `SET_IDFACT`, toate celelalte ~25-30 cai raman byte-for-byte identice cu azi — nu e
- nevoie sa se verifice fiecare apelant individual, garantia e la sursa (variabila neinitializata =
- comportament vechi).
-- **Riscul real nu e in `SET_IDFACT`, ci in `DOCUMENTE`.** Schimbarea INSERT->MERGE cu `WHEN MATCHED`
- la `PACK_CONTAFIN.pck:796-817` e riscanta pentru toata suita in alt sens: `WHEN MATCHED` s-ar
- declansa doar cand `ID_DOC` (generat din secventa) coincide cu unul existent — ceea ce, pe drumul
- normal, nu se intampla niciodata (secventa e monoton crescatoare, nu se repeta), deci practic
- ramura noua e inerta pentru toti apelantii actuali si activa doar cand variabila de la C.8 a fost
- setata explicit. Totusi orice modificare la acest INSERT/MERGE e in cod comun apelat de toata
- suita si trebuie testata pe cel putin un ciclu normal de scriere (fara variabila fortata) in
- fiecare produs care scrie facturi/note, nu doar in ROAFACTURARE.
-
-Ramas de verificat pe baza vie
---------------------------------
-- Structura curenta reala a tabelei `DOCUMENTE` (DDL-ul citat e dintr-un script vechi de "firma
- noua"; coloanele `SERIE_ACT/NRACT/DATAACT/DATAIREG/ID_CTR/ID_SET/TVA_INCASARE` folosite de
- INSERT-ul activ nu apar in acel DDL — probabil adaugate ulterior prin `ALTER TABLE`). De rulat pe
- baza vie: `SELECT column_name, nullable FROM user_tab_columns WHERE table_name = 'DOCUMENTE'
- ORDER BY column_id;` si `SELECT constraint_name, constraint_type FROM user_constraints WHERE
- table_name = 'DOCUMENTE';` — sa se confirme ca `PK_DOCUMENTE` e inca activa si ca nu exista alta
- constrangere aparuta intre timp.
-- Daca exista deja documente reale in productie unde `DOCUMENTE.ID_DOC` a fost, intr-un fel sau
- altul, reutilizat (ex. printr-o interventie manuala) — de verificat cu
- `SELECT id_doc, count(*) FROM documente GROUP BY id_doc HAVING count(*) > 1;` (ar trebui sa fie
- gol, dat fiind PK-ul, dar merita confirmat inaintea oricarei schimbari).
-- Comportamentul exact al `finalizeaza_stergere_nota`/`finalizeaza_modificare_nota` (`:8601+`,
- nu au fost citate integral aici) fata de `ID_FACT`/`ID_FACTD` — relevante daca reemiterea schimba
- seria/numarul, nu doar continutul (cazul S9 "de baza" e cel mai simplu: acelasi NRACT/SERIE_ACT).
-- Comportamentul lui `EXECUTA_SCRIE_TVA`/`SCRIE_JC_2007` (mentionate la `:8504-8540`, cazul an <
- 2007 sau JC) fata de reutilizarea ID_FACT — nu au fost verificate in detaliu, doar `SCRIE_JV_2007`.
-- Nu am putut testa efectiv (fara acces la baza vie) daca `ORA-00001` e chiar eroarea ridicata de
- Oracle in acest scenariu exact — e o deductie directa din DDL (PK unic + INSERT simplu pe coloana
- respectiva), dar merita o rulare de proba pe o baza de test inainte de a proiecta solutia finala.
diff --git a/docs/cercetare/idpol_comanda_contract.md b/docs/cercetare/idpol_comanda_contract.md
deleted file mode 100644
index 3b108a2..0000000
--- a/docs/cercetare/idpol_comanda_contract.md
+++ /dev/null
@@ -1,553 +0,0 @@
-# De unde vine SCC-ul pe facturile din comandă/contract — și dacă modelul se poate refolosi pentru #13
-
-Cercetare read-only, pe cod (VFP text + export `PACK_FACTURARE` curent) și pe baza vie (`MARIUSM_AUTO`
-pe `ROA_CENTRAL`, doar `SELECT`, 10.08.2026). Nu modifică nimic — nici `pack_facturare`, nici
-`ofacturare_comun.vc2`, nici `ofacturare_editare.prg`.
-
-Continuă `docs\cercetare\coresp_cont_venchelt.md` (secțiunea 9) și `docs\plan_13_unificare_formular_facturare.md`
-(J-quater), care stabiliseră deja: FACT-024 verifică apartenența articolului la politica **de pe linie**,
-`id_pol` e parametru per-linie trimis de VFP (`V_ID_POL`, `adauga_articol_factura`), și pe contract
-articolul „liber" nu e de fapt fără politică — vine deja cu una atașată prin `cursor_contract`/`cursor_preturi`.
-
-**Runda 2 (reformulare Marius):** prima trecere de mai jos (secțiunile D–C, păstrate ca dovadă) presupunea
-că întrebarea era „de unde vine `id_pol`". Marius a corectat premisa: el chiar emite facturi pe bază de
-document care **nu au** politică de preț și notă atașată **prin lanțul obișnuit** — ceea ce contrazicea
-concluzia inițială („`id_pol` gol → `FACT-024`, mereu"). Secțiunea 0 de mai jos reconciliază contradicția,
-pe cod și pe date reale, și e livrabilul principal al acestei runde. Sursa SQL folosită în ambele runde:
-`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (823.337 octeți — fișierul
-cu același nume din `docs\` a fost șters în timpul sesiunii anterioare; numerele de linie de mai jos sunt
-verificate direct pe fișierul din `SCRIPTURI_CLAR`, nu preluate din plan).
-
----
-
-## 0. Reconcilierea contradicției — Marius are dreptate, dar mecanismul nu e cel presupus în runda 1
-
-**Verdict, cu citat**: `id_pol` `NULL` **tot** blochează `contabilizeaza_articol` necondiționat — asta nu
-s-a schimbat, e reconfirmat mai jos. Ce s-a stabilit greșit în runda 1 e presupunerea că **orice** linie de
-document trece prin `contabilizeaza_articol`. **Nu e adevărat**: pachetul are cel puțin **două rute
-paralele**, folosite azi în producție (confirmate pe date reale), care scriu o notă contabilă de vânzare
-**fără `id_pol` și fără `CRM_POLITICI_PRETURI`** — pentru că nu apelează deloc `contabilizeaza_articol`.
-
-### 0a. Reconfirmare: `contabilizeaza_articol` nu tolerează `id_pol NULL`, în nicio ramură
-
-```sql
--- ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:7275-7302 (inceputul functiei, necondiționat)
-BEGIN
- BEGIN
- SELECT COMPUS, ID_POL_ART
- INTO V_COMPUS, V_ID_POL_ART
- FROM VCRM_POLITICI_PRET_ART
- WHERE ID_ARTICOL = detalii_articol.id_articol
- AND ID_POL = detalii_articol.id_pol; -- id_pol NULL => X=NULL => NO_DATA_FOUND, mereu
- EXCEPTION
- WHEN NO_DATA_FOUND THEN
- ... SELECT NUME_LISTA_PRETURI INTO lcPolitica FROM CRM_POLITICI_PRETURI WHERE id_pol = detalii_articol.id_pol;
- RAISE_APPLICATION_ERROR(-20000, '... (FACT-024)');
-```
-Nu există niciun `IF detalii_articol.id_pol IS NULL THEN ...` înainte de acest bloc — e primul lucru pe
-care funcția îl face, necondiționat, pentru orice apel. **Bonus, deja semnalat în runda 7** (`plan_13...
-md:1451-1457`, reconfirmat aici pe fișierul curent): al doilea `SELECT` din `EXCEPTION` (cel care aduce
-`lcPolitica` pentru mesaj) filtrează tot pe `id_pol = detalii_articol.id_pol`, deci și el dă `NO_DATA_FOUND`
-când `id_pol` e `NULL` — utilizatorul nu vede mesajul formatat „FACT-024", ci un `ORA-01403` brut,
-necaptat. În ambele cazuri: **eroare, tranzacție întreruptă, nimic scris**. Deci dacă o linie chiar ajunge
-la `contabilizeaza_articol` cu `id_pol` gol, nu există azi nicio cale silențioasă de succes.
-
-### 0b. Ce am găsit real, pe date vii — 384 din 1113 linii `VANZARI_DETALII` active (34%) au `ID_POL` `NULL`
-
-```sql
-select count(*), sum(case when id_pol is null then 1 else 0 end) from vanzari_detalii where sters=0;
--- 1113 384
-```
-Deci liniile facturate fără `id_pol` **există masiv** în producție — nu e un caz exotic. Împărțite pe
-`VANZARI.TIP`:
-
-| `TIP` | linii fără `id_pol` | din ele, rânduri `ACT` cu `SCC` populat | interpretare |
-|---|---|---|---|
-| `-12` | 97 | 588/604 | **ROAAUTO** (confirmat, `tip=-12` e explicit ROAAUTO — `plan_13...md:1710,1735`) |
-| `-1..-13` (restul) | ~140 | majoritar populat | variante storno/aviz ale documentelor de mai jos, nu cercetate individual |
-| `2` (**contract**) | 19 | populat, vezi 0c | facturare pe bază de contract, **rată/scadențar**, nu articol |
-| `1` (listă prețuri) | 1 | — | un singur caz, neexplorat separat |
-| `51` | 121 | 179/275 (cumulat) | tip necunoscut în codul VFP citit — posibil retail/POS, neidentificat |
-| **`3` (comandă, ROAFACTURARE)** | **0 din 66** | — | **niciun caz** — vezi 0d |
-
-`select count(*), sum(case when id_pol is null then 1 else 0 end) from vanzari_detalii d join vanzari v on v.id_vanzare=d.id_vanzare where d.sters=0 and v.sters=0 and v.id_comanda is not null` → **66 / 0**. Pe ruta
-`COMENZI` a lui ROAFACTURARE (secțiunea A de mai jos), **`id_pol` nu e niciodată gol, pe datele disponibile.**
-Contradicția lui Marius nu se reproduce pe acest obiect precis.
-
-### 0c. Mecanismul găsit: `contabilizeaza_rata` — notă contabilă direct din contract, fără politică, fără `id_pol`
-
-Contractele cu facturare pe **rate/scadențar** (`CONTRACTE.OPT_FACTURARE IN (1,2)`) nu trec liniile prin
-`contabilizeaza_articol` — trec prin o funcție **separată**, `contabilizeaza_rata`:
-```sql
--- ff_...:7549-7597
-FUNCTION contabilizeaza_rata(detalii_rata VANZARI_DETALII_TEMP%ROWTYPE) RETURN NUMBER IS
-BEGIN
- BEGIN
- SELECT NVL(B.ID_VENCHELT, pack_facturare.nid_venchelt), ..., C.SCD, C.ASCD, C.SCC, C.ASCC, C.CU_TVA, C.IN_VALUTA
- INTO ...
- FROM CONTRACTE A
- LEFT JOIN CRM_NOTE_VANZARI B ON A.ID_NOTA = B.ID_NOTA -- <- nota vine din CONTRACTE.ID_NOTA, NU din id_pol
- LEFT JOIN NOTE_CONTABILE C ON B.ID_SET = C.ID_SET
- WHERE A.STERS = 0 AND A.ID_CTR = detalii_rata.id_ctr AND B.STERS = 0;
- EXCEPTION
- WHEN NO_DATA_FOUND THEN
- RAISE_APPLICATION_ERROR(-20000, 'Nu sunt configurate notele de vanzare pentru acest contract!');
- END;
- ...
- V_INCASAT_CALCUL := V_INCASAT_CALCUL + pack_facturare.scrie_nota(..., V_SCD, V_ASCD, V_SCC, V_ASCC, ...);
-```
-`CONTRACTE` are coloană proprie `ID_NOTA` (confirmat pe schema vie: `NUMBER`, nullable) — **contractul însuși
-duce nota contabilă**, ales o singură dată la configurarea lui, independent de orice `id_pol`/politică de
-preț per articol. Confirmă exact tiparul din `cursor_contract` (secțiunea B mai jos, ramura „rată" a
-cursorului, `ff_...:2837-2893`): `NULL as id_articol, ..., NULL AS ID_POL` — liniile de rată **nu au
-niciodată `id_pol`, prin construcție**, pentru că nu sunt articole din nomenclator, sunt rate de scadențar.
-
-**Confirmat pe o factură reală** (`MARIUSM_AUTO`, 10.08.2026):
-```sql
--- id_vanzare 360, tip 2 (contract), linia din VANZARI_DETALII: id_articol NULL, id_pol NULL
--- ACT pentru id_fact=5039903:
--- ID_ACT SCD ASCD SCC ASCC SUMA EXPLICATIA
--- 102204 4111 11 704 300 RATA 1
--- 102205 4111 11 4427 57 TVA RATA 1
-```
-O factură reală, cu o linie fără `id_articol` și fără `id_pol`, **cu notă contabilă scrisă corect** (`SCD
-4111`, `SCC 704`) — exact dovada cerută. Mecanismul: **nota nu vine prin politică deloc**, vine direct din
-`CONTRACTE.ID_NOTA`, o singură dată per contract, la configurare — un tipar „un document duce o notă fixă",
-nu „fiecare linie duce o politică de preț".
-
-### 0d. De ce nu se reproduce pe `COMENZI` (ROAFACTURARE): tabelul nu are echivalentul lui `ID_NOTA`
-
-```sql
-select column_name from user_tab_columns where table_name='COMENZI';
--- ID_COMANDA, NR_COMANDA, DATA_COMANDA, ID_PART, ID_GESTIUNE, ID_SECTIE, ID_SECTIE2, ID_CTR, ... (29 coloane)
--- nicio ID_NOTA, nicio ID_POL, nicio coloana de contabilizare
-```
-`COMENZI` (antetul) nu duce nicio informație contabilă — singura legătură posibilă e `ID_CTR` (dacă
-comanda vine dintr-un contract). `COMENZI_ELEMENTE.ID_POL` rămâne singurul canal, și e `NOT NULL` (secțiunea
-A). Deci pe **acest** obiect, mecanismul „notă fără politică" descris de Marius **nu există** — dacă
-experiența lui vine de aici, ar însemna fie (a) o versiune de bază/schemă diferită de `MARIUSM_AUTO`, fie
-(b) o factură pe care a facturat-o efectiv prin ruta **contract cu rate** (secțiunea 0c) sau prin **ROAAUTO**
-(`tip -12`, deviz — tipar deja documentat în `coresp_cont_venchelt.md` §9b: `adauga_articol_factura_deviz`
-→ `scrie_in_vanzari`, fără `contabilizeaza_articol`, cu notă scrisă separat de fiecare produs), și a numit-o
-generic „factură pe bază de comandă". **Nu pot decide între aceste ipoteze fără să întreb** — dovada de cod
-și de date arată clar CARE mecanisme există și niciunul nu e pe `COMENZI` propriu-zis.
-
-### 0e. Variantele din brief, verdict pe fiecare
-
-- *„liniile de comandă primesc totuși un `id_pol` de undeva"* — **confirmat, dar nu ascuns**: da, primesc,
- documentat deja în secțiunea A/D veche, e vizibil în UI (`v_articole`), nu explică „fără politică".
-- *„`contabilizeaza_articol` nu e apelată pe ruta comandă, ci altă procedură"* — **fals pentru `COMENZI`**
- (`ofacturare.prg:292-293` → `cursor_comanda` → `crsarticole` → `do_scrie_articole` → `adauga_articol_factura`
- → `contabilizeaza_articol`, ruta normală); **adevărat pentru contract-cu-rate** (`contabilizeaza_rata`) și
- pentru ROAAUTO/ROAACNPRO (proceduri proprii, deja documentate).
-- *„există o ramură de fallback în `contabilizeaza_articol` care ajunge la notă fără politică"* — **fals**,
- reconfirmat la 0a; funcția nu are asemenea ramură, blochează necondiționat.
-- *„FACT-024 se ridică doar când `id_pol` e nenul dar articolul nu e membru, `id_pol` nul merge pe alt
- drum"* — **fals ca „alt drum în aceeași funcție"**; **adevărat ca „alt drum = altă funcție"** (0c/0d).
-
----
-
-## D. Răspunsul la întrebarea lui Marius, în cinci rânduri (actualizat după reconciliere)
-
-**Depinde care „comandă".** Pe obiectul `COMENZI`/`COMENZI_ELEMENTE` al ROAFACTURARE (facturare „pe bază
-de comandă", tip 3), SCC-ul vine tot din `NOTE_CONTABILE.SCC` prin `id_pol` — **`id_pol` nu lipsește
-niciodată**, e coloană `NOT NULL` (confirmat pe schemă și pe date: 0 din 6868/66 linii fără el), populată la
-adăugarea articolului dintr-o listă deja restrânsă la o singură politică (`v_articole`/`com_vpreturi_utilizator`),
-politică aleasă o dată pe comandă. **Dacă experiența lui Marius vine din facturarea contractelor cu rate
-(scadențar, `OPT_FACTURARE IN (1,2)`) sau din ROAAUTO**, atunci da, există o rută reală, azi în producție,
-care scrie nota **fără nicio politică de preț**: pe contracte-cu-rate, nota vine direct din
-`CONTRACTE.ID_NOTA` (o coloană pe contract, aleasă o singură dată la configurarea lui, independentă de orice
-`id_pol` per linie) — `contabilizeaza_rata`, nu `contabilizeaza_articol`. Pe ROAAUTO/ROAACNPRO, nota o scrie
-o procedură proprie a produsului (`pack_acn.salveaza_regdoc` etc.), tot în afara lanțului `CRM_POLITICI_PRETURI`.
-**Aceste rute nu sunt „`id_pol` gol tratat cu grijă" — sunt căi care nu ating deloc `id_pol`/`contabilizeaza_articol`.**
-Pe contract-cu-**articole** (nu rate), tiparul rămâne cel din runda 1: `CTR_ARTICOLE.ID_POL_ART` → membru
-al unei politici reale, ca și pe comandă.
-
-## E. Se poate refolosi „același model" pentru articolul ad-hoc din #13?
-
-**Parțial. Mecanismul de jos (RPC + „apartenența e garantată prin construcția listei") e direct
-transplantabil — dar e deja exact ce propune rețeta în 4 pași din J-quater, nu o alternativă mai simplă
-la ea. Partea care ar simplifica cu adevărat lucrurile — „ia pur și simplu politica curentă și adaugă
-articolul în ea" — e decizia 24, deja retrasă de Marius, din motive care rămân valabile.**
-
-Detaliat:
-
-1. **Ce arată comandă/contract, tehnic**: operatorul nu alege niciodată `id_pol` pentru un articol anume —
- alege **o politică** (una dintre cele la care are drept, via `UTILIZATORI_ROL_INTERN` →
- `POLITICI_GRUPURI` → `CRM_POLITICI_PRETURI`), iar din acel moment orice articol afișat spre alegere e
- deja membru al ei (`com_vpreturi_utilizator`/`cPol_pret_art` filtrează `id_pol_art`/`id_pol IS NOT NULL`
- la sursă). Verificarea FACT-024 „trece" pe comandă/contract **nu pentru că ar exista un fallback** — ci
- pentru că nu există cale, în UI, de a ajunge la un articol care nu e deja membru. E o garanție de
- construcție a listei, nu o validare separată.
-2. **Acest tipar exact e deja documentat, ca fezabil, în `coresp_cont_venchelt.md` secțiunea „e)" / J-quater
- punctul 3** — RPC `pack_preturi.adauga_politica_pret_art` (deja folosit în producție,
- `ofacturare.vc2:15551-15587`) pentru „asigură apartenența", plus trimiterea lui `id_pol` neschimbat la
- `adauga_articol_factura`. Nu e nimic nou de inventat aici — comanda/contractul confirmă că tiparul
- „RPC + listă pre-filtrată" funcționează în producție de multă vreme, dar **planul A din J-quater deja îl
- folosește**. Refolosirea nu elimină pasul, îl confirmă.
-3. **Ce NU rezolvă modelul comandă/contract e alegerea SCC-ului corect per articol** — pe comandă/contract
- politica e **una singură, fixă**, aleasă pentru tot documentul/sesiunea, cu un singur `SCC` (orice ar
- fi el) pentru toate articolele adăugate așa. Aplicat identic pe `caut_articol` (restricționează
- rezultatele căutării din nomenclator la politica curentă a operatorului), rezultatul ar fi
- **exact ceea ce există deja azi ca „Cauta in lista de preturi…"** — nu rezolvă cazul pe care S4g/#13 îl
- cere explicit: un articol care **nu e membru al niciunei politici** (`plan_13...md:1711-1716`: „din
- nomenclator se oferă și articole gestionabile, și negestionabile"; „un articol fără `ID_POL` nu ajunge
- la cont gol, ci la eroare").
-4. **„Alege o politică fixă și pune articolul în ea" e literalmente decizia 24, deja retrasă**
- (`plan_13...md:926-930`): *„Decizia 24: articolul ales din nomenclator primește `id_pol`-ul unei
- politici de pret implicite. RETRASĂ în runda 8... prețul lui era o întrebare de configurare cu
- contabilul (care politică, cu ce `SCC`, una sau mai multe) și un cont de venit uniform pentru orice
- articol adăugat așa. Marius a ales în loc derivarea contului. Nu se reintroduce."* Motivul retragerii
- nu s-a schimbat: o politică unică (fie ea „a operatorului", ca pe comandă) dă un **singur** cont de
- venit oricărui articol, indiferent de natura lui (marfă/producție/serviciu) — exact opusul deciziei 27,
- care cere `SCC` diferențiat după clasa contului de gestiune al articolului (`707`/`711`/`702`/`703`/
- `7015`/`7018`/`704`).
-5. **Deci ce rămâne de făcut e exact pasul central din rețeta în 4 pași**: nu „cum trimit un `id_pol`
- valid la Oracle fără să ating `pack_facturare`" (asta e deja rezolvat, și demonstrat funcțional de
- comandă/contract) — ci „**care** politică, cu **care** `SCC`, pentru **acest** articol anume" — acolo
- comanda/contractul nu ajută, pentru că ele nu rezolvă niciodată această întrebare: politica le vine
- gata aleasă, de operator, o singură dată, nu calculată per articol.
-
-**Verdict la „mă gândeam la același model" (dacă modelul e comandă/contract-cu-articole)**: da, la nivel de
-mecanism (RPC de inserare + membership garantat prin listă filtrată) — dar acel nivel era deja acoperit de
-planul A/decizia 27-bis. Nu, la nivelul la care ar simplifica ceva („nu mai calculăm SCC per articol, luăm
-politica gata aleasă") — pentru că acela e exact decizia 24, respinsă cu un motiv care rămâne valabil.
-
-### E-bis. Dar există un al treilea model, mai simplu — cel din `contabilizeaza_rata` (secțiunea 0c)
-
-Reconcilierea de la secțiunea 0 arată un tipar pe care raportul din runda 1 nu-l luase în calcul: **un
-document poate duce el însuși o notă contabilă fixă, complet în afara `CRM_POLITICI_PRETURI`, iar
-`pack_facturare` are deja o funcție care face exact asta** (`contabilizeaza_rata`, sursa `CONTRACTE.ID_NOTA`).
-Aplicat la #13, ideea ar fi: nu mai deriva `SCC` per articol și nu mai caut/construi o politică tehnică — scrie
-nota direct, cu conturile calculate în VFP (regula deciziei 27: `CORESP_CONT_VENCHELT`/`NOM_ARTICOLE.CONT`/
-`704`), printr-o cale de scriere **paralelă**, ca și pentru rate.
-
-**De ce nu se poate fără să ating `pack_facturare`, și asta contează, dat fiind decizia 27-bis**:
-- `contabilizeaza_rata` există deja, dar e legată strict de `VANZARI_DETALII_TEMP` cu semantică de „rată de
- contract" (`detalii_rata.id_ctr` obligatoriu în interogare) — nu e apelabilă pentru un rând de articol
- obișnuit (`id_articol` populat, `id_pol` gol) fără o funcție **nouă**, analogă, în `pack_facturare`.
-- Sursa notei la rată e `CONTRACTE.ID_NOTA` — o coloană pe un document care **există deja** și **se
- configurează o dată** (la crearea contractului). Pentru articolul ad-hoc de pe formularul unificat nu
- există azi un asemenea „document-sursă cu notă fixă" — ar trebui inventat (ex. o coloană similară pe
- antetul facturii, sau parametru nou la `adauga_articol_factura`) — tot cod nou în `PACK_FACTURARE`.
-- **Constrângerea „pack_facturare rămâne neatins" (decizia 27-bis) exclude explicit acest drum.** Dacă
- Marius e dispus s-o relaxeze, tiparul `contabilizeaza_rata` e un precedent real, mai simplu decât rețeta
- în 4 pași — pentru că elimină complet nevoia unei „politici tehnice" și a RPC-ului de apartenență
- (`pack_preturi.adauga_politica_pret_art`): SCC-ul ar merge direct în `scrie_nota`, fără ocolul prin
- `CRM_POLITICI_PRET_ART`. Dacă nu, rămâne exact ce spunea verdictul din runda 1: rețeta în 4 pași (planul
- A, tot în VFP) rămâne singura variantă compatibilă cu constrângerea.
-
-**Verdict final, actualizat**: modelul comandă/contract (runda 1) nu ajută, motivele rămân cele deja arătate.
-Dar există un al doilea model real, comandă**-rate**/contract-rate, care **ar** ajuta — cu prețul de a
-renunța la „`pack_facturare` neatins". E o decizie de produs pentru Marius, nu o concluzie tehnică unică —
-raportul pune ambele opțiuni pe masă, cu costul lor exact.
-
-**Corecție importantă, din verificarea independentă de mai jos („Completare de la sesiunea principală"):**
-politica `7 DISCOUNT` (870 linii de comandă, `SCD=667`/`SCC=4111`, notă `2 DISCOUNT`) e deja, în producție,
-o **politică tehnică folosită doar ca rutare contabilă**, nu ca listă comercială — exact tiparul „o politică
-per scop contabil" pe care planul A/decizia 27-bis îl propune (nu decizia 24, care era o politică unică
-pentru *orice* articol ad-hoc, indiferent de natură). Deci precedentul operațional pentru „politică tehnică,
-una per destinație contabilă" **există deja pe ruta comandă** — mai puternic decât `gnId_pol_pret_stoc`
-(care e un singur cont pentru tot stocul). **Dar** aceeași verificare arată că garanția „apartenență prin
-construcția listei" (punctul 1 de mai sus) **nu e etanșă pe date**: 37 din 6868 linii active de comandă au
-un articol care nu (mai) e membru al politicii înregistrate pe linie — verificare, cauză și comportament la
-facturare, deschise, vezi secțiunea finală.
-
----
-
-## A. Ruta COMANDĂ
-
-### A.1 — `cursor_comanda` selectează `ID_POL`? Da, direct de pe linia comenzii
-
-```sql
--- D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:2996-3054 (ramura factură)
-OPEN V_CURSOR FOR
- SELECT ROWNUM as id_c,
- A.ID_ARTICOL,
- NULL AS LOT,
- NULL as SERIE,
- A.ID_POL, -- <- direct din COMENZI_ELEMENTE, nu derivat
- A.ID_VALUTA, ...
- FROM COMENZI_ELEMENTE A
- LEFT JOIN CRM_POLITICI_PRET_ART B
- ON A.ID_POL = B.ID_POL AND A.ID_ARTICOL = B.ID_ARTICOL
- ...
- WHERE A.STERS = 0 AND A.ID_COMANDA = V_ID_COMANDA ...
-```
-(identic la `:3084-3140` pentru ramura aviz, `V_TIP > 20`). `A.ID_POL` e coloană directă pe
-`COMENZI_ELEMENTE` — `LEFT JOIN CRM_POLITICI_PRET_ART B` de mai jos **nu** derivă `id_pol`, doar aduce
-`DISCOUNT_UNITAR`/`PROC_TVAV` pentru acea combinație `(id_pol, id_articol)`.
-
-### A.2 — Unde e stocat: `COMENZI_ELEMENTE.ID_POL`, coloană `NOT NULL`
-
-Confirmat pe schema vie (`MARIUSM_AUTO`, `ROA_CENTRAL`, 10.08.2026):
-```sql
-select column_name, data_type, nullable from user_tab_columns where table_name='COMENZI_ELEMENTE';
--- ID_POL NUMBER N <- NOT NULL
-select count(*), sum(case when id_pol is null then 1 else 0 end) from comenzi_elemente where sters=0;
--- 6868 0
-```
-**`ID_POL` e obligatoriu la nivel de constrângere de tabel**, nu doar „de obicei populat" — și cele 6868
-linii active din baza vie confirmă 0 excepții. E o coloană de **linie**, nu de antet (nu există `ID_POL`
-pe `COMENZI`).
-
-### A.3 — Cine îl pune acolo la crearea comenzii
-
-Nu e o alegere liberă per articol — e moștenit dintr-o **politică aleasă o singură dată pe comandă**:
-
-```
-COMUN\clase\ocomenzi.vc2:1849-1870 (do_modifica, la deschiderea/crearea comenzii)
-Do Case
- Case Inlist(loRec.interna,2,5)
- If lnTip = 0 And Reccount('crscomanda_curenta')>0
- lnIdPol = id_pol && preia politica de pe comanda existenta
- Else
- loCauta = caut_politici_curente_utilizator() && cautare manuala, comanda noua
- If !Empty(Nvl(loCauta.id_pol,0))
- lnIdPol = loCauta.id_pol
- Else
- Return
- Endif
- Endif
- update_articole_politica(lnIdPol)
- Case loRec.interna = 3
- update_articole_politica_comenzi([IDPOLITICAPRET]) && optiune implicita globala
- Otherwise
- update_articole_politica_comenzi([ID_LISTA_PRETURI_PV]) && optiune implicita globala
-Endcase
-```
-Deci: pentru un tip de comandă (`interna` 2/5) operatorul **caută explicit** o politică
-(`caut_politici_curente_utilizator`); pentru celelalte tipuri, politica vine dintr-o **opțiune globală**
-(`gnIdPoliticaPret`/`gnId_lista_preturi_PV`, citite în `extrage_optiuni_firma`,
-`update_comenzi.prg:16-29`). Nu se moștenește de la client.
-
-Politica aleasă filtrează lista de articole disponibile de adăugat:
-```
-COMUN\programe\update_comenzi.prg:31-60 (update_articole_politica)
-select p.id_articol,p.id_pol,p.pret,... from com_vpreturi_utilizator p ...
-where p.id_util = <> and p.id_pol = <>
-```
-```sql
--- D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\01\ff_2026_01_21_01_FACTURARE.sql:3-30
-create or replace view com_vpreturi_utilizator as
-select a.id_util, b.id_politica as id_pol, ..., d.id_articol, d.pret, ...
- from 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 c.id_pol = d.id_pol
- left join nom_articole e on d.id_articol = e.id_articol
- where a.sters = 0 and b.sters = 0 and ... and d.id_pol is not null and ...
-```
-`v_articole` (grid-ul de adăugare articole pe comandă, `ocomenzi.vc2:4005-4014`,
-`RecordSource = "v_articole"`) e populat strict din acest view, **filtrat `d.id_pol IS NOT NULL`** — deci
-orice articol afișat spre alegere e deja membru garantat. La alegere (`do_adauga`,
-`ocomenzi.vc2:4645-4702`) și la salvare (`do_scrie_articole`, `:4864-4899`):
-```
-ocomenzi.vc2:4885-4893
-Scatter Name poArticol
-...
-lcSql = [begin pack_comenzi.adauga_articol_comanda(] + Alltrim(Str(This.nId)) + [,] + ;
- Alltrim(Str(poArticol.id_articol)) + [,] + Alltrim(Str(poArticol.id_pol)) + [,] + ...
-```
-`poArticol.id_pol` (scatter din `v_articole`) merge neschimbat în `COMENZI_ELEMENTE.ID_POL`. Nu există în
-`ocomenzi.vc2` niciun al doilea punct de adăugare a articolelor pe comandă (nicio cale către `caut_articol`
-de nomenclator liber) — `v_articole` e singura sursă.
-
-### A.4 — Ce se întâmplă când linia de comandă are `ID_POL` gol la facturare
-
-**Nu se poate întâmpla, prin construcție dublă**: (a) `COMENZI_ELEMENTE.ID_POL` e `NOT NULL` la nivel de
-Oracle — un `INSERT` cu `id_pol` gol ar da `ORA-01400`, nu ajunge niciodată să fie facturat; (b) singurul
-punct de inserare din VFP (`pack_comenzi.adauga_articol_comanda`, apelat cu `poArticol.id_pol` din
-`v_articole`) nu poate produce `id_pol` gol, pentru că sursa (`com_vpreturi_utilizator`) filtrează deja
-`id_pol IS NOT NULL`. Verificat pe date reale: 0 din 6868 linii active. Spre deosebire de nomenclator
-(`caut_articol`, unde coloana `id_pol` **nu există deloc** în SELECT), pe comandă întrebarea „ce se
-întâmplă la gol" nu are un răspuns de cod (fallback/eroare) pentru că premisa nu apare niciodată.
-
----
-
-## B. Ruta CONTRACT
-
-Produsul e separat, **`D:\ROA\ROACONTRACTE`** (există în arbore, alături de `ROAFACTURARE`).
-
-### B.1 — Cursorul de facturare selectează `ID_POL`? Da, dar prin `ID_POL_ART`, nu direct
-
-```sql
--- D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:2718-2836 (cursor_contract, V_CURSOR2 = grd_contracte)
-SELECT ..., id_pol, ...
- FROM (SELECT A.ID_CTR, C.ID_ARTICOL, NULL as id_rata, C.ID_POL, ...
- FROM CONTRACTE A
- LEFT JOIN CTR_ARTICOLE B ON A.ID_CTR = B.ID_CTR
- LEFT JOIN CRM_POLITICI_PRET_ART C ON B.ID_POL_ART = C.ID_POL_ART -- <- cheia stocata e ID_POL_ART
- LEFT JOIN NOM_ARTICOLE E ON C.ID_ARTICOL = E.ID_ARTICOL ...
-```
-Grid-ul principal de adăugare articole pe contract (`crsarticole`, folosit pentru „adăugare liberă") **nu**
-vine din acest cursor — vine dintr-un apel separat, în interiorul aceleiași proceduri:
-```sql
--- ff_...:2940-2948
-pack_facturare.cursor_preturi(V_DATA_CURS, V_TIP, V_ID_VALUTA, V_ID_GESTIUNE_INIT,
- V_LUNA, V_AN, V_ID_UTIL, V_ID_SUCURSALA, V_CURSOR);
-```
-adică **exact aceeași sursă ca „lista de prețuri" (secțiunea C)** — confirmă din nou concluzia din runda
-anterioară (`retur_si_lista_preturi.md` B7): grid-ul „liber" de pe contract nu e liber de politică, e lista
-de prețuri normală a operatorului.
-
-### B.2 — Unde e stocat pe contract: `CTR_ARTICOLE.ID_POL_ART` (linie, nullable)
-
-```sql
-select column_name, nullable from user_tab_columns where table_name='CTR_ARTICOLE';
--- ID_POL_ART Y <- nullable, spre deosebire de COMENZI_ELEMENTE.ID_POL
-select count(*), sum(case when id_pol_art is null then 1 else 0 end) from ctr_articole;
--- 27 6
-```
-Spre deosebire de comandă, contractul stochează **`ID_POL_ART`** — FK direct la rândul din
-`CRM_POLITICI_PRET_ART` (articol+politică), nu la politică ca atare — și coloana **e nullable**, fără
-constrângere de tabel. Pe datele reale (bază de dezvoltare, eșantion mic — 27 rânduri în total, deci
-**nu extrapolez procentul la producție**), 6 din 27 rânduri nu au `id_pol_art`. Dacă un asemenea rând ar
-ajunge selectat spre facturare prin `V_CURSOR2`/`grd_contracte` (nu prin `crsarticole`, care e mereu lista
-de prețuri), `LEFT JOIN ... ON B.ID_POL_ART = C.ID_POL_ART` nu găsește nimic, `id_pol` iese `NULL` în
-cursor — același drum spre FACT-024 ca la nomenclator. **Neverificat**: dacă UI-ul (`grd_contracte`) permite
-efectiv selecția unei asemenea linii spre facturare sau o filtrează/dezactivează — nu am urmărit acel cod
-de grid, în afara bugetului acestei runde.
-
-### B.3 — Cine îl pune acolo la crearea contractului
-
-`D:\ROA\ROACONTRACTE\Clase\ferestre_contracte.vc2`, `PROCEDURE do_adauga_obiectul` (`:9454+`):
-```
-:9464-9470
-Case gnParametru_prog = 1 && clienti
- lcSel = [{call pack_crm.get_politici_grup(] + Alltrim(Str(gnIdUtil)) + [,] + ;
- Alltrim(Str(goContract.id_valuta)) + [,?gnIdSucursala)}]
- ... INTO Cursor crsPoliticiGrup1 ...
-```
-```
-:9486-9500
-fpp = Createobject("frm_politica_preturi") && operatorul alege O politica dintre cele la care are drept
-fpp.Show(1)
-...
-Select *, PRETFTVA As pret_unitar, 1 As cant, ... FROM cPol_pret_art With (Buffering = .T.) ;
- WHERE ales = 1 INTO Cursor cAles && articolele bifate, deja membre ale politicii alese
-```
-`pack_crm.get_politici_grup` e echivalentul ROACONTRACTE al lanțului
-`UTILIZATORI_ROL_INTERN → POLITICI_GRUPURI → CRM_POLITICI_PRETURI` folosit și de comandă/factură normală —
-operatorul primește lista politicilor lui, alege una, `cPol_pret_art` (bind pe `CRM_POLITICI_PRET_ART`
-pentru politica aleasă) afișează articolele ei, iar rândurile bifate (`ales=1`) devin linii `CTR_ARTICOLE`
-cu `id_pol_art` = `ID_POL_ART`-ul din acel rând. Din nou: **nu se alege un articol liber, se alege dintr-o
-listă deja restrânsă la politică.**
-
-### B.4 — Ce se întâmplă cu `ID_POL_ART` gol la facturare
-
-Vezi B.2 — spre deosebire de comandă, **nu e imposibil prin constrângere de schemă** (coloana e nullable),
-și există cazuri reale (6/27) în baza de dezvoltare. Comportamentul la facturare (dacă acea linie ajunge
-selectată) urmează același `NULL → FACT-024` ca la nomenclator — **neconfirmat direct pe o factură reală**,
-dedus din structura JOIN a cursorului (B.1).
-
----
-
-## C. Ruta LISTĂ DE PREȚURI (tip 1/5/7/10/22/29/45), ca termen de comparație
-
-**Corectare față de premisa din brief**: `id_pol` pe această rută **nu vine din alegerea operatorului pe
-document** pentru majoritatea tipurilor — vine automat din rolul operatorului logat, exact ca pe comandă,
-dar fără nicio interacțiune UI.
-
-`ofacturare.prg:279-282` (apelul cursorului pentru tip 1,5,7,10,22,23,29):
-```
-lcSqlCursor = [{call pack_facturare.cursor_preturi(?poDate.zi_curs,?poDate.tip,?poDate.id_valuta,] + ;
- [?poDate.id_gestiune_init,?gnLuna,?gnAn,?gnIdUtil,?gnIdSucursala)}]
-```
-`poDate.id_pol` **nu e printre parametri**. `cursor_preturi` (`ff_...:2138-2354`) derivă `A.ID_POL` intern:
-```sql
--- ff_...:2222-2251 (V_TIP IN (1,2)) / 2330-2354 identic ca structura, tot fara parametru id_pol
-FROM (select a1.id_util, a3.id_pol, ...
- from utilizatori_rol_intern a1
- left join politici_grupuri a2 on a1.id_grup = a2.id_grup
- left join crm_politici_preturi a3 on a2.id_politica = a3.id_pol
- ...
- where a1.id_util = V_ID_UTIL
- and NVL(a1.ID_SUCURSALA,-99) = NVL(V_ID_SUCURSALA,-99)
- and ) A
-LEFT JOIN CRM_POLITICI_PRET_ART B ON A.ID_POL = B.ID_POL
-```
-Adică `id_pol` per linie vine din rolul de utilizator (`UTILIZATORI_ROL_INTERN.ID_UTIL = V_ID_UTIL`) și
-sucursală — **niciodată dintr-o alegere pe documentul curent**, pentru tip 1/2/5/7/10/22/29/45.
-
-Câmpul de căutare vizibil pe antet există, dar e **inert pentru aceste tipuri**:
-```
-COMUN\clase\ofacturare.vc2:6822-6825
-ADD OBJECT 'Ct_clb_politici_preturi' AS ct_clb_cautare WITH ;
- cconditie = ISNULL(poDate.id_pol) or EMPTY(poDate.id_pol), ;
- cprocedura = thisform.do_cauta_politica, ...
-```
-`poDate.id_pol` e citit efectiv (trimis la Oracle) **doar** pentru `cursor_gestiune`, tip 41/23
-(`ofacturare.prg:297,777`); e validat ca obligatoriu **doar** pentru aceleași două tipuri
-(`ofacturare.vc2:7334-7337`: *„Nu ati ales politica de preturi!"*). Pe factura normală din listă de
-prețuri, câmpul poate rămâne gol fără nicio consecință — nu alimentează nimic.
-
-**Concluzie C**: „lista de preț pe document" nu există ca mecanism activ pentru rutele principale — e „lista
-de preț a operatorului logat", determinată automat de rolul lui în `UTILIZATORI_ROL_INTERN`. Fiecare linie
-din `crsarticole` vine deja cu propriul `A.ID_POL` din acest join; dacă operatorul are mai multe grupuri de
-politici active simultan, teoretic același articol ar putea apărea de mai multe ori cu `id_pol` diferit —
-**neverificat pe date reale**, în afara bugetului acestei runde.
-
----
-
-## Ce nu s-a putut stabili și de ce
-
-- **B.4, comportamentul exact la facturare a unei linii de contract cu `ID_POL_ART` gol** — dedus din
- structura JOIN a `cursor_contract`, nu confirmat pe o factură reală emisă din contract cu o asemenea
- linie (ar necesita un contract de test cu o linie fără politică, apoi o încercare de facturare — în
- afara bugetului read-only al acestei runde).
-- **Dacă `grd_contracte` (UI) permite selecția/afișarea unei linii cu `id_pol_art` gol** — nu am urmărit
- codul de grid din `ROACONTRACTE`/`ofacturare.vc2` pentru acest caz specific.
-- **Dacă un operator cu mai multe grupuri de politici active poate primi articole duplicate cu `id_pol`
- diferit în `crsarticole`** (secțiunea C) — plauzibil din structura JOIN-ului (fără `DISTINCT` pe
- `a1.id_util`), neverificat pe date reale.
-- **Eșantionul `CTR_ARTICOLE` e mic (27 rânduri) în baza de dezvoltare** — raportul 6/27 fără
- `id_pol_art` e o dovadă reală, dar nu extrapolabilă direct la volumul de producție; merită o verificare
- separată pe o bază cu volum de producție dacă decizia depinde de frecvența cazului.
-- **Cele 37 de linii de comandă active cu articol ne-membru al politicii de pe linie** (semnalate în
- „Completare de la sesiunea principală") — cauza (import? editare ulterioară a politicii? ștergere din
- `CRM_POLITICI_PRET_ART` după ce comanda a fost creată?) nu e stabilită, și nici comportamentul real la
- facturare (`FACT-024`/`ORA-01403` așteptat pe cod, neconfirmat pe o încercare reală). E cea mai
- importantă verificare rămasă înainte de S4g — dacă garanția „membership prin construcția listei" se sparge
- și pe alte linii similare, tot raționamentul din secțiunea E (paragraful 1) trebuie recalibrat.
-- **`VANZARI.TIP = 51`** — 121 de linii fără `id_pol`, cu 179/275 rânduri `ACT` cu `SCC` populat cumulat pe
- documentele aferente — nu am identificat ce tip de document e (nu apare în `Do Case` din
- `ofacturare.prg:266-308`); posibil vânzare retail/POS sau un tip specific altui produs ROA. Neexplorat.
-- **Restul tipurilor negative (`-1`…`-13`, în afară de `-12`=ROAAUTO)** — nu au fost identificate individual;
- presupun variante storno/aviz ale rutelor deja documentate, dar nu s-a verificat pe cod care produs le
- generează.
-- **Dacă experiența lui Marius vine efectiv din contract-cu-rate, din ROAAUTO, sau din altă rută
- neidentificată (`51`, negative)** — nu s-a putut stabili fără să-l întrebăm direct; secțiunea 0d
- enumeră ipotezele plauzibile, cu dovezi pentru fiecare, dar nu poate alege între ele.
-
----
-
-## Completare de la sesiunea principala (confirmare pe schema, 10.08.2026)
-
-Verdictul de mai sus a fost verificat independent, pentru ca **contrazice o afirmatie a lui Marius**
-(„fac facturi pe baza de comanda care nu au politica de pret"). Confirmat:
-
-- `COMENZI_ELEMENTE.ID_POL` — `nullable = N`, constrangerea `SYS_C0015376` (`"ID_POL" IS NOT NULL`) plus
- `FK_COMENZI_ELEMENTE_002`. In date: **7108 randuri total, 0 cu `ID_POL` nul, 0 cu `ID_POL` = 0**, 9
- politici distincte in uz. Pe liniile active (`STERS = 0`): 6868, tot 0 nule.
-- `CTR_ARTICOLE.ID_POL_ART` — `nullable = Y`. Confirmata asimetria semnalata in raport.
-- Toate cele 9 politici folosite pe linii de comanda au `ID_NOTA` si ajung la un `SCC`.
-
-**Doua observatii noi, care nu erau in raport:**
-
-1. **Politica `7 DISCOUNT` e o politica tehnica de rutare contabila, folosita in producție.** Apare pe
- **870 de linii de comanda** si trimite la nota `2 DISCOUNT` (`SCD = 667`, `SCC = 4111`). Nu e o lista
- comerciala de preturi — e o politica existenta doar ca sa duca linia la o nota contabila anume. **E
- precedentul de care are nevoie decizia 27**, si e mai apropiat de ce cere #13 decat
- `gnId_pol_pret_stoc` (care e o singura politica pentru tot stocul). Tiparul „politica tehnica per scop
- contabil" nu trebuie inventat: exista.
-2. **Garantia „apartenenta prin construcția listei" nu e etanșă in date.** Din 6868 de linii active de
- comanda, **37 au un articol care nu e membru al politicii de pe linie**
- (`NOT EXISTS (SELECT 1 FROM crm_politici_pret_art WHERE id_pol = e.id_pol AND id_articol = e.id_articol)`).
- Adica 37 de linii care, la facturare, ar trebui sa cada cu `FACT-024`. Cauza nu e stabilita — import,
- sau editarea / stergerea articolului din politica dupa introducerea comenzii. **Punctul 1 al secțiunii E
- („nu exista cale, in UI, de a ajunge la un articol care nu e deja membru") e corect despre UI, dar nu
- despre starea datelor.** De verificat inainte de S4g: daca acele 37 de linii se factureaza fara eroare,
- exista o cale nedescoperita si intrebarea deciziei 32 se redeschide.
-
-Interogarile: schema `MARIUSM_AUTO` pe `ROA_CENTRAL`, doar `SELECT`.
diff --git a/docs/cercetare/inventar_controale_formulare.md b/docs/cercetare/inventar_controale_formulare.md
deleted file mode 100644
index 61d0c0f..0000000
--- a/docs/cercetare/inventar_controale_formulare.md
+++ /dev/null
@@ -1,179 +0,0 @@
-# Inventar controale — formulare facturare (ROAFACTURARE, `COMUN\clase`)
-
-Investigatie read-only (fara editari, fara `git_sync.ps1`/`txt2vcx.ps1`, fara commit). Toate liniile
-sunt din fisierele text `.vc2` (FoxBin2Prg), verificate pe fisierul real (nu `.bak`). Scop: pregatirea
-unui mockup pentru un formular de facturare unificat — inventarul reflecta controalele existente, nu
-o propunere noua.
-
-## 1. Butoane `frm_facturare_articole` (`ofacturare.vc2:10968-15739`)
-
-Grid sursa (comanda/lista preturi) = `grd_articole` (`Left=9,Top=336,Width=326,Height=130`,
-`RecordSource=crsarticole`, `ofacturare.vc2:11570`). Grid destinatie (linii factura) = `grd_factura`
-(`Left=379,Height=337`, `RecordSource=crsfactura`, `ofacturare.vc2:12263`).
-
-| Control | Clasa de baza | Caption/Picture | L/T/W/H | ToolTipText | Pozitie fata de grid | `fisier:linie` |
-|---|---|---|---|---|---|---|
-| But_modifica1 | but_modifica | (fara caption, `modific_sus.bmp`) | 773/61/30/27 | "Modificare (CTRL+M)" | dreapta-sus `grd_factura` (Anchor=9) | `ofacturare.vc2:11192` |
-| But_sterge1 | but_sterge | `sterg_sus.bmp` | 811/61/30/27 | "Stergere (CTRL+D)" | dreapta-sus `grd_factura`, langa But_modifica1 | `ofacturare.vc2:11229` |
-| But_renunt1 | but_renunt | `renunt_sus.bmp` | 792/1/30/27 | "Renuntare (ESC)" | coltul din dreapta-sus al formularului | `ofacturare.vc2:11202` |
-| But_reset1 | but_reset | `reset_sus.bmp` | 303/295/30/27 | "Reseteaza" | deasupra `grd_articole` (Top grid=336) | `ofacturare.vc2:11213` |
-| But_urmator1 | but_urmator, `caction=do_urmator` | `urmator1.bmp` | 343/348/30/27 | "Verificare" | lateral-dreapta `grd_articole` (Left grid+Width+8=343) | `ofacturare.vc2:11237` |
-| But_urmator2 | but_urmator, `caction=do_urmator2` | `urmator1.bmp` | 343/143/30/27 | "Verificare" | deasupra `grd_articole`, langa `grd_contracte` | `ofacturare.vc2:11247` |
-| **But_urmator_tot1** ("adauga tot din comanda") | but_urmator_tot, `caction=do_adauga_tot` | `urmator1_tot.bmp`, **fara ToolTipText** | 343/378/30/27, `Visible=.F.` implicit | — | lateral-dreapta `grd_articole`, sub But_urmator1 | `ofacturare.vc2:11257` |
-| But_retur | but_retur | `retur1.bmp` | 343/407/30/27, `Visible=.F.` implicit | "Retur" | lateral-dreapta `grd_articole`, sub But_urmator_tot1 | `ofacturare.vc2:11221` |
-
-**"Adauga tot din comanda" — But_urmator_tot1.Click -> `do_adauga_tot`**
-(`ofacturare.vc2:13169-13198`): parcurge `crsarticole` (SCAN) si apeleaza
-`Thisform.do_adauga_articol(.T.)` pentru fiecare linie; daca articolul e gestionabil si cantitatea
-ramasa >0, cere confirmare "Nu ati selectat toata cantitatea... treceti la urmatorul?"
-(`aMessageBox` cu butoane Da/Nu/Renunta, cod 7).
-
-Vizibilitate pe tip document (`Init`, `ofacturare.vc2:14976-15344`, `Do Case poDate.tip`):
-
-| Control | Vizibil cand | Dovada |
-|---|---|---|
-| But_urmator_tot1 | `poDate.eProforma=1`, `poDate.lCopiere`, `tip=3` (comanda), `tip=4` (din avize), `tip in(21,28,42,47)` (aviz din comanda), `tip=25`, `tip in(8,9)` (retur factura), `tip=24` (retur aviz) | `ofacturare.vc2:15113,15120,15150,15166,15177,15215,15240,15245` |
-| But_retur | `tip in(1,5,7,10)` (facturare din lista de preturi) | `ofacturare.vc2:15127` — comentariu explicit: "pot sa fac retur de articole intr-o factura de vanzare" |
-| But_urmator2 / `grd_contracte` | eliminate (`RemoveObject`) daca nu exista `crsarticole1` (fara contracte pe formular) | `ofacturare.vc2:15294-15324` |
-
-**Conventia de clase de butoane** (suita ROA): clasa de baza `buton` (`_cmd_base.vc2:16`,
-`AS _cmdbase OF "_cmd_base.vcx"`) — 30x27px implicit, `Caption=""` (buton doar cu imagine),
-`BackColor=alb`, `SpecialEffect=1`. `Click` (`_cmd_base.vc2:41-70`) executa dinamic
-`This.Parent.()` (macro pe `cAction`/`clistaparametri`) — de-asta majoritatea instantelor nu
-au `Caption`/`Click` propriu, doar `caction=`. Subclasele concrete (`but_nou`,
-`but_sterge`, `but_modifica`, `but_urmator_tot`, etc.) sunt in `cmd_butoane.vc2:7-441`, fiecare
-hardcodand `caption`/`cpictureup`/`cpicturedown`/`Picture` (`..\grafice\*.bmp`, stare sus/jos) si
-`ToolTipText` cu shortcut intre paranteze (ex. "Modificare (CTRL+M)"). `but_nou` (`do_adauga`,
-`nou_sus.bmp`, "Adaugare (CTRL+N)") — `cmd_butoane.vc2:214`.
-
-## 2. Butoane `frm_facturare_articole2` (prototip, `ofacturare.vc2:15741-19355`)
-
-Diferenta arhitecturala fata de #1: **un singur grid** `grd_factura` (`Left=12,Top=204,Height=240`,
-`ofacturare.vc2:16601`) cu editare inline prin comboboxuri in celule (`cCodMat.cboCodmat`,
-`cDenumire.cCboDenumire`, `cGestiune.cCboGestiune`) — nu exista casete separate de cautare articol
-(`ct_codmat`/`ct_articole`) si nici `crsarticole`/comanda sursa.
-
-| Control | Clasa de baza | Caption/Picture | L/T/W/H | ToolTipText | Pozitie fata de grid | `fisier:linie` |
-|---|---|---|---|---|---|---|
-| **But_nou1** | but_nou (mostenit, `caption=do_adauga` suprascris in clasa) | `nou_sus.bmp` | 719/175/30/27 | "Adaugare (CTRL+N)" | deasupra-dreapta `grd_factura` (Top grid=204) | `ofacturare.vc2:15936` |
-| But_sterge1 | but_sterge | `sterg_sus.bmp` | 747/175/30/27 | "Stergere (CTRL+D)" | deasupra-dreapta `grd_factura`, langa But_nou1 | `ofacturare.vc2:15955` |
-| But_renunt1 | but_renunt | `renunt_sus.bmp` | 716/1/30/27 | "Renuntare (ESC)" | coltul din dreapta-sus | `ofacturare.vc2:15944` |
-
-**But_nou1.Click -> `do_adauga`** (`ofacturare.vc2:17118-17122`, override propriu, nu
-`but_nou`.caction implicit): `SELECT crsFactura / APPEND BLANK / this.grd_factura.SetFocus()` —
-adauga direct un rand gol in grid si da focus, spre deosebire de `do_adauga_articol` complex din #1.
-
-Nu exista `But_modifica` in aceasta clasa — editarea se face inline in celulele gridului, nu prin
-dialog separat.
-
-**Bonus relevant pentru mockup**: acest prototip **incorporeaza deja aceleasi controale de antet**
-(`Ct_clb_venchelt`, `Ct_clb_sectie`, `Ct_clb_responsabil`, `Ct_clb_lucrare`, `Ct_clb_altele`,
-`Ct_clb_valuta`, `clb_fdoc`, `Clb_serie_act1`, `Clb_nract`, `Clb_dataact`, `Clb_data_scadenta`,
-`Clb_zi_curs`) direct pe formularul de articole, la `ofacturare.vc2:15741+182..749` — e cea mai
-apropiata schita existenta de un "formular unificat".
-
-## 3. Antet `frm_date_factura` (`ofacturare.vc2:8482-9869`) si `frm_date_aviz` (`ofacturare.vc2:6566-7618`)
-
-| Control cerut | `frm_date_factura` — caption real | `frm_date_aviz` — caption real | Tip/container | Obligatoriu / vizibil conditionat |
-|---|---|---|---|---|
-| tip venit/cheltuiala | `Ct_clb_venchelt` = "Venit / cheltuiala" | `Ct_clb_venchelt` = "Venit / cheltuiala" | `ct_clb_cautare` (container cautare) | eliminat pe aviz pentru `tip=23,41,25` (transfer/retur) — `ofacturare.vc2:7438-7461` |
-| sectie | `Ct_clb_sectie` = "Sectie" | `Ct_clb_sectie` = "Sectie" | `ct_clb_cautare` | intotdeauna prezent in ambele (nu s-a gasit `RemoveObject`) |
-| responsabil | `Ct_clb_responsabil` = "Responsabil" | `Ct_clb_responsabil` = "Responsabil" | `ct_clb_cautare` | eliminat cand `gnScadereStoc=0` sau `tip in(4,7,8,9,48,49)` — factura: `9646-9707`; aviz: eliminat pe majoritatea tipurilor cu comanda/lista |
-| lucrare | `Ct_clb_lucrare` = "Lucrare" | `Ct_clb_lucrare` = "Lucrare" | `ct_clb_cautare` | nu s-a gasit eliminare conditionata |
-| altele | `Ct_clb_altele` — label dinamic ("Altele" implicit) | idem | `ct_clb_cautare`, `.do_schimba_explicatia(...)` | eticheta se schimba pe tip: "Nr. contract"/"Nr. comanda"/"Nr. factura"/"Nr. facturi"/"Locatie" (`9633-9643`); eliminat complet daca `gnScadereStoc=0 and tip in(1,5,10)` fara copiere |
-| valuta | `Ct_clb_valuta` = "Valuta" | **nu exista pe aviz** | `ct_clb_cautare` | eliminat daca `poDate.in_valuta=0` (`ofacturare.vc2:9725-9732`) |
-| fel document | `Ct_clb_fdoc` = combo `_combobox1` FACTURA/PROFORMA/BON FISCAL, label "Tip document" | `Ct_clb_fdoc` = camp cautare "Felul documentului" (`caut_ora.vcx`) | container diferit intre cele doua forme (combo la factura, cautare la aviz) | intotdeauna vizibil |
-| serie | `Clb_serie_act` label "Serie document" | `Clb_serie_act` (fara label explicit override) | `clb_serie_act` (`serii_numere.vcx`) | eliminat daca `poDate.rezultat_serii` nu e in `(1,2,3)` — nicio serie configurata |
-| numar | `Clb_nract` = "Numar document" | `Clb_nract` = "Nr. documentului" | `clb_tx_simplu`, `InputMask=get_mask(14,0)` | mereu prezent |
-| data act | `Clb_dataact` = "Data document" | `Clb_dataact` = "Data documentului" | `clb_tx_data` | mereu prezent |
-| data scadenta | `Clb_data_scadenta` = "Data scadenta" | **nu exista pe aviz** | `clb_tx_data` | **dezactivat** (nu eliminat) cand `gnScadentaAutomata=1` (`.dezactiveaza()`, `9713-9715`) |
-| zi curs | `Clb_zi_curs` = "Data curs valutar" | `Clb_zi_curs` = "Data cursului valutar" | `clb_tx_data` | eliminat pe factura daca `tip in(8,9)` retur (`9718-9722`) |
-| client | `Ct_clb_nume_client` = "Nume client" | `Ct_clb_nume_client` = "Nume client" | `ct_clb_cautare` | eticheta se schimba pe aviz ("Retur de la"/"Gestiune sursa") in functie de tip transfer |
-
-Control specific doar in `frm_date_factura`: `Ct_clb_gestiune_init`="Gestiune sursa" (`ToolTipText`:
-"Daca nu alegeti gestiunea, la scaderea din stoc a unui articol va vor fi aratate stocurile tuturor
-gestiunilor pe care aveti drepturi.") — eliminat impreuna cu `Ct_clb_responsabil` in majoritatea
-cazurilor `gnScadereStoc=0`; `txtCodFiscal`/`lblCodFiscal` (cod fiscal, `ReadOnly`, langa client) si
-`txtSoldLei`/`lblSoldLei` (sold curent client, populat din `GetSoldClient()` daca
-`poDate.id_client<>0`); `But_verifica1` (verificare ANAF). Control specific doar in
-`frm_date_aviz`: `Ct_clb_politici_preturi`="Politica de preturi" — eliminat pe majoritatea
-tipurilor cu comanda.
-
-Toate conditiile de vizibilitate sunt in `Init` (nu in `do_schimba_tipdoc`, care doar realoca
-seria/numarul): `frm_date_factura.Init` = `ofacturare.vc2:9563-9796`; `frm_date_aviz.Init` =
-`ofacturare.vc2:7354-7600` (citit doar pana la ~`7533`; ultimele ~65 linii nu au fost verificate,
-vezi "Necunoscute ramase").
-
-## 4. `frm_alte_date` (`ferestre_cere_date.vc2:2219-3353`)
-
-| Control | Caption | Grupare logica | `fisier:linie` |
-|---|---|---|---|
-| `Ct_clb_delegat` | "Delegat" | Delegat/transport | `2553` |
-| `Ct_clb_masina` | "Masina" | Delegat/transport | `2569` |
-| `Ct_clb_agent` | "Agent" | Delegat/transport | `2537` |
-| `Clb_dataora_exp` | "Data si ora expedierii" | Delegat/transport | `2443` |
-| `opt_incasat` (radiogrup 4 optiuni) | "Fara incasare" / "Chitanta" / "Bon fiscal" / "POS Card" | Incasare | `2638` |
-| `Cb_casa` | "Casa" (-> "Banca POS" pe POS) | Incasare | `2362` |
-| `Clb_serie_chit` | "Serie chitanta" | Incasare (doar Chitanta) | `2503` |
-| `Clb_nrchit` | "Nr. chitanta" (-> "Nr. bon" pe Bon fiscal/POS) | Incasare | `2480` |
-| `Clb_incasat` | "Incasat" | Incasare | `2461` |
-| `cmdModificaBon` | (icon `but_modifica`) | Incasare (doar Bon fiscal), `caction=do_modifica_bon` | `2526` |
-| `chkPOS` | "POS" | Incasare (doar Bon fiscal) | `2409` |
-| `chkDetaliat` | "Detaliat" | Incasare (doar Bon fiscal) | `2396` |
-| `cboTipFactura` | (combo, langa label "Tip factura") | Incasare | `2378` |
-| `clb_adresa_facturare` | "Adresa facturare" | Adresa de facturare | `2422` |
-| `Ed_tx_simplu1` | "Text aditional (max. 1000 caractere)" | Text aditional | `2585` |
-| `But_modifica1` | (icon) `caction` implicit -> `do_modifica` | actiune pe delegat (deschide `nom_parteneri_modifica`) | `2343` |
-
-**`actualizeaza_tipincasare`** (`2698-2856`) comuta vizibilitatea pe `This.opt_incasat.Value`:
-
-| Valoare | Vizibile | Ascunse | Numar alocat |
-|---|---|---|---|
-| 1 = Fara incasare | — | `cb_casa,clb_serie_chit,clb_nrchit,clb_incasat,_shape3,lb_simplu1,cmdModificaBon,chkPOS,chkDetaliat` | dezaloca 16(chitanta)/3(bon)/26(POS) |
-| 2 = Chitanta | `cb_casa,clb_serie_chit,clb_nrchit,clb_incasat,_shape3,lb_simplu1` | `cmdModificaBon,chkPOS,chkDetaliat` | `Thisform.clb_serie_chit.genereazaNumar()` (`2783`) |
-| 3 = Bon fiscal | `cb_casa,clb_nrchit,clb_incasat,_shape3,lb_simplu1,cmdModificaBon,chkPOS,chkDetaliat` | `clb_serie_chit` | `Thisform.do_aloca_nr_bon([CLICK])` (`2807`) |
-| 4 = POS/Card | `cb_casa,clb_nrchit,clb_incasat,_shape3,lb_simplu1,cmdModificaBon` | `clb_serie_chit,chkPOS,chkDetaliat` | `Thisform.do_aloca_nr_pos([CLICK])` (`2844`) |
-
-`cmdModificaBon.Click -> do_modifica_bon` (`3001-3010`) deschide `viz_config_serii_complet WITH 3`
-(`oserii_numere.prg`) si, la confirmare, dezaloca+realoca numarul de bon fiscal.
-
-## 5. Butoane `frm_facturi` (lista facturi, `ofacturare_comun.vc2:1168-5126`, fisierul real —
-verificat, nu `.pre_s4butoane.bak`)
-
-| Control | Caption/Picture | Metoda apelata (`caction`/override) | `fisier:linie` |
-|---|---|---|---|
-| `but_modifica1` | `modific_sus.bmp` | `caction` implicit = `inainte_de_do_modifica` -> meniu `xmenu("Modificare date factura;Editare factura (articole, cantitati, preturi)")` -> optiune 1: `do_modifica()`, optiune 2: **`do_editare_factura()`** | ADD OBJECT `1424`; `inainte_de_do_modifica` `4925-4934`; `do_modifica` `4538-4637`; `do_editare_factura` `3715-3869` |
-| `But_modifica2` | (fara caption, Top=341 — pe grid-ul de detalii, nu in bara de sus) | `caction=do_modifica_explicatie`, ToolTipText "Modificare explicatie articol" | `1434`; `do_modifica_explicatie` `4639-4656` |
-| `But_copiaza1` | `copy_sus.bmp`, `Visible=.F.` implicit | `caction` mostenit = `do_copiaza` | `1404`; `do_copiaza` `3628-3713` |
-| `But_sterge1` | `sterg_sus.bmp` | `caction` mostenit (`inainte_de_do_sterge` din clasa `but_sterge`) -> `do_sterge` | `1463`; `do_sterge` `4658-4874` |
-| `But_listare1` | `listare_sus.bmp` | `do_listare` | `1414` |
-| `But_verifica1` | (fara Picture explicit) | `do_verifica`, ToolTipText "Vericare coduri fiscale pe serverul ANAF" | `1473` |
-| `But_attach1` | `attach_sus.bmp` | `caction=` gol, override `But_attach1.Click` | `1394` |
-
-**Nu exista buton separat "editare 2024"**: `do_editare_factura` este optiunea 2 din meniul popup
-deschis de `but_modifica1` (`inainte_de_do_modifica`), nu un buton propriu.
-
-`Init` (`4936-4959`): daca `glLunaInchisa` (luna contabila inchisa),
-`Thisform.but_sterge1.Visible = .F.` si se scoate dreptul de stergere din `gcAcces` — singura
-conditionare de vizibilitate pe drept gasita in aceasta clasa.
-
-## Necunoscute ramase
-
-- `do_modifica` (frm_facturare_articole, `13746-13914`, 168 linii) si `do_sterge`/`do_editare_factura`
- (frm_facturi) nu au fost citite in detaliu — doar identificate ca existenta/semnatura; daca
- mockup-ul are nevoie de logica exacta de validare la modificare/stergere linie, trebuie citite
- explicit.
-- `frm_date_aviz.Init` (`7354-7600`) a fost citit doar pana la ~`7533`; ultimele ~65 linii (probabil
- finalizare `laPozitii`/repozitionare, simetrice cu `frm_date_factura`) nu au fost verificate.
-- Nu am verificat daca vizibilitatea controalelor din sectiunea 3 mai depinde si de **drept de
- utilizator** (nu doar `poDate.tip`/`gnScadereStoc`/`gnScadentaAutomata`) — codul citit foloseste
- doar variabile globale de setare firma si tipul documentului, nicio verificare explicita
- `gcAcces`/drepturi pe aceste containere.
-- Dimensiunile exacte (`Width`/`Height`) ale containerelor `ct_clb_cautare`/`clb_tx_*` nu sunt
- listate explicit in multe instante (mostenite din clasa de baza `caut_ora.vcx`/`lb_tx.vcx`) — nu
- am deschis acele biblioteci pentru dimensiuni implicite; doar `Left`/`Top`/`TabIndex` sunt
- suprascrise per instanta.
-- Nu am inspectat `caut_ora.vcx`/`lb_tx.vcx`/`serii_numere.vcx` (clasele de baza ale containerelor
- `clb_*`/`ct_clb_*`) pentru a confirma dimensiunile standard sau comportamentul exact al
- proprietatii `cconditie` (pare sa controleze cand campul de cautare cere obligatoriu o valoare,
- nu vizibilitatea).
diff --git a/docs/cercetare/legatura_linie_retur.md b/docs/cercetare/legatura_linie_retur.md
deleted file mode 100644
index e02cfd4..0000000
--- a/docs/cercetare/legatura_linie_retur.md
+++ /dev/null
@@ -1,228 +0,0 @@
-# Cercetare: legatura "linie de retur -> linie/factura originala" se persista undeva?
-
-## Verdict (10 randuri)
-
-**NU se persista la nivel de linie. PARTIAL la nivel de document, si numai cand a fost aleasa o
-singura factura sursa.** Cursorul Oracle care populeaza grila de retur pentru N.1 (documente tip
-8/9/24, `pack_facturare.cursor_retur_document`, `ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:3949-4062`)
-**nu selecteaza deloc** `A1.ID_VANZARE` sau `A1.ID_VANZARE_DET` din `VANZARI_DETALII` — legatura cu
-factura/linia sursa se pierde chiar in query-ul care aduce datele in VFP, inainte sa existe vreo
-sansa sa fie afisata. INSERT-ul final in `VANZARI_DETALII` (`scrie_in_vanzari`, documentat deja in
-`rec_cale_vanzari_detalii.md:105-113`) nu are nicio coloana de tip sursa. Exista in schimb un link
-**la nivel de document intreg**: `VANZARI_CORESP` (`TIP=3`, `ID_VANZARE_FACT`=documentul de retur,
-`ID_VANZARE_AVIZ`=fiecare factura sursa aleasa) — dar cand utilizatorul alege mai multe facturi
-sursa deodata (selectie multipla, suportata explicit de dialog), acest link iti da **multimea** de
-facturi posibile, nu factura exacta a liniei. Pentru N.2 (`But_retur`, per articol) nu exista niciun
-document nou scris separat — returul e o linie in factura normala curenta, iar "sursa" e verificata
-doar la nivel de stoc (`RUL`/`STOC` filtrat pe `COD` legat de `VANZARI.ID_VANZARE`), nu persista ca
-atribut al liniei noi. Concluzie pentru S4f: **se livreaza fara coloana de provenienta pe linie**;
-cel mult se poate afisa, cand e un singur document sursa, "factura de retur X provine din factura Y"
-la nivel de document (din `VANZARI_CORESP`), nu per linie.
-
-## 1. Ce face Oracle cu `poDate.listaid`
-
-Doua cai, in functie de mecanism:
-
-**N.1 (document, tip 8/9/24)**: `poDate.listaid` = CSV de `id_vanzare` (facturile alese la pasul de
-cautare multipla, `ofacturare.vc2:9200`: `poDate.listaid = cursor2lista("crsFacturiTemp", "id_vanzare", ",")`).
-Ajunge la Oracle ca parametru `V_LISTAID` in `pack_facturare.cursor_retur(V_IN_VALUTA, V_LISTAID,
-V_ID_UTIL, V_CURSOR)` (`ff_...sql:3934-3947`), care e doar un wrapper peste
-`cursor_retur_document(V_IN_VALUTA, V_LISTAID, V_COPIERE=0, V_PROFORMA, V_ID_UTIL, V_CURSOR)`
-(`:3949-4062`). Acolo `V_LISTAID` devine CTE-ul `CRS` (`:3962-3964`):
-```sql
-WITH CRS AS (SELECT X as ID_VANZARE FROM table(charn2collection(V_LISTAID, V_SEPARATOR)))
-```
-folosit doar ca filtru: `WHERE A1.STERS = 0 AND A1.ID_VANZARE IN (SELECT ID_VANZARE FROM CRS)`
-(`:4054-4055`). **Filtru, nu persistare** — dupa acest `WHERE`, `ID_VANZARE` nu mai apare deloc in
-lista de coloane a `SELECT`-ului extern (`:3965-4028`: `ID_C` (=`ROWNUM`, sintetic), `ID_ARTICOL`,
-`LOT`, `SERIE`, `ID_POL`, preturi, `GESTIONABIL`, `CANTITATE`, `ID_GESTIUNE`, `PRET_ACHIZITIE`... dar
-nu `ID_VANZARE` si nu `ID_VANZARE_DET`). Cursorul primit de VFP in `crsarticole` nu are, deci, nicio
-coloana care sa spuna din ce factura/linie vine randul.
-
-Separat, la scrierea efectiva a documentului de retur, `scrie_corespondente_vanzari(3)`
-(`:14834-14836`, apelata din `finalizeaza_factura`) foloseste tot `pack_facturare.clistaid`
-(= acelasi `poDate.listaid`, tinut in variabila de sesiune a pachetului) ca sa scrie in
-`VANZARI_CORESP` (`:15481-15516`):
-```sql
-INSERT INTO VANZARI_CORESP (ID_VANZARE_FACT, ID_VANZARE_AVIZ, TIP)
- SELECT pack_facturare.nid_vanzare, ID_VANZARE, 3
- FROM VANZARI WHERE ID_VANZARE IN (SELECT X FROM table(charn2collection(V_LISTAID,',')));
-```
-Asta scrie **cate un rand per factura sursa aleasa** (nu per linie), cu noul document de retur ca
-`ID_VANZARE_FACT` si fiecare sursa ca `ID_VANZARE_AVIZ` (numele coloanei e generic, reutilizat si
-pentru perechi aviz-factura, `TIP=1/2`, vezi `sterge_factura:5452-5457,5582-5585`).
-
-**N.2 (`But_retur`, per articol)**: `poDate.listaid` = `"ID_ARTICOL:ID_VANZARE"` (una sau mai multe
-perechi CSV, `ofacturare.vc2:12888`: `thisform.cListaIdArticoleRetur = ... + STR(poArticol.id_articol) + ':' + poDate.listaid`,
-trimis la Oracle la `:13978`). In `pack_facturare` (verificat in ramura `WHEN V_CANTE < 0 and
-pack_facturare.clistaid is not null and instr(pack_facturare.clistaid, ':') > 0`,
-`ff_...sql:8142-8212`) e folosit ca filtru pentru calculul cantitatii disponibile de retur din
-rulaj (`RUL`), NU ca sa scrie o legatura:
-```sql
-AND A.COD IN (SELECT COD FROM VANZARI WHERE ID_VANZARE IN
- (SELECT id_vanzare FROM (SELECT CAST(GETWORDNUM(id_articol_id_vanzare,1,':') AS NUMBER(20,0)) id_articol,
- CAST(GETWORDNUM(id_articol_id_vanzare,2,':') AS NUMBER(20,0)) id_vanzare
- FROM (SELECT x AS id_articol_id_vanzare FROM table(cast(CHARC2COLLECTION(pack_facturare.clistaid,',') AS char_tab))))
- WHERE id_articol = V_ID_ARTICOL))
-```
-Foloseste `listaid` doar ca sa restranga `RUL` la miscarile de stoc (`A.COD`) legate de factura
-aleasa, ca sa calculeze **cantitatea inca disponibila in gestiune din acea vanzare** pentru articolul
-respectiv (`tab_stoc`, tip=1 in acel `SELECT`). Nu se scrie nicio linie noua de legatura in vreun
-tabel — e folosit exclusiv ca filtru intr-un calcul de disponibil.
-
-## 2. Coloana de provenienta pe `VANZARI_DETALII`
-
-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`,
-`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`,
-`PRET`, `CANTITATE`, `PRET_CU_TVA`, `DISCOUNT_UNITAR`, `PROC_TVAV`, `ID_GESTIUNE`, `CONT`,
-`ID_VALUTA`, `ID_JTVA_COLOANA`, `SERIE`, `EXPLICATIE`, `TAXCODE`, `LOT`, `STERS`, `VALIDAT`,
-`DATAORA_VALID`, `ID_UTIL_VALID`, `ID_UTILS`, `DATAORAS`, `DIFERENTA`, `CUSTODIE`, `DESCARCAT`,
-`PRETD`, `ID_VALUTAD`, `PRETV_ORIG`, `ID_CTR`, `ID_RATA`. **Nicio coloana** de tipul
-`ID_VANZARE_SURSA`, `ID_DETALIU_SURSA`, `ID_FACT_SURSA`, `ID_VANZARE_RETUR`, `ID_ORIGINAL` sau orice
-self-referinta catre o alta linie `VANZARI_DETALII`. Cautat explicit acele siruri in tot exportul
-`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (~28000 linii) si in `COMUN\docs\` — zero potriviri
-(vezi comanda de mai jos, sectiunea "Ramas de verificat").
-
-Confirmarea independenta finala si cea mai directa: INSERT-ul care trece liniile din
-`VANZARI_DETALII_TEMP` in `VANZARI_DETALII` la finalizarea oricarui document (inclusiv retur, pentru
-ca `scrie_in_vanzari` e comun tuturor tipurilor) are lista de coloane explicita
-(`rec_cale_vanzari_detalii.md:105-113`):
-```sql
-INSERT /*+ APPEND */ INTO VANZARI_DETALII
- (ID_VANZARE, ID_ARTICOL, SERIE, ID_POL, CANTITATE, PRET_ACHIZITIE, PRETD, ID_VALUTAD,
- PRET, PROC_TVAV, DISCOUNT_UNITAR, ID_GESTIUNE, ID_VALUTA, CONT, PRET_CU_TVA, ID_JTVA_COLOANA)
-SELECT pack_facturare.nid_vanzare, ID_ARTICOL, ... FROM VANZARI_DETALII_TEMP WHERE ...
-```
-Nicio coloana sursa in lista. Cum `VANZARI_DETALII_TEMP` insasi e populata pentru retur din
-`cursor_retur_document` (care, cf. punctul 1, nu aduce `ID_VANZARE`/`ID_VANZARE_DET` sursa), legatura
-e pierduta cu doi pasi inainte de a ajunge la acest INSERT — nu doar "nu se scrie", ci "nu mai exista
-in date la momentul scrierii".
-
-## 3. Tabel separat de legatura
-
-**Da, exista, dar la nivel de document, nu de linie**: `VANZARI_CORESP(ID_VANZARE_FACT,
-ID_VANZARE_AVIZ, TIP, STERS)`. Folosit pentru mai multe perechi de corespondenta, disambiguizate prin
-`TIP`:
-- `TIP=1`: factura scrisa dintr-un aviz (`scrie_corespondente_vanzari(1)`, la facturare din aviz,
- `:14826`);
-- `TIP=2`: aviz de retur (`scrie_corespondente_vanzari(2)`, `:14830`, la `ntip=24`);
-- `TIP=3`: **factura de retur** (`scrie_corespondente_vanzari(3)`, `:14834-14836`, la `ntip in (8,9)`)
- — exact cazul cerut de S4f.
-
-Verificarile de stergere din `sterge_factura` (`:5450-5494`) confirma semantica: interogheaza
-`VANZARI_CORESP WHERE ID_VANZARE_AVIZ = V_ID_VANZARE AND TIP = 3` pentru "exista facturi de retur pe
-aceasta factura?" — deci pentru o factura normala, `ID_VANZARE_AVIZ` (nume generic, refolosit) e ea
-insasi, iar `ID_VANZARE_FACT` gasit prin acea interogare e factura(le) de retur emise pe baza ei.
-Invers, pentru un document de retur dat, `SELECT ID_VANZARE_AVIZ FROM VANZARI_CORESP WHERE
-ID_VANZARE_FACT = :id_retur AND TIP = 3` da **toate** facturile sursa alese la emiterea acelui retur
-(poate fi mai multe, cf. selectie multipla din `caut_facturi_multiple_client`,
-`docs/cercetare/factura_retur_document.md:67-85`).
-
-**Limita exacta**: cand pe un document de retur exista o singura factura sursa in `VANZARI_CORESP`,
-"factura originala" e determinata fara ambiguitate pentru **toate** liniile documentului de retur
-(pentru ca nu exista alt candidat). Cand exista mai multe (utilizatorul a bifat 2+ facturi la
-cautare), `VANZARI_CORESP` da multimea, dar nu se poate spune care linie de retur vine din care
-factura din multime — informatia care ar face diferenta (ID_VANZARE per linie in cursorul de
-populare) a fost deja aruncata la pasul 1/2. Nu exista niciun tabel `VANZARI_RETUR`, `RETUR_DETALII`
-sau `LEGATURI_DOCUMENTE`; cautate explicit in `ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` si in
-`COMUN\docs\` — zero potriviri.
-
-`DOCUMENTE.AVIZE` (coloana denormalizata pe `VANZARI`, nu tabel separat) e completata redundant tot
-din `VANZARI_CORESP` (`scrie_corespondente_vanzari:15505-15514`, `UPDATE VANZARI SET AVIZE = ...`) —
-tine text afisabil (serie+numar avize), nu un id structurat, si nu e populata pentru `TIP=3` (doar
-pentru avize, vezi apelul unic la acel `UPDATE` in corpul procedurii, comun tuturor `V_TIP`-urilor
-dar cu sens practic doar pentru avize-spre-factura).
-
-## 4. Cum calculeaza serverul maximul returnabil
-
-**Raspunsul e diferit pe cele doua mecanisme, si niciunul nu se sprijina pe o legatura persistata
-linie-la-linie:**
-
-**N.1 (document)**: NU exista un calcul de "cat s-a mai returnat deja". Coloana pe care utilizatorul
-o vede ca "Cant. max. de returnat" (`ofacturare.vc2:15238,15243` — doar schimbare de caption pe capul
-de coloana, nu logica noua) e pur si simplu `CANTITATE` a liniei originale, asa cum vine din
-`cursor_retur_document` (`A1.CANTITATE`, `:4036`, filtrat doar pe `A1.STERS = 0`, fara nicio
-agregare cu alte retururi anterioare pe aceeasi linie). Validarea din
-`do_verifica_articol` (`:14743-14754`) nu face niciun calcul suplimentar de disponibil — blocheaza
-doar cazul `tnCantitate >= 0` cand esti in mod retur (semnul gresit), nu o depasire de maxim istoric.
-**Consecinta directa**: daca acelasi utilizator emite doua facturi de retur separate pe aceeasi
-factura sursa, a doua interogare `cursor_retur_document` va aduce din nou linia originala cu
-`CANTITATE` **intreaga**, neredusa de primul retur — nimic in cod nu scade sau marcheaza cat s-a
-returnat deja la acest nivel. Acesta e cel mai clar indiciu ca legatura linie-la-linie *nu* e tinuta
-nicaieri pentru N.1: daca ar fi fost tinuta, ar fi trebuit folosita exact aici, ca sa capeze
-cantitatea, si nu e.
-
-**N.2 (`But_retur`)**: exista un calcul real de disponibil, dar e un calcul de **stoc/rulaj**, nu de
-"cat s-a returnat pe acea linie". Ramura din `pack_facturare` citata la punctul 1
-(`ff_...sql:8142-8212`) calculeaza cantitatea inca prezenta in `RUL` (miscari de stoc) care a venit
-din vanzarea aleasa (`RUL.COD` legat prin `VANZARI.COD`, filtrat pe `id_articol:id_vanzare` din
-`listaid`), plus `STOC`/`RUL_TEMP` pentru cazul general. E un calcul valid de "poti scoate din
-gestiune atat cat inca exista acolo cu provenienta asta", sprijinit pe legatura persistata
-`RUL.COD -> VANZARI.COD` (asta e adevarata "legatura care exista" pentru N.2) — dar e o legatura la
-nivelul miscarii de stoc, nu un contor "cantitate returnata" pe `VANZARI_DETALII`, si nu se
-translateaza in nicio coloana de provenienta pe linia noua scrisa.
-
-## 5. Ce se poate afisa efectiv
-
-- **Numarul/seria facturii originale la nivel de document de retur, cand exista o singura factura
- sursa**: SE POATE, din `VANZARI_CORESP` (`TIP=3`) join `VANZARI` pe `ID_VANZARE_AVIZ`. Interogare
- de rulat pe baza vie (nu verificata aici, doar formulata):
- ```sql
- SELECT v.serie_act, v.numar_act
- FROM VANZARI_CORESP c JOIN VANZARI v ON v.ID_VANZARE = c.ID_VANZARE_AVIZ
- WHERE c.ID_VANZARE_FACT = :id_document_retur AND c.TIP = 3 AND c.STERS = 0;
- ```
- Daca randul e unic, se poate afisa "provine din factura X" **pe capul documentului de retur**
- (nu pe linie — toate liniile ar arata aceeasi sursa, pentru ca e singura posibila).
-- **Cand documentul de retur are 2+ facturi sursa** (selectie multipla permisa de dialog): se poate
- afisa lista de facturi sursa posibile (tot din `VANZARI_CORESP`), dar NU care linie vine din care
- factura din lista — informatia nu exista.
-- **Numarul facturii originale pe fiecare linie individuala de retur**: NU SE POATE, in niciun caz —
- nici cand exista un singur document sursa (pentru ca "linie cu linie" nu inseamna nimic diferit de
- "documentul cu documentul" atunci, dar afirmatia stricta "aceasta linie de retur vine din linia Y a
- facturii" nu poate fi demonstrata din date, doar presupusa cand exista un singur candidat), si sigur
- nu cand exista mai multe facturi sursa sau cand linia e libera (permisa explicit de decizia 22).
-- Pentru N.2 (retur in factura normala, tip 1/5/7/10): nu exista deloc "document de retur" separat de
- arata provenienta — linia de retur e o linie normala (cu cantitate negativa) in factura curenta;
- singura urma a sursei e `RUL.COD`/`VANZARI.COD` folosita tranzitoriu la calculul de disponibil, nu
- persistata pe linia noua din `VANZARI_DETALII`.
-
-## Verdict pentru plan (S4f)
-
-**NU se persista legatura linie-la-linie.** Pentru documentul de retur (N.1), se poate afisa
-"factura sursa" **la nivel de document**, din `VANZARI_CORESP` (TIP=3), **doar cand exista exact o
-singura factura sursa aleasa** — cazul cu selectie multipla da doar multimea, fara atribuire per
-linie. Pe linia individuala de retur nu se poate afisa nimic verificabil din date, in niciun caz.
-Recomandare pentru S4f: se livreaza fara coloana de provenienta pe linie (cf. deciziei deja scrise in
-plan, "nu se inventeaza"); daca se vrea un gest minim, singura afisare sustenabila cu date e un text
-de tip "Retur pentru factura: X" pe **capul** documentului (deja exista, cf.
-`factura_retur_document.md:85`: `poDate.text_aditional = ... + poDate.descriere`, unde
-`poDate.descriere` e lista serie+numar a facturilor alese) — nu pe linie, si nu nou, e deja acolo.
-
-## Ramas de verificat pe baza vie
-
-- Nu s-a interogat live daca `VANZARI_CORESP.TIP=3` e scris consecvent pentru fiecare factura de
- retur emisa istoric (posibil sa existe date vechi scrise inainte ca aceasta ramura sa existe, sau
- prin alt cod neexaminat aici) — de rulat:
- ```sql
- SELECT COUNT(*) FROM VANZARI v
- WHERE v.TIP IN (8,9) AND v.STERS = 0
- AND NOT EXISTS (SELECT 1 FROM VANZARI_CORESP c WHERE c.ID_VANZARE_FACT = v.ID_VANZARE AND c.TIP = 3);
- ```
- Daca da >0, exista facturi de retur fara nicio legatura de document persistata, nici macar cea
- partiala descrisa mai sus.
-- Nu s-a verificat live cate din facturile de retur existente au >1 factura sursa in
- `VANZARI_CORESP` (adica cate din documentele reale ar cadea in cazul "multime, nu atribuire") —
- utila pentru a decide cat de des s-ar aplica de fapt afisarea propusa la punctul 5.
-- Nu s-a gasit (si nici nu era in scop) un mecanism separat pentru avize de retur custodie (`tip=50`,
- marcat "in lucru" in `tipuri_documente_facturare.md`) — daca S4f ajunge sa acopere si acel tip, de
- recercetat separat.
-- Subagentul de research auxiliar lansat pentru confirmarea independenta a definitiei
- `caut_facturi_multiple_client`/`caut_facturi_multiple_client_articol` nu a returnat un raport
- utilizabil (rezultat gol la finalizare); definitiile au fost gasite si citite direct in aceasta
- sesiune, in `COMUN\programe\oproceduri_facturare.prg:2091-2160`, deci nu blocheaza verdictul, dar
- nu a adaugat nimic peste ce e deja in acest raport.
diff --git a/docs/cercetare/linii_comanda_articol_nemembru.md b/docs/cercetare/linii_comanda_articol_nemembru.md
deleted file mode 100644
index 048fca1..0000000
--- a/docs/cercetare/linii_comanda_articol_nemembru.md
+++ /dev/null
@@ -1,182 +0,0 @@
-# Linii de comanda cu articol nemembru al politicii de pret — verificare facturare
-
-Status: FINALIZAT.
-
-## Verdict
-
-**DA — s-a facturat cel putin o linie fara ca FACT-024 sa se declanseze.** Comanda `497`, linia
-`4294507522` (VOUCHER DISCOUNT) / politica `7` (DISCOUNT), a fost facturata cu succes in factura
-`ID_VANZARE=1028` (serie `SSS`, numar `535`, `FACTURAT=1`, `DATA_FACTURAT=2026-03-20`), desi
-articolul **nu e membru** al politicii 7 in `CRM_POLITICI_PRET_ART` la data acestei cercetari
-(10.08.2026). **Decizia 32 se REDESCHIDE partial**: nu pentru ca ar exista o cale de cod care ocoleste
-verificarea (codul chiar cheama `contabilizeaza_articol` pentru acest tip de vanzare, cf. punctul 3),
-ci pentru ca datele arata ca membru-ul politicii **s-a schimbat dupa facturare** — vezi punctul 4.
-Pentru celelalte 34 de linii cu acelasi articol/politica (35 in total cu `CANTITATE<0`), **nu exista
-nicio factura, nici macar stearsa** — la ele fisura ramane doar o stare inconsistenta nefacturata
-(vezi punctul 1).
-
-Observatie structurala separata de cea de mai sus: **inca 2 linii** (comenzile 114 si 115, alt articol,
-alta politica) au `CANTITATE>0`, adica **nefacturate inca deloc** — pentru acestea afirmatia "ar trebui
-sa cada la facturare" e neverificata pentru ca nu au fost niciodata trecute prin `contabilizeaza_articol`.
-
-## 1. S-a facturat vreuna din ele fara eroare?
-
-Interogare: pentru fiecare din cele 37 linii `COMENZI_ELEMENTE` cu `ID_POL NOT NULL` si articol
-nemembru in `CRM_POLITICI_PRET_ART`, am cautat linii `VANZARI_DETALII` (prin `VANZARI.ID_COMANDA`)
-cu acelasi `ID_ARTICOL`+`ID_POL`, **inclusiv cele sterse** (ca sa nu ratez o factura anulata):
-
-```sql
-select ce.id_comanda_element, ce.id_comanda, ce.id_articol, ce.id_pol, ce.cantitate,
- (select count(*) from vanzari v join vanzari_detalii vd on vd.id_vanzare=v.id_vanzare
- where v.id_comanda = ce.id_comanda and vd.id_articol=ce.id_articol and vd.id_pol=ce.id_pol) as nr_total_incl_sters
-from comenzi_elemente ce
-where ce.id_pol is not null and ce.cantitate < 0
-and not exists (select 1 from crm_politici_pret_art cppa
- where cppa.id_pol = ce.id_pol and cppa.id_articol = ce.id_articol);
-```
-
-Rezultat: **doar comanda 497** are potriviri (2 linii `VANZARI_DETALII`, id 1494 si 1495, ambele
-`STERS=0`, `CANTITATE=-1` fiecare, apartinand facturii `ID_VANZARE=1028`). Toate celelalte 34 de
-comenzi (349, 351, 352, 359, 360, 377, 388, 404, 412, 417, 429, 443, 447, 450, 451, 453, 455, 456,
-457, 466, 471, 475, 486, 500, 501) au **0 potriviri**, inclusiv sters.
-
-**Interpretare structurala a mecanismului** (cititul codului, nu presupunere): singurul loc care
-insereaza randuri cu `CANTITATE<0` in `COMENZI_ELEMENTE` e procedura `inchide_comanda`
-(`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:5769-5820`):
-
-```sql
-INSERT INTO COMENZI_ELEMENTE (... CANTITATE ...)
- SELECT ..., NVL(C.CANTITATE, 0) + NVL(B.CANTITATE, 0) - A.CANTITATE AS CANTITATE, ...
- FROM COMENZI_ELEMENTE A
- LEFT JOIN (... FROM VANZARI_DETALII_TEMP ...) B ON ... -- lotul curent de facturare
- LEFT JOIN (... FROM VANZARI JOIN VANZARI_DETALII ...) C ON ... -- deja facturat anterior
- WHERE A.ID_COMANDA = :comanda
- AND SIGN(A.CANTITATE) * A.CANTITATE >
- SIGN(A.CANTITATE) * (NVL(C.CANTITATE, 0) + NVL(B.CANTITATE, 0));
-```
-
-Asta insemna ca randul negativ **nu dovedeste singur ca linia a fost facturata** — el reprezinta
-*diferenta ramasa* fata de cantitatea comandata, la momentul **inchiderii** comenzii, chiar daca
-`B` (lotul curent) si `C` (facturat anterior) sunt amandoua 0. O comanda inchisa fara sa i se
-factureze o anumita linie tot primeste un rand `CANTITATE = -A.CANTITATE`. De-asta 34 din 35 de
-linii "negative" nu au nicio factura in spate: comenzile respective au fost **inchise** (probabil
-manual, ca "restanta anulata"), nu facturate pe acea linie. **Zero cazuri in date pentru acestea nu
-demonstreaza ca nu se poate factura — demonstreaza doar ca nu s-a intamplat.**
-
-Pentru comanda 497 insa, potrivirea cu 2 linii reale, active, `FACTURAT=1` in `VANZARI_DETALII`
-e dovada directa (nu inferenta) ca acea combinatie articol/politica **a ajuns** intr-o factura emisa.
-
-## 2. Reconfirmarea cifrei si lista liniilor
-
-Cifra **37** se reconfirma exact (nu 6868/nemembru cum sugera masuratoarea anterioara — aceea era
-alt numitor; numitorul corect pentru linii cu `ID_POL NOT NULL` e **7108**, nu 6868):
-
-```sql
-select count(*) from comenzi_elemente ce where ce.id_pol is not null; -- 7108
-select count(*) from comenzi_elemente ce where ce.id_pol is not null
- and not exists (select 1 from crm_politici_pret_art cppa
- where cppa.id_pol = ce.id_pol and cppa.id_articol = ce.id_articol); -- 37
-```
-
-Compozitie (verificata, `select sign(cantitate), count(*) ... group by sign(cantitate)`):
-- **35 linii** cu `CANTITATE=-1`: acelasi articol/politica in toate — `ID_ARTICOL=4294507522`
- ("VOUCHER DISCOUNT"), `ID_POL=7` ("DISCOUNT"). Comenzi: 349(x2), 351, 352(x2), 359, 360(x2), 377,
- 388, 404, 412(x2), 417, 429, 443, 447, 450, 451, 453, 455, 456, 457, 466, 471(x2), 475(x2),
- 486(x2), 497(x2), 500, 501(x2).
-- **2 linii** cu `CANTITATE=+10` (nefacturate inca, nicio urma de consum):
- - comanda 114, `ID_ARTICOL=4294507508` ("CAFEA TEST - PRODUS TEST PENTRU IMPORT WEB"), `ID_POL=2`
- ("LISTA 2"), data comanda 2025-09-10, `COMENZI.STERS` neverificat suplimentar dar randul e
- prezent activ.
- - comanda 115, `ID_ARTICOL=4171144217` ("CAFEA 1"), `ID_POL=2`. **Anomalie separata**: `COMENZI`
- nu contine niciun rand cu `ID_COMANDA=115` — antetul comenzii lipseste, doar linia de element a
- supravietuit. NEDETERMINABIL DIN DATE de ce (nu exista audit/istoric pe `COMENZI`); posibil
- date de test/import, dat fiind ca articolul insusi e "CAFEA TEST ... PENTRU IMPORT WEB" pe
- cealalta linie similara.
-
-Toate cele 37 de linii au `COMENZI_ELEMENTE.STERS=0` (nicio linie de comanda marcata stearsa).
-
-Stare de facturare per linie: singura cu urma reala de facturare e comanda 497 (vezi punctul 1);
-restul de 36 sunt **nefacturate** pe aceasta combinatie articol/politica.
-
-## 3. Verificare cod FACT-024 (`contabilizeaza_articol`)
-
-Blocul citat in brief (`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:7278-7302`) e identic cu ce ruleaza
-in productie — verificat direct in codul compilat, nu doar in scriptul istoric (fisierul `.sql` e un
-istoric cumulativ cu **doua definitii** ale `contabilizeaza_articol` in text, la linia 746 si la
-7173; doar a doua e cea vie):
-
-```sql
-select owner, line from all_source
- where name='PACK_FACTURARE' and type='PACKAGE BODY'
- and text like '%FACT-024%';
-```
-confirma acelasi text de eroare in schema `MARIUSM_AUTO` (Dev).
-
-Verificarea foloseste view-ul `VCRM_POLITICI_PRET_ART`:
-```sql
-SELECT COMPUS, ID_POL_ART INTO ... FROM VCRM_POLITICI_PRET_ART
- WHERE ID_ARTICOL = detalii_articol.id_articol AND ID_POL = detalii_articol.id_pol;
-EXCEPTION WHEN NO_DATA_FOUND THEN ... RAISE_APPLICATION_ERROR(-20000, ... '(FACT-024)');
-```
-Am verificat textul view-ului (`user_views`): `VCRM_POLITICI_PRET_ART` are `CRM_POLITICI_PRET_ART PA`
-ca tabel-sursa (driving table) al tuturor `LEFT JOIN`-urilor, fara niciun `WHERE` care sa filtreze
-`PA` (nu exista coloana `STERS` pe `CRM_POLITICI_PRET_ART`). Deci view-ul are exact acelasi set de
-perechi `(ID_POL, ID_ARTICOL)` ca tabelul de baza — verificarea mea prin `NOT EXISTS` pe
-`CRM_POLITICI_PRET_ART` e echivalenta cu ce evalueaza codul. **Concluzie: pentru toate cele 37 de
-linii, `SELECT ... INTO` ar da `NO_DATA_FOUND` -> `FACT-024`, daca ar trece prin
-`contabilizeaza_articol` ACUM, cu starea curenta a `CRM_POLITICI_PRET_ART`.**
-
-Apelul e neconditionat pentru facturi standard: am cautat toate apelurile
-`pack_facturare.contabilizeaza_articol(tab_detalii(i))` in codul **compilat** (`all_source`, schema
-`MARIUSM_AUTO`) — 6 aparitii, linii 4877, 4901, 5594, 5618, 5876, 5900. Linia 4901 e in procedura
-`scrie_factura2` (facturarea principala), in ramura `ELSE` a unui `CASE pack_facturare.ntip` care
-exclude doar transferurile intre subunitati (23,25,30,41), avizele de custodie (42,47) si facturile
-cu rate (2,6,52 cu `id_rata<>0`) — **tip 3 (tipul facturii 1028) cade in ELSE, deci
-`contabilizeaza_articol` chiar s-a executat pentru acea linie.**
-
-Prin urmare, pentru comanda 497: fie (a) la data facturarii (20.03.2026) articolul 4294507522 CHIAR
-era membru al politicii 7 si a fost scos ulterior din `CRM_POLITICI_PRET_ART`, fie (b) verificarea a
-fost ocolita altfel. Nu am gasit dovada de tip (b) — vezi punctul 4.
-
-## 4. Cauza
-
-`CRM_POLITICI_PRET_ART` **nu are coloana `STERS`** si nu exista niciun tabel de istoric/audit pentru
-ea (`select table_name from user_tables where table_name like '%POLITICI%' or ... '%AUDIT%'` — doar
-tabelele de configurare curenta, niciunul de istoric). Stergerile din aceasta tabela sunt deci
-**fizice, fara urma**. Nu pot reconstitui direct daca perechea (politica 7, articol 4294507522) a
-existat la 20.03.2026.
-
-Coloanele de audit disponibile pe randurile facturii/comenzii **nu arata nicio editare ulterioara**:
-`VANZARI.ID_UTILS`/`DATAORAS` si `VANZARI_DETALII.ID_UTILS`/`DATAORAS` (1494, 1495) sunt toate NULL —
-niciun `UPDATE` standard nu a atins aceste randuri dupa creare. Deci nu exista dovada ca linia de
-factura ar fi fost modificata ulterior prin fluxul nou de "editare factura emisa" (adaugat recent in
-proiect, cf. changelog 2.11.15) — desi asta nu exclude o editare care ar fi ocolit acele coloane de
-audit, doar ca nu am gasit dovada ei.
-
-Indiciu indirect, dar nu concludent: articolul 4294507522 e denumit **"VOUCHER DISCOUNT"**, iar
-politica 7 e **"DISCOUNT"** — o pereche generica folosita ca linie de discount pe **35 de comenzi
-diferite**, nu un caz izolat. Reutilizarea masiva a exact aceleiasi perechi sustine ipoteza unei
-**modificari de catalog** (articolul-voucher scos ulterior din lista politicii DISCOUNT ca decizie de
-business/curatare), mai degraba decat 35 de erori de introducere independente. **Aceasta ramane insa
-o inferenta din tipar, nu o dovada directa — se marcheaza NEDETERMINABIL DIN DATE strict pe cauza si
-data exacta a schimbarii.**
-
-## Ce am incercat si ce a esuat
-
-- Doua incercari de a delega cautarea codului sursa VFP/PL-SQL unui subagent `Explore` au esuat cu
- raspunsuri goale/neinformative ("Nimic nou.", "No new input to act on.") — fara nicio dovada ca ar
- fi rulat vreo cautare. Am renuntat la delegare si am facut cautarile direct cu Grep si Read.
-- Interogarea `all_source` fara `owner=` a intors linii duplicate/interclasate (schema `ACN` are de
- asemenea un `PACK_FACTURARE`) — a trebuit filtrat explicit pe `owner='MARIUSM_AUTO'` pentru
- rezultate coerente.
-- Un `prompt '---text---'` intre doua instructiuni SQL in acelasi fisier `.sql` a produs iesire
- amestecata (headerul s-a lipit de urmatoarea instructiune) — am renuntat la `prompt` si am rulat
- interogarile in fisiere separate.
-
-## Date tehnice folosite
-
-- Conexiune: `MARIUSM_AUTO/ROMFASTSOFT@ROA_CENTRAL` (Dev), via
- `D:\ROA\instantclient_19_18\sqlplus.exe`, fisiere `.sql` ASCII in scratchpad, niciun `INSERT`/`UPDATE`/`DDL` rulat.
-- Cod verificat: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`
- (text istoric cumulativ) si pachetul compilat `MARIUSM_AUTO.PACK_FACTURARE` (`all_source`, sursa de
- adevar pentru ce ruleaza efectiv).
diff --git a/docs/cercetare/modifica_date_factura_parametri.md b/docs/cercetare/modifica_date_factura_parametri.md
deleted file mode 100644
index 53b925e..0000000
--- a/docs/cercetare/modifica_date_factura_parametri.md
+++ /dev/null
@@ -1,124 +0,0 @@
-# Cercetare: `pack_facturare.modifica_date_factura` — parametri, mapare pe coloane si pe controale
-
-Sursa pachetului: `D:\ROA\ROAACNPRO\PACK_FACTURARE.pck` (declaratie spec `:921-935`, corp `:14392-14462`).
-Apel VFP: `D:\ROA\ROAFACTURARE\COMUN\clase\ofacturare_comun.vc2`, metoda `frm_facturi.do_modifica` (`:4538-4637`),
-apelul efectiv la `:4599-4614`. Formular de editare: `frm_modifica_factura` (`:5262-5774`).
-
-Nu exista alt fisier `.pck`/`.sql` cu semnatura diferita pentru `modifica_date_factura` in
-`D:\ROA\ROAFACTURARE` sau `COMUN`; niciun alt loc din VFP (in afara de `ofacturare_comun.vc2` si
-copia identica `.bak`) nu apeleaza procedura — cautat cu grep pe `*.vc2/*.sc2/*.prg` in tot arborele.
-
-## 1-2. Tabel parametri (semnatura + destinatie in Oracle)
-
-| # | Parametru | Tip (`.pck:921-935`) | Coloana / tabel scrise in corp (`.pck:14392-14462`) | Observatii |
-|---|---|---|---|---|
-| 1 | `V_ID_VANZARE` | `NUMBER` | Folosit doar in `WHERE ID_VANZARE = V_ID_VANZARE` (`:14424`) si ca sursa pentru `lnIdFact` (`:14426`) | Identitate randului, niciodata scris |
-| 2 | `V_ID_RUTA` | `NUMBER` | `VANZARI.ID_RUTA` (`:14414`) | Scris neconditionat |
-| 3 | `V_ID_DELEGAT` | `NUMBER` | `VANZARI.ID_DELEGAT` (`:14415`) | Scris neconditionat |
-| 4 | `V_ID_AGENT` | `NUMBER` | `VANZARI.ID_AGENT` (`:14416`) | Scris neconditionat |
-| 5 | `V_ID_MASINA` | `NUMBER` | `VANZARI.ID_MASINA` (`:14417`) | Scris neconditionat |
-| 6 | `V_DATAORA_EXP` | `DATE` | `VANZARI.DATAORA_EXP` (`:14418`) | Scris neconditionat |
-| 7 | `V_ID_FACTURARE` | `VANZARI.ID_FACTURARE%TYPE` | `VANZARI.ID_FACTURARE` (`:14419`) | Scris neconditionat |
-| 8 | `V_LISTARE_DETALIATA` | `VANZARI.LISTARE_DETALIATA%TYPE` | `VANZARI.LISTARE_DETALIATA = NVL(V_LISTARE_DETALIATA, 0)` (`:14420`) | NVL la 0 |
-| 9 | `V_TEXT_ADITIONAL` | `VANZARI.TEXT_ADITIONAL%TYPE` | `VANZARI.TEXT_ADITIONAL` (`:14421`) | Scris neconditionat, fara NVL |
-| 10 | `V_TIP_SAFT` | `VANZARI.TIP_SAFT%TYPE DEFAULT NULL` | `VANZARI.TIP_SAFT` (`:14422`) | Scris neconditionat |
-| 11 | `V_EFACTURA` | `VANZARI.EFACTURA%TYPE DEFAULT NULL` | `VANZARI.EFACTURA` (`:14423`) | Scris neconditionat |
-| 12 | `V_DATA_ACT` | `VANZARI.DATA_ACT%TYPE DEFAULT NULL` | `VANZARI.DATA_ACT` (`:14448`) + `DOCUMENTE.DATAACT`, `ACT.DATAACT`, `IREG_PARTENERI.DATAACT`, `JV2007.DATAACT`, `RUL.DATAACT` si `RUL.DATAOUT` (`:14449-14453`), toate `WHERE ID_FACT = lnIdFact` | Doar daca `V_DATA_ACT IS NOT NULL AND V_DATA_ACT <> NVL(ldDataAct, SYSDATE)` (`:14447`) |
-| 13 | `V_DATA_SCAD` | `VANZARI.DATA_SCAD%TYPE DEFAULT NULL` | `VANZARI.DATA_SCAD` (`:14457`) + `ACT.DATASCAD`, `IREG_PARTENERI.DATASCAD` (`:14458-14459`), `WHERE ID_FACT = lnIdFact` | Doar daca `V_DATA_SCAD IS NOT NULL AND V_DATA_SCAD <> NVL(ldDataScad, sysdate)` (`:14456`) |
-| 14 | `V_NUMAR_ACT` | `VANZARI.NUMAR_ACT%TYPE DEFAULT NULL` | `VANZARI.NUMAR_ACT` (`:14439`) + `DOCUMENTE.NRACT`, `ACT.NRACT`, `IREG_PARTENERI.NRACT`, `JV2007.NRACT`, `RUL.NRACT` (`:14440-14444`), `WHERE ID_FACT = lnIdFact` | Doar daca `V_NUMAR_ACT IS NOT NULL AND V_NUMAR_ACT <> NVL(lnNrAct, 0)` (`:14438`) |
-| 15 | `V_SERIE_ACT` | `VANZARI.SERIE_ACT%TYPE DEFAULT NULL` | `VANZARI.SERIE_ACT` (`:14429`) + `DOCUMENTE.SERIE_ACT`, `ACT.SERIE_ACT`, `IREG_PARTENERI.SERIE_ACT`, `JV2007.SERIE_ACT`, `RUL.SERIE_ACT` (`:14430-14434`), `WHERE ID_FACT = lnIdFact` | Doar daca `V_SERIE_ACT IS NOT NULL AND V_SERIE_ACT <> NVL(lcSerieAct, '')` (`:14428`) |
-
-Parametrii 2-11 se scriu neconditionat in `VANZARI` la fiecare apel (chiar cu `NULL`, daca asa vine
-argumentul). Parametrii 12-15 (`data_act`, `data_scad`, `numar_act`, `serie_act`) au tratament
-conditionat: se propaga si in `DOCUMENTE`/`ACT`/`IREG_PARTENERI`/`JV2007`/`RUL` (unde e cazul),
-filtrate dupa `ID_FACT` (nu dupa `ID_VANZARE`) — deci ating toate randurile din acele tabele legate
-de acelasi document, nu doar randul `VANZARI` curent. Se scriu doar daca valoarea trimisa e
-`NOT NULL` si difera de valoarea curenta.
-
-## 3. Apelul din VFP
-
-`COMUN\clase\ofacturare_comun.vc2:4599-4614`, in interiorul unui `SCAN` peste `crsfacturi` (una sau
-mai multe inregistrari alese):
-
-```
-begin pack_facturare.modifica_date_factura(<>,
- <>,
- <>,
- <>,
- <>,
- to_date('<>','YYYYMMDDHH24:MI:SS'),
- <>,
- <>,
- ?poRec.text_aditional,
- ?poRec.tip_saft,
- ?poRec.efactura,
- ?poRec.data_act,
- ?poRec.data_scad,
- ?poRec.numar_act,
- ?poRec.serie_act);
- end;
-```
-
-Toate argumentele vin din structura `poRec`, populata printr-un `Scatter Name poRec Memo` din
-cursorul `crsfacturi` la intrarea in `do_modifica` (`:4538-4581`), apoi editata prin
-`frm_modifica_factura` cat timp e afisat (`:4588-4590`), inainte de executia `SCAN`-ului.
-
-Observatie de comportament: cand sunt alese mai multe inregistrari (`lnNrInreg > 1`), ramura
-`Otherwise` (`:4565-4580`) face `Scatter Name poRec Memo Blank` si reseteaza explicit
-`id_ruta`, `id_delegat`, `id_agent`, `id_masina`, `dataora_exp`, `id_facturare`,
-`listare_detaliata`, `tip_saft`, `text_aditional`, `efactura` la valori goale/`NULL`/`0` —
-campurile `data_act`/`data_scad`/`numar_act`/`serie_act` raman goale prin acelasi `NVL`. Daca
-formularul nu le modifica explicit, `SCAN`-ul trimite aceste valori goale la **fiecare** inregistrare
-aleasa (parametrii 2-11 se scriu neconditionat in corpul procedurii — vezi tabelul de mai sus).
-
-## 4. Mapare parametru -> control -> fereastra
-
-| Parametru | Control | Fereastra | Observatii |
-|---|---|---|---|
-| `V_ID_VANZARE` | — | — | Nu are control; e identitatea randului din `crsfacturi` (`poRec.id_vanzare`) |
-| `V_ID_RUTA` | `Ct_clb_ruta` (`ControlSource` prin `cprocedura=thisform.do_cauta_ruta`, seteaza `poRec.id_ruta`) | `frm_modifica_factura` (`:5510-5526`, cautare `:5695-5721`) | |
-| `V_ID_DELEGAT` | `Ct_clb_delegat` (`do_cauta_delegat` seteaza `poRec.id_delegat`) | `frm_modifica_factura` (`:5473-5489`, cautare `:5654-5678`) | |
-| `V_ID_AGENT` | `Ct_clb_agent` (`do_cauta_agent` seteaza `poRec.id_agent`) | `frm_modifica_factura` (`:5455-5471`, cautare `:5639-5652`) | |
-| `V_ID_MASINA` | `Ct_clb_masina` (`do_cauta_masina` seteaza `poRec.id_masina`) | `frm_modifica_factura` (`:5491-5508`, cautare `:5680-5693`) | |
-| `V_DATAORA_EXP` | `Clb_dataora_exp.Text_simplu1` (`ControlSource="poRec.dataora_exp"`) | `frm_modifica_factura` (`:5437-5453`) | validat obligatoriu in `inainte_de_do_termin` (`:5723-5734`) |
-| `V_ID_FACTURARE` | `clb_adresa_facturare` (`do_cauta_adresa` seteaza `poRec.id_facturare` + `poRec.adresa_facturare`) | `frm_modifica_factura` (`:5418-5435`, cautare `:5621-5637`) | |
-| `V_LISTARE_DETALIATA` | `chkDetaliat` (`ControlSource="poRec.listare_detaliata"`) | `frm_modifica_factura` (`:5379-5390`) | |
-| `V_TEXT_ADITIONAL` | `Ed_tx_simplu1._EDBASE1` (`ControlSource="poRec.text_aditional"`, `MaxLength=1000`) | `frm_modifica_factura` (`:5528-5551`) | comentariul VFP la `:4575` spune "MAXIM 250 CARACTERE", dar `MaxLength` control e 1000 — contradictie neverificata mai departe |
-| `V_TIP_SAFT` | `cboTipFactura` (`ControlSource="poRec.tip_saft"`, `RowSource` din `saft_tip_facturi`) | `frm_modifica_factura` (`:5335-5351`) | `Visible = m.gl406` (`:5739-5741`), deci controlul e ascuns cand `gl406` e fals (`gl406` definit in `COMUN\programe\oinit_optiuni.prg:524`) |
-| `V_EFACTURA` | **niciun control** | — | `poRec.efactura` vine doar din `Scatter` initial pe `crsfacturi` (cazurile `lnNrInreg=0/1`, `:4538-4564`) sau e fortat `0` la selectie multipla (`:4576`); formularul `frm_modifica_factura` nu are niciun obiect legat de `poRec.efactura` — nu poate fi schimbat de utilizator din acest formular azi |
-| `V_DATA_ACT` | `txtDataAct` (`ControlSource="poRec.data_act"`) | `frm_modifica_factura` (`:5572-5581`) | vezi blocaj la punctul 5 |
-| `V_DATA_SCAD` | `txtDataScad` (`ControlSource="poRec.data_scad"`) | `frm_modifica_factura` (`:5583-5592`) | vezi blocaj la punctul 5 |
-| `V_NUMAR_ACT` | `txtNrAct` (`ControlSource="poRec.numar_act"`) | `frm_modifica_factura` (`:5594-5603`) | vezi blocaj la punctul 5 |
-| `V_SERIE_ACT` | `txtSerieAct` (`ControlSource="poRec.serie_act"`) | `frm_modifica_factura` (`:5605-5614`) | vezi blocaj la punctul 5 |
-
-Nu exista niciun parametru mapat pe `frm_alte_date` (`COMUN\clase\ferestre_cere_date.vc2:2219`) —
-clasa aceea nu e implicata deloc in fluxul `do_modifica`/`modifica_date_factura`.
-
-## 5. Parametri blocati/needitabili azi in `frm_modifica_factura`
-
-Patru checkbox-uri controleaza accesul la seria/numarul/datele actului, si patru textbox-uri asociate:
-
-- `chkSerieAct`, `chkNrAct`, `chkDataAct`, `chkDataScad`: definite cu `Enabled = .F.`
- (`:5405-5416`, `:5392-5403`, `:5353-5364`, `:5366-5377`). Devin `Enabled` doar in `PROCEDURE Init`
- (`:5743-5746`):
- ```
- 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 doar daca factura are deja un numar de act completat (`poRec.numar_act` nenul) la
- deschiderea formularului. Pe o factura fara act (proforma/nefinalizata), toate patru raman
- needitabile.
-- `txtSerieAct`, `txtNrAct`, `txtDataAct`, `txtDataScad`: definite cu `Enabled = .F.`
- (`:5605-5614`, `:5594-5603`, `:5572-5581`, `:5583-5592`) si se activeaza doar din evenimentul
- checkbox-ului corespunzator — `chkSerieAct.Valid` (`:5770-5772`), `chkNrAct.Valid`
- (`:5766-5768`), `chkDataAct.Valid` (`:5758-5760`), `chkDataScad.Click` (`:5762-5764`) — deci
- necesita ca checkbox-ul insusi sa fie deja `Enabled` (conditia de mai sus).
-- `V_EFACTURA`: fara control — needitabil in acest formular indiferent de stare (punctul 4).
-- `V_ID_VANZARE`: nu e un camp de editat, e identitatea randului.
-
-Toti ceilalti parametri (`id_ruta`, `id_delegat`, `id_agent`, `id_masina`, `dataora_exp`,
-`id_facturare`, `listare_detaliata`, `text_aditional`, `tip_saft`) au controale mereu `Enabled`
-(fara restrictie in cod), `tip_saft` fiind conditionat doar de vizibilitate (`gl406`), nu de
-`Enabled`.
diff --git a/docs/cercetare/nota_contabila_fara_politica.md b/docs/cercetare/nota_contabila_fara_politica.md
deleted file mode 100644
index bd68816..0000000
--- a/docs/cercetare/nota_contabila_fara_politica.md
+++ /dev/null
@@ -1,224 +0,0 @@
-# Nota contabila pentru articol fara politica de pret (proiect #13)
-
-Cercetare pe cod, fara modificari. Continua raportul anterior
-`cont_venit_corespondente.md` (SCC vine prin lantul
-`CRM_POLITICI_PRET_ART -> CRM_POLITICI_PRETURI.ID_NOTA -> CRM_NOTE_VANZARI.ID_SET -> NOTE_CONTABILE`,
-citit de `cursor_articol` din `pack_facturare.contabilizeaza_articol`).
-
-Sursa: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql`
-(pachet `pack_facturare`, 17020 linii) si `D:\ROA\ROAAUTO\Programe\oproceduri_devize.prg` +
-`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_31_02_AUTO_PACK_AUTO.sql` (pachet `pack_auto`).
-
----
-
-## 1. Ce face `contabilizeaza_articol` cand `id_pol` e NULL/0
-
-Raspuns: **ridica exceptia FACT-024 si intreruce functia, inainte sa ajunga la cursorul care
-citeste SCC**. Nu exista o ramura de default si nu se scrie nota cu SCC NULL pentru acest caz.
-
-Corpul complet e la `ff_...:7182-7556`. Primul lucru pe care il face (inainte de `cursor_articol`,
-inainte de orice `scrie_nota`) e:
-
-```
-ff_...:7286-7311
-BEGIN
- SELECT COMPUS, ID_POL_ART
- INTO V_COMPUS, V_ID_POL_ART
- FROM VCRM_POLITICI_PRET_ART
- WHERE ID_ARTICOL = detalii_articol.id_articol
- AND ID_POL = detalii_articol.id_pol;
-EXCEPTION
- WHEN NO_DATA_FOUND THEN
- SELECT DENUMIRE INTO lcArticol FROM NOM_ARTICOLE WHERE id_articol = detalii_articol.id_articol;
- SELECT NUME_LISTA_PRETURI INTO lcPolitica FROM CRM_POLITICI_PRETURI WHERE id_pol = detalii_articol.id_pol;
- RAISE_APPLICATION_ERROR(-20000,
- 'Articolul ' || detalii_articol.id_articol || '|' || lcArticol ||
- ' nu este definit in politica de preturi ' ||
- detalii_articol.id_pol || '|' || lcPolitica || '! (FACT-024)');
-END;
-```
-
-`ID_POL = detalii_articol.id_pol` cu `id_pol` NULL nu poate potrivi niciun rand in SQL standard
-(`X = NULL` e necunoscut, nu adevarat) — deci pentru `id_pol` NULL sau 0 (presupunand ca nu exista
-o politica cu `ID_POL = 0`), `SELECT INTO` intra mereu pe `NO_DATA_FOUND`.
-
-**Observatie suplimentara, neceruta explicit dar relevanta**: in ramura de exceptie, al doilea
-`SELECT ... INTO lcPolitica FROM CRM_POLITICI_PRETURI WHERE id_pol = detalii_articol.id_pol` sufera
-de aceeasi problema — cu `id_pol` NULL, si acest `SELECT INTO` da tot `NO_DATA_FOUND`, care **nu e
-tratat** in acest bloc (nu exista un al doilea handler). Deci mesajul FACT-024 "curat" (cu numele
-politicii) nu s-ar afisa niciodata pentru cazul `id_pol IS NULL` — s-ar propaga o exceptie
-`NO_DATA_FOUND` neprinsa din interiorul handler-ului, cu alt mesaj Oracle generic, nu FACT-024 cu
-text. Codul articolului (`lcArticol`) apuca sa fie rezolvat inaintea acestui eșec, deci
-identificarea articolului nu s-ar pierde in log/eroare, dar textul final ar fi ORA-01403, nu
-mesajul FACT-024 formatat. Pentru `id_pol = 0` (nu NULL), daca exista vreo politica cu id 0, acel
-`SELECT` ar reusi si mesajul FACT-024 ar iesi corect.
-
-Cursorul `cursor_articol` (care citeste SCD/ASCD/SCC/ASCC din `NOTE_CONTABILE` prin lant) **nu se
-mai deschide** — funcția a ridicat deja exceptia mai sus. Deci intrebarea "cursorul intoarce zero
-randuri, ce face codul mai departe" nu se pune in acest caz: nu ajunge acolo.
-
-Concluzie Q1: **orice linie de vanzare cu `id_pol` NULL/0 trimisa la `contabilizeaza_articol` in
-starea actuala a codului arunca o eroare si opreste tranzactia** (nu scrie nota cu cont NULL, nu
-pune default). Cerinta proiectului #13 ("articol din nomenclator fara politica de pret, pret
-tastat manual, pe orice tip de document") ar lovi FACT-024 (sau exceptia neprinsa descrisa mai sus)
-daca linia respectiva e trecuta prin acest cod neschimbat.
-
----
-
-## 2. Validare la `scrie_nota` pentru cont NULL
-
-Raspuns: **nu exista**. Corpul complet e la `ff_...:12338-12570`.
-
-- Singura verificare care ar fi atins asta e comentata:
- ```
- ff_...:12441-12453
- /* IF V_SUMA IS NULL THEN
- RAISE_APPLICATION_ERROR(...) ...
- END IF;*/
- ```
- Si oricum verifica `V_SUMA` (suma calculata), nu `V_SCD`/`V_SCC`.
-- `INSERT INTO ACT_TEMP (... SCD, ASCD, SCC, ASCC ...)` (`ff_...:12458-12544`) insereaza direct
- `V_SCD`/`V_ASCD`/`V_SCC`/`V_ASCC` primite ca parametri, fara niciun `NVL`/`CASE`/verificare de
- NULL pe ele.
-- Nu exista `NOT NULL` verificat in cod pentru aceste coloane in acest fisier (constrangerea ar fi
- la nivel de DDL al tabelei `ACT`/`ACT_TEMP`, care nu face parte din pachetul PL/SQL cercetat —
- vezi sectiunea Neverificat).
-
-Deci daca cineva ar ocoli blocul de la punctul 1 (de ex. printr-un `id_pol` care *exista* in
-`CRM_POLITICI_PRET_ART` dar al carui lant `CRM_POLITICI_PRETURI -> CRM_NOTE_VANZARI -> NOTE_CONTABILE`
-e incomplet, asa incat `D.SCC` iese NULL din LEFT JOIN), `scrie_nota` ar scrie nota cu `SCC = NULL`
-fara sa protesteze. Asta e insa un scenariu diferit de "fara politica de pret" (aici politica exista,
-dar lantul de sub ea e incomplet) — nu e cazul cerut de proiectul #13 asa cum a fost formulat.
-
----
-
-## 3. Toti apelantii lui `contabilizeaza_articol` in fisier
-
-Cautare exhaustiva `Grep 'contabilizeaza_articol'` pe tot fisierul: 3 apeluri (in afara de propria
-definitie si un comentariu):
-
-| Linie | Procedura apelanta | Domeniu / flux |
-|---|---|---|
-| `ff_...:6150` | `scrie_factura2` (corp `ff_...:6029-6272`) | **Fluxul principal de scriere** — pentru orice document ale carui randuri nu cad in ramurile speciale ale `CASE`-ului de la `ff_...:6081-6151`: transfer intre subunitati (`ntip IN (23,25,30,41)`), factura/aviz custodie (`ntip IN (42,47)`), rata cu `id_rata<>0` (`ntip IN (2,6,52)`). Toate celelalte tipuri — **factura normala** (`ntip<=20`), hotel, restaurant, nota de plata, vanzare retail, tipurile 48/49/51/52, aviz simplu, aviz catre clienti debitori, si **aviz retur (tip 24)** cand e scris prin `scrie_factura2` — ajung la `contabilizeaza_articol` aici. Aceasta e apelarea "de baza" pe care se sprijina interpretarea corpului functiei facuta la punctul 1 (ramurile `CASE` din interiorul `contabilizeaza_articol`, `ff_...:7407-7432`, mapeaza direct pe tipurile de document tratate de acest apelant). |
-| `ff_...:6867` | `scrie_factura_avize_retur` (corp `ff_...:6273-6666`) | Flux **factura scrisa pe baza de avize + retur simultan**. Apelul e in interiorul buclei pe `articole_aviz` (`ff_...:6841-6960` zona), pentru randurile cu `custodie = 1` (marfa in custodie ce se descarca din avize). |
-| `ff_...:7149` | `scrie_aviz_retur` (corp `ff_...:7094-7180`) | Procedura dedicata **aviz retur** (`V_ID_DELEGAT, V_ID_MASINA, ...`). Apelul e in ramura `ELSE` a testului `pack_facturare.nfactavizcust = 1` (`ff_...:7124-7150`) — deci pentru randurile care **nu** sunt in custodie. |
-
-Concluzie Q3: **da**, `contabilizeaza_articol` e apelata pe fluxul principal de facturare
-(`scrie_factura2`, care acopera factura normala si majoritatea celorlalte tipuri de document), nu
-doar din `scrie_aviz_retur`. Raportul anterior lasase asta neverificat; e confirmat aici cu cele 3
-puncte de apel gasite si citate mai sus — nu exista un al 4-lea apel in fisier.
-
----
-
-## 4. Precedentul ROAAUTO "Alte servicii" — **nu e de fapt un precedent pentru cazul cerut**
-
-Asta contrazice premisa din cerere. Firul (`crsalteserv -> crsvanztemp -> adauga_articol_factura_deviz`)
-duce spre un flux care **ocoleste complet `contabilizeaza_articol`**, deci nu demonstreaza ce se
-intampla in `pack_facturare` pentru un articol fara politica — demonstreaza doar ca exista un *alt*
-mecanism de contabilizare, in afara pachetului `pack_facturare`.
-
-Pasii, cu citate:
-
-1. **`crsalteserv -> crsvanztemp`** (`D:\ROA\ROAAUTO\Programe\oproceduri_devize.prg:1040-1041`):
- ```
- Insert Into (lcCursorDeviz)(id_articol,denumire,explicatie,cantitate,um,id_jtva_coloana,proc_Tvav,taxcode,pret,discount_unitar) ;
- Select id_articol,denumire,"",cantitate,um,CAST(lnIdJTvaColoana as N(6) null) as id_jtva_coloana,CAST(lnProcTvav as N(7,2) null) as proc_tvav,CAST(lnTaxCode as N(6) null) as taxcode,pretftva,0 From crsalteserv Where !Deleted()
- ```
- Nu exista coloana `id_pol` in `crsalteserv`, in `lcCursorDeviz`, sau in cursorul `crsvanztemp`
- creat la `oproceduri_devize.prg:1190-1192` (schema explicita a cursorului nu include `id_pol`).
-
-2. **`crsvanztemp -> adauga_articol_factura_deviz`** (`oproceduri_devize.prg:1240-1257`): apelul RPC
- trimite `id_articol, explicatie, serie, pret_achizitie, pretd, id_valuta_d, pret, id_valuta,
- curs, multiplicator, proc_tvav, id_jtva_coloana, cantitate, discount_unitar, id_gestiune, cont,
- pret_cu_tva, NULL, NULL, taxcode` — **fara `id_pol`**, pentru ca procedura insasi nu are un
- parametru `id_pol`.
-
-3. **Semnatura `adauga_articol_factura_deviz`** (spec `ff_...:468-488`, corp `ff_...:4675-4745`):
- nu exista `V_ID_POL IN NUMBER` printre parametri. `INSERT INTO VANZARI_DETALII_TEMP` la
- `ff_...:4697-4744` **nu include coloana `ID_POL`** in lista de coloane inserate — deci
- `ID_POL` ramane pe valoarea implicita a coloanei (probabil NULL; DDL-ul tabelei nu face parte
- din pachetul cercetat, vezi Neverificat). **Asta confirma partea (a) a intrebarii: da, liniile
- "alte servicii" ajung cu `id_pol` gol** in `VANZARI_DETALII_TEMP`.
-
-4. **Dar acele randuri nu trec niciodata prin `contabilizeaza_articol`.** Apelantul din
- `oproceduri_devize.prg` nu cheama `scrie_factura2` / `scrie_factura_avize` / `scrie_aviz_retur`
- (singurele proceduri care cheama `contabilizeaza_articol`, vezi punctul 3). In schimb cheama, in
- ordine (`oproceduri_devize.prg:1211-1310`):
- - `pack_facturare.initializeaza_date_factura(...)`
- - bucla `pack_facturare.adauga_articol_factura_deviz(...)` (doar insert in `VANZARI_DETALII_TEMP`)
- - opțional `pack_facturare.scrie_incasari(...)` (incasare, nu venit din vanzare)
- - `pack_facturare.scrie_in_vanzari(0, ...)` (`ff_...:13497-13962`)
- - `pack_auto.actualizeaza_deviz(...)` (`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_31_02_AUTO_PACK_AUTO.sql:692-733`)
-
- **`scrie_in_vanzari` nu scrie nici o nota contabila de venit.** Corpul complet
- (`ff_...:13497-13962`) face: `INSERT INTO VANZARI` (antetul documentului), `scrie_cursuri`,
- `scrie_seturi`, apoi
- ```
- ff_...:13714-13766
- INSERT /*+ APPEND */ INTO VANZARI_DETALII (..., ID_POL, ...)
- SELECT ..., ID_POL, ... FROM VANZARI_DETALII_TEMP;
- ```
- (copiaza `ID_POL` — care e NULL pentru aceste randuri — direct in `VANZARI_DETALII`, fara nicio
- validare), si la final actualizeaza totalurile cache pe `VANZARI`. **Nu apare niciun apel catre
- `contabilizeaza_articol`, `scrie_nota`, `cumuleaza_note_act` sau `finalizeaza_factura` in acest
- corp** (verificat citind procedura cap-coada).
-
- `pack_auto.actualizeaza_deviz` (`ff_2026_03_31_02_AUTO_PACK_AUTO.sql:692-733`) face doar:
- ```
- SELECT MAX(ID_FACT) INTO lnIdFact FROM ACT WHERE COD = pack_contafin.get_cod() AND SCD NOT LIKE '5%';
- UPDATE DEV_ORDL SET PROC_TVAV = ... WHERE ID_ORDL IN (...);
- UPDATE RUL SET ID_FACT = lnIdFact WHERE ...;
- UPDATE NOM_LUCRARI SET ID_FACT = lnIdFact WHERE ... (doar pt anumite id_set);
- ```
- Adica **presupune ca exista deja un rand in `ACT`** (nu `ACT_TEMP`) cu `SCD NOT LIKE '5%'` pentru
- codul documentului curent, si doar propaga `ID_FACT` gasit acolo spre `DEV_ORDL`/`RUL`/`NOM_LUCRARI`.
- Nu insereaza el insusi in `ACT` sau `NOTE_CONTABILE`, si nu contine nicio referinta la `SCC`,
- `NOTE_CONTABILE` sau `CRM_POLITICI*` (cautat explicit, zero rezultate in acest fisier).
-
-**Concluzie Q4, corectand premisa din cerere**: liniile "Alte servicii" chiar ajung cu `id_pol` gol
-(confirmat), dar **nu demonstreaza ca `contabilizeaza_articol` tolereaza `id_pol` gol** — pentru ca
-nu trec niciodata prin el. Ele demonstreaza doar ca exista deja, pentru fluxul deviz ROAAUTO, o cale
-de facturare paralela (`scrie_in_vanzari` + `pack_auto.actualizeaza_deviz`) care **nu genereaza deloc
-nota contabila de venit prin `pack_facturare`**. Daca acele randuri capata totusi un cont de venit in
-`ACT`/`NOTE_CONTABILE` in productie, mecanismul nu e vizibil in codul cercetat (posibil un
-trigger pe tabel, un job batch, sau o scriere manuala/alt modul neexaminat — vezi Neverificat).
-**Nu se poate folosi acest precedent ca raspuns de fapt la intrebarea 1.**
-
----
-
-## 5. Vreun mecanism care sa foloseasca `NOM_ARTICOLE.CONT` drept cont de venit
-
-Raspuns: **NU**, in `pack_facturare`.
-
-Cautat explicit `Grep -i 'NOM_ARTICOLE\.CONT'` pe intregul fisier
-`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql` (17020 linii) — **zero potriviri**. Singurele utilizari
-ale `NOM_ARTICOLE` gasite in `contabilizeaza_articol` insusi sunt pentru `DENUMIRE` (mesajul de
-eroare FACT-024, `ff_...:7295-7298`), nu pentru `CONT`.
-
-`crs_rand_articol.scc` (folosit ca `V_SCC` la `ff_...:7434`) vine exclusiv din
-`D.SCC` din join-ul `CRM_POLITICI_PRET_ART -> CRM_POLITICI_PRETURI -> CRM_NOTE_VANZARI -> NOTE_CONTABILE`
-(`ff_...:7261, 7275-7276`) — nu exista ramura alternativa care sa substituie `NOM_ARTICOLE.CONT`
-cand politica lipseste. (Raportul anterior confirmase deja separat ca `NOM_ARTICOLE.CONT` e folosit
-doar ca **cont de gestiune**, transmis catre `descarca_gestiune`, `ff_...:7499`.)
-
----
-
-## Neverificat
-
-- **Continutul efectiv al `NOTE_CONTABILE`/`CRM_POLITICI_PRET_ART`** (daca exista politici cu
- `ID_POL = 0`, ce SCC au liniile din productie pentru documente "alte servicii" existente) —
- necesita interogare pe baza de date, nu doar cod.
-- **Constrangerile DDL** ale `VANZARI_DETALII_TEMP.ID_POL` si `ACT_TEMP.SCC`/`ACT.SCC` (NOT NULL?
- default?) — scripturile DDL ale acestor tabele nu au fost cautate/citite in aceasta cercetare
- (am cautat doar in pachetele PL/SQL `ff_...COMUN_PACK_FACTURARE.sql` si `..._AUTO_PACK_AUTO.sql`).
-- **Cine scrie efectiv contul de venit (`ACT`/`NOTE_CONTABILE`) pentru documentele "alte servicii"
- din ROAAUTO**, daca se scrie deloc. `pack_auto.actualizeaza_deviz` presupune ca exista deja un
- rand `ACT` cu `SCD NOT LIKE '5%'` pentru codul documentului curent — sursa acelui rand nu a fost
- gasita in `oproceduri_devize.prg` sau in corpul `scrie_in_vanzari`/`actualizeaza_deviz` cercetate.
- Ar trebui cautat: alte proceduri `pack_auto` (fisierul `ff_2026_03_31_02_AUTO_PACK_AUTO.sql` are
- si alte proceduri necercetate aici), triggere pe `VANZARI`/`VANZARI_DETALII`/`ACT`, sau apeluri
- din alte forme VFP (`.scx`/`.vcx`) din ROAAUTO care preced acest apel RPC. Nu am cautat exhaustiv
- triggere in afara folderului `SCRIPTURI_CLAR\2026` (cautare limitata, zero rezultate acolo).
-- **Ce se intampla exact daca `id_pol = 0` si exista o politica reala cu `ID_POL = 0`** (caz
- teoretic, neexclus explicit din schema) — ar schimba concluzia de la "eroare neprinsa" la
- "FACT-024 cu mesaj complet", dar tot ramane o eroare, nu un default silentios.
diff --git a/docs/cercetare/optiune_firma_cont_debit.md b/docs/cercetare/optiune_firma_cont_debit.md
deleted file mode 100644
index c97cae8..0000000
--- a/docs/cercetare/optiune_firma_cont_debit.md
+++ /dev/null
@@ -1,373 +0,0 @@
-# Optiune de firma pentru contul de debit (`SCD`) pe ramura fara politica de pret (#13, decizia 36)
-
-Cercetare read-only, terminata. Continua `canal_cont_venit_fara_politica.md` (proiectarea
-parametrului de cont, sectiunea "Proiectarea parametrului de cont contabil", `:27-241`) si
-verificarea ei, `parametru_cont_contabilizeaza_articol.md`. Acolo, randul `SCD` din tabelul de
-sectiunea 3 propunea **`SCD` hardcodat `'4111'`**, marcat explicit "de confirmat cu Marius"
-(`canal_cont_venit_fara_politica.md:146`). **Decizia 36 (Marius, 10.08.2026): `SCD` vine dintr-o
-optiune de firma, cu `4111` ca implicit** — motivul fiind ca se poate schimba la client fara
-recompilare. Aici e proiectarea acelei optiuni. Decizia 31 se aplica: datele din baza de dev arata
-ce *exista*, nu ce e configurat la client — nu se generalizeaza pe numere, doar pe tipar/structura.
-
-Oracle interogat doar `SELECT`, schema `MARIUSM_AUTO`/`ROA_CENTRAL`. Niciun fisier de cod atins.
-
----
-
-## 0. Rezumat, in cinci randuri
-
-Mecanismul de optiuni de firma **exista deja de 15+ ani** (`PACK_SESIUNE.getoptiunefirma`, tabelul
-`OPTIUNI`, 458 randuri azi) si are **exact tiparul cerut deja in productie, in acelasi pachet**:
-`pack_facturare.scrie_incasare2` seteaza `V_SCD` dintr-o optiune (`RF_CONT_INCASARE_BONFISCAL` etc.,
-cate una per tip de incasare), cu fallback pe un cont hardcodat daca optiunea lipseste — **acelasi
-camp (`SCD`), acelasi pachet, aceeasi sursa Oracle** (`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`,
-liniile 13191-13233, tratate integral in sectiunea 2). Ecranul de editare (`frm_optiuni`/
-`frm_optiuni_nou`, `COMUN\clase\oOptiuni.vc2`) e **complet generic** peste tabelul `OPTIUNI` —
-adaugarea cheii noi **nu cere niciun cod VFP nou** in ecranul de optiuni, doar randul in tabel.
-Propunerea (sectiunea 3): cheia noua `FACT_SCD_ARTFPRET` (sau numele ales de Marius), instalata cu
-valoare implicita `'4111'` chiar in randul din `OPTIUNI` (tiparul deja folosit de toate exemplele
-gasite), **plus** fallback hardcodat `'4111'` in cod langa `getoptiunefirma`, in oglinda exacta a
-tiparului `scrie_incasare2` — dubla plasa de siguranta (instalare veche fara randul din `OPTIUNI`
-**si** rand editat gresit/gol raman amandoua acoperite).
-
----
-
-## 1. Cum functioneaza mecanismul de optiuni de firma, azi
-
-### 1.1 Stocare — tabelul `OPTIUNI`
-
-Interogat direct (`ALL_TAB_COLUMNS`, schema curenta), 458 randuri azi:
-
-| Coloana | Tip | Null | Rol |
-|---|---|---|---|
-| `ID_OPTIUNI` | `NUMBER` | N | cheie surogat, PK implicita |
-| `VARNAME` | `VARCHAR2(30)` | Y | cheia optiunii — cautata `UPPER(TRIM(...))`, deci case-insensitive in practica |
-| `VARTYPE` | `VARCHAR2(10)` | Y | eticheta de tip pentru randare/parsare in VFP: `CHARACTER`/`NUMERIC`/`CURRENCY`/`DATE`/`DATETIME`/`LOGICAL` — **descriptiva, nu impusa de Oracle**; distinct azi: `CHARACTER` 156, `NUMERIC` 288, `LOGICAL` 11, `DATE` 3 |
-| `VARVALUE` | `VARCHAR2(1000)` | Y | valoarea, **mereu text**, indiferent de `VARTYPE` |
-| `VARVALUE2` | `CLOB` | Y | valoare alternativa, folosita de un mecanism separat (`citeste_optiune(tcOptiune, tlValue2)`, `oinit_optiuni.prg:802-823`) — irelevant aici |
-| `VARDESC` | `VARCHAR2(100)` | Y | descriere afisata in ecran |
-| `PROGRAM` | `VARCHAR2(30)` | Y | produsul care a creat optiunea (metadata) |
-| `PROGRAME` | `VARCHAR2(1000)` | Y | lista CSV de produse pentru care optiunea e vizibila/relevanta (folosita la filtrare in incarcarea globala VFP, sectiunea 1.4) |
-| `ID_PRG_OWNER` | `NUMBER` | Y | neexaminat mai departe, neрелevant aici |
-
-**Fara `ID_FIRMA`.** Motivul: fiecare firma are **schema Oracle proprie** — tabelul `OPTIUNI` din
-schema curenta de conexiune **este** deja "optiunile firmei curente"; nu exista randare
-multi-firma in acelasi tabel. Confirmat si de codul VFP: `frm_optiuni.cschema` e setat la
-constanta de compilare `CONTAFIN_ORACLE` (`oOptiuni.vc2:1089`, acelasi simbol folosit peste tot in
-COMUN pentru "schema firmei curente"), iar `getoptiunefirma(tcS, tcOptiune)` **primeste** un
-parametru de schema (`tcS`, azi mereu `USER`) dar **nu il foloseste in interogare** — `select
-varvalue from optiuni` fara calificare de schema (cod exact la sectiunea 1.2) — pentru ca sesiunea
-Oracle e deja conectata direct in schema firmei. `tcS` ramane doar din compatibilitate istorica cu
-supraincarcarea `getOptiuneFirma(tcOptiune)` (fara schema), care apeleaza pe cea cu doi parametri
-cu `user` (sectiunea 1.2).
-
-### 1.2 Semnatura si contract — `PACK_SESIUNE.getoptiunefirma`
-
-Sursa curenta confirmata prin `ALL_SOURCE` pe pachetul live (`PACK_SESIUNE`, tip `PACKAGE BODY`) —
-identica, verificat, cu ultima versiune gasita in `SCRIPTURI_CLAR`
-(`2014/04/ff_2014_04_24_01_COMUN_PACK_SESIUNE.sql:328-350`; nicio modificare de atunci, cautare
-`FUNCTION getoptiunefirma` in `SCRIPTURI_CLAR/2024`, `/2025`, `/2026` — zero rezultate):
-
-```sql
-FUNCTION getoptiunefirma(tcS IN VARCHAR2, tcOptiune IN VARCHAR2)
- RETURN VARCHAR2 IS
- lcValue Optiuni.Varvalue%Type := '';
-BEGIN
- BEGIN
- select varvalue
- INTO lcValue
- from optiuni
- where UPPER(TRIM(VARNAME)) = UPPER(TRIM(tcOptiune));
- EXCEPTION
- WHEN OTHERS THEN
- lcValue := '';
- END;
- RETURN lcValue;
-END;
-
-FUNCTION getOptiuneFirma(tcOptiune IN VARCHAR2) RETURN VARCHAR2 IS
- lcValue Optiuni.Varvalue%Type := '';
-BEGIN
- lcValue := getOptiuneFirma(user, tcOptiune);
- return lcValue;
-END;
-```
-
-Contract, verificat pe `RETURN`, nu dedus din nume:
-
-- **Parametru**: numele optiunii (`tcOptiune`), cautat `UPPER(TRIM(...))` — insensibil la caz si la
- spatii; a doua forma (`getOptiuneFirma(tcOptiune)`, un singur parametru) e cea folosita azi peste
- tot in `pack_facturare` (vezi sectiunea 2) — deleaga la forma cu doi parametri cu `user`.
-- **Cand optiunea NU exista** (`NO_DATA_FOUND`, prins de `WHEN OTHERS` generic): **`RETURN ''`**
- (string gol), **niciodata `NULL` explicit si niciodata exceptie propagata**. Insa in Oracle un
- `VARCHAR2` egal cu `''` **este** `NULL` la nivel de reprezentare (Oracle nu distinge stringul gol
- de `NULL`) — deci orice apelant care testeaza `IF V_X IS NULL THEN` dupa un apel la
- `getoptiunefirma` **prinde si cazul "optiune inexistenta"**, fara cod suplimentar. Acesta e
- exact tiparul folosit de toti apelantii gasiti (sectiunea 2).
-- **`WHEN OTHERS THEN lcValue := ''`** inghite **orice** eroare, nu doar `NO_DATA_FOUND` (de ex. si
- `TOO_MANY_ROWS` daca ar exista vreodata doua randuri cu acelasi `VARNAME` — nu exista constrangere
- `UNIQUE` pe `VARNAME`, doar convenția aplicatiei). Nu e un risc nou introdus de propunerea de
- fata — e comportamentul mecanismului de 15+ ani, pastrat ca atare.
-- **Variante**: **o singura functie**, intotdeauna `VARCHAR2`. **Nu exista** `getoptiunefirma`
- numerica/booleana separata in Oracle — conversia se face **la apelant**, in PL/SQL cu
- `TO_NUMBER(NVL(...))` (exemplu confirmat, acelasi fisier, `scrie_incasare2`,
- `ff_...:13177`: `TO_NUMBER(NVL(pack_sesiune.getoptiunefirma('D406'), '0'))`) sau in VFP cu
- `VAL()`/`CTOD()`/etc., pe baza coloanei `VARTYPE` (vezi `oinit_optiuni.prg:179-211`, functia
- `actualizeaza_optiuni_program`, care materializeaza fiecare optiune intr-o variabila globala VFP
- cu prefix dupa tip: `gc` pentru `CHARACTER`, `gn` pentru `NUMERIC`,
- `gl` pentru `LOGICAL` etc.). **Pentru un cont contabil (`VARCHAR2(4)`), varianta corecta e
- cea de baza, `VARTYPE='CHARACTER'`** — exact tipul folosit de toate exemplele cu cont din
- sectiunea 2, fara nicio conversie necesara la citire in PL/SQL (`V_SCD` e deja `VARCHAR2`).
-
-### 1.3 Ecranul de editare — complet generic peste tabel
-
-`COMUN\clase\oOptiuni.vc2`, doua clase relevante:
-
-- **`frm_optiuni`** (`:1064-1314`) — grid pe view-ul VFP local `v_optiuni` (populat dintr-un
- `SELECT * FROM .optiuni`, vezi `oinit_optiuni.prg:337` in `viz_optiuni`), 4 coloane
- (`varname`, `vartype`, `varvalue`, `vardesc`), cu cautare doar dupa `varname LIKE`
- (`do_cauta`, `:1261-1278`) si butoane Adauga/Modifica/Sterge care deschid `frm_optiuni_nou`.
-- **`frm_optiuni_nou`** (`:1316-1462`) — formular Adauga/Modifica cu 4 campuri: `varname` (text,
- `Format="!K"` = uppercase), `vartype` (combobox cu lista fixa `CHARACTER,CURRENCY,NUMERIC,
- DATETIME,DATE,LOGICAL`), `varvalue` (text), `vardesc` (text). Validare la salvare
- (`inainte_de_do_termin`, `:1417-1450`): **doar "nu e gol"** pe `varname`, `vartype`, `varvalue` —
- **nicio validare de format sau de continut** (nu verifica lungime, nu verifica daca `varvalue`
- e un cont existent in planul de conturi, nimic specific per optiune).
-- **`cus_odata_optiuni`** (`:139-206`) — clasa de persistenta: `INSERT`/`UPDATE`/`DELETE` generic pe
- `optiuni (varname, vartype, varvalue, vardesc)` — confirma ca **orice cheie noua** functioneaza
- fara nicio schimbare la acest cod; scrie exact cele 4 coloane editabile din ecran.
-
-**Concluzie la intrebarea "adaugarea unei optiuni noi cere cod nou in ecran": NU.** Ecranul e
-generic peste tabel dupa cele 4 coloane editabile. Randul nou (`FACT_SCD_ARTFPRET`, sectiunea 3)
-apare automat in grid dupa ce e inserat, si e editabil din prima fara nicio modificare VFP.
-
-*Nota conexa, nu necesara pentru mecanismul Oracle*: la fiecare pornire de sesiune, VFP
-materializeaza **toate** randurile din `OPTIUNI` in variabile globale (`optiuni_firma`,
-`oinit_optiuni.prg:234-310`), filtrate `Isnull(programe) Or gcNumeProgram $ programe` — deci coloana
-`PROGRAME` conteaza doar pentru **vizibilitatea in acest mecanism global VFP**, nu pentru
-`getoptiunefirma` (care nu se uita deloc la `PROGRAME`). Optiunea noua nu are nevoie de acest canal
-VFP (Oracle o citeste direct), dar completarea corecta a `PROGRAME` evita zgomot/confuzie daca
-cineva se uita in `frm_optiuni` din ROAFACTURARE si se asteapta sa vada optiunea listata acolo cu
-`gcNumeProgram = 'ROAFACTURARE'` in `PROGRAME`.
-
----
-
-## 2. Exemple reale de optiuni existente, cu lantul complet
-
-### 2a. `RF_CONT_INCASARE_*` — exact tiparul cerut, in acelasi pachet, pe acelasi camp `SCD`
-
-**Cel mai relevant exemplu posibil**: patru optiuni care alimenteaza direct `SCD` pe o nota
-contabila, in `pack_facturare.scrie_incasare2` — **aceeasi functie Oracle pe care propunerea de la
-`canal_cont_venit_fara_politica.md` o modifica** (acelasi fisier,
-`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`).
-
-**Randul din tabel** (interogat direct, 4 randuri, VARTYPE `CHARACTER` la toate):
-
-| VARNAME | VARVALUE azi | VARDESC | PROGRAM | PROGRAME |
-|---|---|---|---|---|
-| `RF_CONT_INCASARE_BONFISCAL` | `5311` | `CONTUL DEBITOR PENTRU NOTA DE INCASARE 5311 = 4111` | `ROAFACTURARE` | `ROAFACTURARE,ROAACNPRO,ROACOMENZI,ROACONTRACTE,ROAGEST,ROARESTAURANT` |
-| `RF_CONT_INCASARE_CARDBANCAR` | `5125` | `CONTUL DEBITOR PENTRU NOTA DE INCASARE 5113 = 4111` | idem | idem |
-| `RF_CONT_INCASARE_TICHETE` | `5323` | `CONTUL DEBITOR PENTRU NOTA DE INCASARE 5323 = 4111` | idem | idem |
-| `RF_CONT_INCASARE_CHITANTA` | `5311` | `CONTUL DEBITOR PENTRU NOTA DE INCASARE 5311 = 4111` | idem | idem |
-
-(`VARDESC` mentioneaza si `= 4111` — nu e o eroare de copy-paste: e nota ca partea de credit a
-notei de incasare e contul de clienti `4111`, deci descrierea documenteaza ambele parti ale notei,
-nu doar valoarea implicita a optiunii.)
-
-**Insertia originala** (`SCRIPTURI_CLAR/2010/08/ff_2010_08_11_01_OPTIUNI.sql:9-19`), tiparul de
-migrare de urmat:
-
-```sql
-insert into optiuni (VARNAME, VARTYPE, PROGRAM, VARVALUE, VARDESC, ID_PRG_OWNER, PROGRAME)
-values ('RF_CONT_INCASARE_BONFISCAL', 'CHARACTER', 'ROAFACTURARE', '5311',
- 'CONTUL DEBITOR PENTRU NOTA DE INCASARE 5311 = 4111', null, 'ROAFACTURARE');
-```
-
-**Apelul din PL/SQL** (`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:13161-13234`,
-`PROCEDURE scrie_incasare2`), citit integral — **exact tiparul "optiune cu fallback hardcodat" cerut
-de decizia 36**:
-
-```sql
-V_SCD := V_PSCD; -- parametru explicit, daca a fost dat de apelant (ff_...:13185)
-CASE
- WHEN V_TIP = nTipIncasareBonFiscal THEN
- ...
- IF V_SCD IS NULL THEN
- V_SCD := PACK_SESIUNE.getoptiunefirma('RF_CONT_INCASARE_BONFISCAL');
- END IF;
- IF V_SCD IS NULL THEN
- V_SCD := '5311'; -- fallback hardcodat, instalare veche
- END IF;
- ...
-END CASE;
-```
-
-Trei niveluri, in ordine: **(1) parametru explicit daca a fost dat, (2) optiunea de firma, (3)
-constanta hardcodata** — folosita si daca randul din `OPTIUNI` lipseste complet (instalare veche,
-migrare neaplicata) *si* daca a fost sters/golit manual din ecran. Acest cont ajunge apoi direct in
-`INSERT INTO ACT_TEMP (..., SCD, ...)` (`ff_...:13241-13249` in continuare), **fara nicio validare
-suplimentara de format sau de existenta in planul de conturi** — nici in Oracle, nici in ecranul de
-optiuni (sectiunea 1.3), nici la `INSERT`.
-
-**Ecranul de editare**: acelasi `frm_optiuni`/`frm_optiuni_nou` generic (sectiunea 1.3) — niciun
-ecran dedicat pentru aceste 4 optiuni, se editeaza ca text simplu in grid.
-
-### 2b. `D406` — optiune numerica/booleana folosita ca flag, cu conversie explicita la citire
-
-`VARNAME='D406'`, `VARTYPE='NUMERIC'`, `VARVALUE='1'`, `PROGRAM='ROACONT'`,
-`PROGRAME='ROACONT,ROAAUTO,ROACONTRACTE,ROADEVIZE,ROAFACTURARE,...'`. Citita in acelasi
-`scrie_incasare2` (`ff_...:13177`): `lnD406 := TO_NUMBER(NVL(pack_sesiune.getoptiunefirma('D406'),
-'0'))` — **tipar de citire pentru optiune numerica**: `getoptiunefirma` intoarce mereu text,
-apelantul face `NVL(...,'0')` inainte de `TO_NUMBER` (aici fallback-ul `'0'` e in acelasi loc cu
-apelul, nu separat ca la `RF_CONT_INCASARE_*` — variatie minora de stil intre autori, nu o regula
-diferita).
-
-### 2c. `CONT411` si `DEVCONTALTELE` — optiuni "cont" mai vechi, azi orfane in cod
-
-`CONT411` (`VARTYPE='CHARACTER'`, `VARVALUE='4111'`, `VARDESC='411 SAU 4111'`, fara `PROGRAM`) si
-`DEVCONTALTELE` (`VARTYPE='CHARACTER'`, `VARVALUE='704'`, `VARDESC='CONT ALTE SERVICII FACTURA'`,
-`PROGRAM='ROAAUTO'`) — cautare `grep` pentru ambele in tot `SCRIPTURI_CLAR`: **niciun apelant activ
-gasit** (doar insertiile originale din 2011). Probabil cod dezafectat sau folosit doar din alt
-produs/raport neexaminat aici. Mentionate pentru completitudine si pentru ca `CONT411` confirma
-**exact valoarea implicita ceruta de Marius** (`4111`) ca precedent de configurare tot pe un cont
-de clienti — dar **nu** au un lant activ de apel, deci nu sunt un exemplu de "tipar in uz" la fel de
-tare ca `RF_CONT_INCASARE_*`.
-
-### 2d. `EFACTURA_CONT_ART_E`/`EFACTURA_CONT_ART_P` — optiune "cont implicit pe articol", azi goala
-
-`VARTYPE='CHARACTER'`, `VARVALUE` **goala** azi (nesetata pe baza curenta), `VARDESC='CONT ARTICOLE
-IMPLICIT FACTURI EMISE'`/`'...PRIMITE'`, `PROGRAM='ROACONT'`. Confirma ca tiparul "cont implicit
-configurabil, gol pana e setat manual" exista deja ca optiune (nu s-a putut verifica in aceasta
-runda cine o citeste — cautare in afara scopului, modulul `ROACONT`/eFactura nu a fost deschis).
-Relevanta doar ca a patra confirmare a conventiei de nume (`EFACTURA_CONT_ART_`), nu ca lant
-complet verificat.
-
----
-
-## 3. Propunerea concreta
-
-### 3.1 Cheia optiunii
-
-**`FACT_SCD_ARTFPRET`** — respecta conventia dominanta observata in tabel: prefix de modul
-(`FACT` pentru optiunile specifice `pack_facturare`/ROAFACTURARE, ca `FACTSETURI`,
-`FACTALGREPCOM`, `FACTURACUCHITANTA`, `FACTURAEMAIL`, `FACTURASOLD` — toate `PROGRAM='ROAFACTURARE'`)
-plus sufix descriptiv scurt fara diacritice si fara spatii (`SCD` = campul contabil vizat,
-`ARTFPRET` = "articol fara politica de pret" — in oglinda cu numele deja folosit in proiectarea
-anterioara, "ramura fara politica"). Nicio cheie `SCD`/`SCC` existenta azi in tabel (cautare directa,
-zero rezultate) — nu exista risc de coliziune de nume. **Alternativa mai scurta**, daca Marius
-prefera: `SCD_FARA_POLITICA` (fara prefix de modul) — tiparul din tabel nu e strict, exista si chei
-fara prefix (`D406`, `CONT411`); prefixul `FACT_` e recomandat, nu obligatoriu.
-
-### 3.2 Valoarea implicita si unde traieste
-
-**Tiparul deja stabilit si folosit de `RF_CONT_INCASARE_*` (sectiunea 2a) se copiaza identic**:
-implicitul traieste **in doua locuri**, nu unul:
-
-1. **In randul din `OPTIUNI`, la instalare** — valoarea `VARVALUE='4111'` scrisa direct de scriptul
- de migrare (sectiunea 3.4). Asta e valoarea pe care o vede si o poate schimba Marius/clientul din
- `frm_optiuni`, fara recompilare — exact cerinta deciziei 36.
-2. **Hardcodat in PL/SQL, langa apelul `getoptiunefirma`**, ca a doua plasa de siguranta pentru
- instalari vechi unde migrarea nu a rulat inca sau randul a fost sters/golit manual din ecran:
-
-```sql
-V_SCD := PACK_SESIUNE.getoptiunefirma('FACT_SCD_ARTFPRET');
-IF V_SCD IS NULL THEN -- acopera si randul lipsa, si VARVALUE gol/sters din ecran (sectiunea 1.2)
- V_SCD := '4111';
-END IF;
-```
-
-Plasata **in ramura noua din `contabilizeaza_articol`** (`canal_cont_venit_fara_politica.md:146`,
-randul `SCD` din tabelul design-ului), **in locul** liniei `SCD := '4111'` hardcodat propuse acolo —
-inlocuire punctuala, restul ramurii (`ASCD` calculat din `GetAnaliticByGrupUtilizatori(...,
-V_SCD)`, deja dependent de `V_SCD`) ramane neschimbat, primeste automat valoarea corecta indiferent
-de sursa (optiune sau fallback).
-
-### 3.3 Comportamentul cand optiunea lipseste sau e invalida
-
-- **Lipseste randul din `OPTIUNI`** (instalare veche, migrare neaplicata): `getoptiunefirma` intoarce
- `''` -> tratat `IS NULL` in Oracle -> fallback la `'4111'` hardcodat (sectiunea 3.2, pasul 2).
- **Acoperit prin constructie**, acelasi tipar ca `RF_CONT_INCASARE_*`.
-- **Randul exista dar `VARVALUE` e gol** (sters manual din ecran, fara sa fi fost stearsa cheia):
- identic cazului anterior — `''` tot `IS NULL` in Oracle. **Acoperit prin constructie.**
-- **`VARVALUE` contine un cont care nu exista in planul de conturi**, sau un string cu lungime/
- format invalid: **nu exista nicio validare azi**, nici in `getoptiunefirma`, nici in ecranul de
- optiuni (sectiunea 1.3, "nicio validare de format sau de continut"), nici la `INSERT INTO
- ACT_TEMP` (coloana `SCD` e `VARCHAR2(4) NULL` fara `CHECK`, fara `FK`, confirmat in DDL-ul deja
- citat in `canal_cont_venit_fara_politica.md`, sectiunea DDL). Un cont inexistent ar ajunge pe nota
- neschimbat — **exact acelasi risc pe care il are deja `RF_CONT_INCASARE_*` de 15 ani**, nu unul
- nou introdus de aceasta propunere. Daca se doreste o garda, ar trebui adaugata **la citire** (in
- ramura noua din `contabilizeaza_articol`, dupa cele doua atribuiri de mai sus, cu un `SELECT
- COUNT(*) FROM PLCONT WHERE COD_CONT = V_SCD` sau echivalent) — **nu exista azi un precedent de
- validare pe niciuna dintre optiunile de tip cont examinate**, deci adaugarea uneia ar fi o
- imbunatatire noua, nu o continuare a unui tipar existent; de decis explicit (sectiunea 4).
-- **Lungime > 4 caractere** in `VARVALUE` (campul din tabel e `VARCHAR2(1000)`, mult mai lat decat
- `ACT_TEMP.SCD VARCHAR2(4)`): ar da `ORA-12899` (value too large) la `INSERT INTO ACT_TEMP` daca
- cineva scrie din greseala un text lung in ecran — eroare Oracle standard, nu un `NULL`/gol tacut;
- comportament acceptabil ca gardă minimala "gratuita", fara cod suplimentar.
-
-### 3.4 Scriptul de migrare — schita, neaplicata
-
-Tiparul exact al insertiei `RF_CONT_INCASARE_BONFISCAL` (sectiunea 2a), idempotent prin verificarea
-existentei prealabile (tipar comun in scripturile de migrare vazute in `SCRIPTURI_CLAR`, desi
-insertia originala din 2010 nu avea garda — cea de mai jos o adauga, mai sigura pentru un script
-care ar putea rula de doua ori):
-
-```sql
--- ff__NN_COMUN_OPTIUNI.sql (schita, neaplicata)
-DECLARE
- V_CNT NUMBER;
-BEGIN
- SELECT COUNT(*) INTO V_CNT FROM OPTIUNI WHERE UPPER(TRIM(VARNAME)) = 'FACT_SCD_ARTFPRET';
- IF V_CNT = 0 THEN
- INSERT INTO OPTIUNI (VARNAME, VARTYPE, PROGRAM, VARVALUE, VARDESC, PROGRAME)
- VALUES ('FACT_SCD_ARTFPRET', 'CHARACTER', 'ROAFACTURARE', '4111',
- 'CONTUL DEBITOR (SCD) PENTRU ARTICOL FACTURAT FARA POLITICA DE PRET',
- 'ROAFACTURARE');
- END IF;
-END;
-/
-exec pack_migrare.UpdateVersiune('ff__NN_COMUN_OPTIUNI');
-commit;
-```
-
-`ID_PRG_OWNER` omis (rand `NULL` in toate exemplele citate, coloana pare neutilizata activ pentru
-optiuni de firma simple). `PROGRAME='ROAFACTURARE'` — restrans, spre deosebire de
-`RF_CONT_INCASARE_*` care listeaza 6 produse; de largit doar daca se confirma (in afara scopului
-acestei cercetari, sectiunea "Ce ramane de decis") ca alte produse din suita ajung sa apeleze aceeasi
-ramura din `contabilizeaza_articol` prin `adauga_articol_factura` simplu.
-
-### 3.5 Validare la salvare in ecran
-
-**Nu** — confirmat la sectiunea 1.3: `frm_optiuni_nou` valideaza doar "camp nevid" pe cele 3 campuri
-principale, nicio validare specifica per-cheie. Optiunea noua se comporta identic cu restul tabelei:
-utilizatorul poate scrie orice text de pana la 1000 caractere in `VARVALUE`, cu riscurile descrise
-la sectiunea 3.3.
-
----
-
-## 4. Ce ramane de decis
-
-1. **Numele exact al cheii** — `FACT_SCD_ARTFPRET` propus (sectiunea 3.1); Marius poate prefera alt
- nume sau formatul mai scurt `SCD_FARA_POLITICA`.
-2. **Se adauga o validare a contului la citire** (cont trebuie sa existe in planul de conturi) sau
- se pastreaza tiparul actual, fara validare, ca la `RF_CONT_INCASARE_*`? Niciun exemplu existent nu
- valideaza — a introduce validare ar fi prima data cand se face asta pe o optiune de tip cont.
-3. **`PROGRAME` restrans la `ROAFACTURARE` sau extins** ca la `RF_CONT_INCASARE_*` (6 produse)? Tine
- de raspunsul, inca deschis in `parametru_cont_contabilizeaza_articol.md` sectiunea 2d, la
- intrebarea daca alte produse din suita apeleaza `adauga_articol_factura` simplu.
-4. **Textul exact din `VARDESC`** — schita de mai sus e o propunere, nu o cerinta.
-
----
-
-## Ce nu s-a putut stabili
-
-- **Cine citeste azi `EFACTURA_CONT_ART_E`/`EFACTURA_CONT_ART_P`** (sectiunea 2d) — cautarea s-a
- oprit la insertia originala; modulul `ROACONT`/eFactura nu a fost deschis, in afara scopului
- cerut (exemplul a servit doar ca a patra confirmare de conventie de nume, nu ca lant complet).
-- **Definitia view-ului VFP local `v_optiuni`** (folosit ca `RecordSource` in `frm_optiuni`) — e un
- cursor/view generat dinamic prin `gencursor()`/`goExecutor.oExecute()` din `oinit_optiuni.prg`, nu
- un obiect Oracle persistent (interogare `DBMS_METADATA` pe `V_OPTIUNI` a esuat cu "object not
- found", asteptat) — nu schimba nimic din propunere, doar noteaza ca numele nu desemneaza o vedere
- Oracle.
-- **Daca `CONT411`/`DEVCONTALTELE` (sectiunea 2c) mai au vreun apelant in alt produs din suita**
- (ROACONT, ROAGEST etc.) — cautarea s-a limitat la `SCRIPTURI_CLAR` (tot codul PL/SQL istoric); nu
- s-a cautat in `.vc2`/`.prg` din alte COMUN-uri de produs.
diff --git a/docs/cercetare/pack_auto_actualizeaza_deviz.md b/docs/cercetare/pack_auto_actualizeaza_deviz.md
deleted file mode 100644
index 0d96364..0000000
--- a/docs/cercetare/pack_auto_actualizeaza_deviz.md
+++ /dev/null
@@ -1,210 +0,0 @@
-# Cercetare: `pack_auto.actualizeaza_deviz` si riscul asupra devizului ROAAUTO la #13
-
-Scop: `plan_13_unificare_formular_facturare.md` vrea sa permita adaugarea unei linii noi pe o
-factura deja emisa, inclusiv pe facturile ROAAUTO (`tip = -12`). Intrebarea: ce se intampla cu
-**devizul** din ROAAUTO cand factura primeste o linie pe care devizul nu o stie. Punctul de
-plecare a fost `pack_auto.actualizeaza_deviz`, apelat din
-`D:\ROA\ROAAUTO\Programe\oproceduri_devize.prg:1310`, al carei corp nu fusese citit inainte de
-aceasta cercetare.
-
-Continua `roaauto_facturi.md` si `roaauto_articole_lista_preturi.md` (deja citite, nu reiau
-constatarile lor: acelasi `PACK_FACTURARE`, `VANZARI_DETALII_TEMP` -> `VANZARI_DETALII`,
-`tip=-12`, liniile sintetice `-100000..-100008` plus liniile reale "Alte servicii", editorul
-`frm_modific2024` read-only, `oviz_devize.vc2:4536` blocheaza modificarea dupa `nrfact`).
-
-## 1. Unde e definit `PACK_AUTO`
-
-`D:\ROA\DATABASE\SCRIPTURI_CLAR\\\ff_..._AUTO_PACK_AUTO.sql` — 14 versiuni istorice
-gasite (2013-2026). Sursa de adevar folosita (cea mai recenta, dupa conventia deja aplicata in
-`roaauto_facturi.md` pentru `PACK_FACTURARE`):
-
-**`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_31_02_AUTO_PACK_AUTO.sql`** (1804 linii,
-antet "17.03.2026 / robert / creare procedura setOptiuneInchidere").
-
-Semnatura in spec: `:74-76`. Corp: `:692-733`.
-
-## 2. Ce face `actualizeaza_deviz`, pas cu pas
-
-Corpul complet (`ff_2026_03_31_02_AUTO_PACK_AUTO.sql:692-733`):
-
-```sql
-procedure actualizeaza_deviz(tnProcTvav IN NUMBER,
- tcSirIdOrdl IN VARCHAR2,
- tnIdSet IN NUMBER) is
- lcSeparator VARCHAR2(1) := ',';
- lnIdFact DOCUMENTE.ID_DOC%TYPE;
-begin
- -- nu iau pack_contafin.get_idfact pentru ca s-ar putea sa am id_fact de la incasare, nu de la factura
- SELECT MAX(ID_FACT)
- INTO lnIdFact
- FROM ACT
- WHERE COD = pack_contafin.get_cod()
- AND SCD NOT LIKE '5%';
-
- UPDATE DEV_ORDL
- SET PROC_TVAV = tnProcTvav
- WHERE ID_ORDL IN (SELECT X FROM table(charn2collection(tcSirIdOrdl, lcSeparator)));
-
- UPDATE /*+ INDEX(RUL IDX_RUL_001) */ RUL
- SET ID_FACT = lnIdFact
- WHERE ID_SET <> 229
- AND ID_LUCRARE IN (SELECT ID_LUCRARE FROM DEV_ORDL
- WHERE ID_ORDL IN (SELECT X FROM table(charn2collection(tcSirIdOrdl, lcSeparator))));
-
- IF tnIdSet IN (31003, 31004, 31005, 31006, 31007, 31011) THEN
- UPDATE NOM_LUCRARI
- SET ID_FACT = lnIdFact
- WHERE ID_LUCRARE IN (SELECT ID_LUCRARE FROM DEV_ORDL
- WHERE ID_ORDL IN (SELECT X FROM table(charn2collection(tcSirIdOrdl, lcSeparator))));
- END IF;
-end actualizeaza_deviz;
-```
-
-Trei pasi, toti indexati pe `ID_ORDL`/`ID_LUCRARE` (comanda/lucrarea din ROAAUTO), **niciunul pe
-`VANZARI`/`VANZARI_DETALII`**:
-
-1. Citeste `lnIdFact` = cel mai mare `ID_FACT` din `ACT` pentru "codul" curent de sesiune
- (`pack_contafin.get_cod()`), excluzand notele de incasare (`SCD NOT LIKE '5%'`) — comentariul
- din cod explica de ce: la momentul apelului pot exista in `ACT` atat o nota de incasare cat si
- nota/factura propriu-zisa, si vrea explicit factura.
-2. `UPDATE DEV_ORDL SET PROC_TVAV = tnProcTvav` — scrie cota de TVA pe comenzile din
- `tcSirIdOrdl` (lista CSV de `ID_ORDL`, despartita cu `charn2collection`).
-3. `UPDATE RUL SET ID_FACT = lnIdFact WHERE ID_SET <> 229 AND ID_LUCRARE IN (...)` — leaga
- inapoi randurile din `RUL` (jurnalul de manopera/materiale al lucrarii, folosit si la
- `frm_inchidere_productie.do_executa` pentru totalul pe sectii, vezi §4) de documentul creat.
-4. Doar daca `tnIdSet` e unul din `{31003,31004,31005,31006,31007,31011}`, acelasi `ID_FACT` se
- scrie si pe `NOM_LUCRARI` (nomenclatorul de lucrari).
-
-**Nu exista niciun `SELECT`/`UPDATE` pe `VANZARI` sau `VANZARI_DETALII` in `actualizeaza_deviz`**
-si, verificat suplimentar, **in tot pachetul `PACK_AUTO`** (grep pe `VANZARI` in cele 1804 linii
-ale fisierului: 0 potriviri). Deci raspunsul direct la intrebarea din brief: procedura **nu
-recalculeaza niciun total al devizului din liniile facturii** — nu citeste liniile facturii deloc.
-Ce face e sa "stampileze" `ID_FACT` (documentul de vanzare/nota abia creat) pe randurile din `RUL`
-si `NOM_LUCRARI` legate de comenzile din `tcSirIdOrdl`, plus sa actualizeze cota TVA pe
-`DEV_ORDL`. E o legatura *deviz -> document*, nu un recalcul *document -> total deviz*.
-
-## 3. Ce se intampla cu o linie de factura pe care devizul nu o are
-
-Raspunsul e neted, pentru ca premisa intrebarii (un `SUM` peste `VANZARI_DETALII`) nu exista in
-cod: **procedura nu vede deloc liniile facturii**, nici cele cunoscute (sintetice
-`-100000..-100008`), nici cele reale (nomenclator, cazul "Alte servicii" din raportul anterior),
-nici una noua adaugata din afara. Ea opereaza exclusiv pe `ID_ORDL`/`ID_LUCRARE` (identitatea
-comenzii ROAAUTO), primite ca parametru `tcSirIdOrdl` — nu deriva niciodata acest identificator
-din continutul `VANZARI_DETALII`.
-
-Precedentul "Alte servicii" (articole reale, `id_articol` pozitiv, cf.
-`roaauto_articole_lista_preturi.md` §2) confirma exact acest comportament pe date deja live: acele
-linii coexista cu liniile sintetice in `VANZARI_DETALII` de multa vreme, fara ca
-`actualizeaza_deviz` sa faca vreo distinctie — pentru ca nu se uita la `VANZARI_DETALII` deloc.
-
-**Consecinta pentru #13**: adaugarea unei linii noi pe `VANZARI_DETALII` pentru o vanzare
-`tip=-12` nu poate "dezechilibra" ce scrie `actualizeaza_deviz`, pentru simplul motiv ca aceasta
-procedura nu depinde de continutul `VANZARI_DETALII`. Nu exista *eroare*, nu exista *ignorare
-explicita* — e o absenta totala de citire.
-
-Important insa (nuanta pe care intrebarea din brief o presupune implicit gresit): asta **nu**
-inseamna ca "devizul" (asa cum e prezentat operatorului in ROAAUTO) ar reflecta automat noua
-linie. Totalul devizului afisat in `oviz_devize.vc2` e calculat client-side din `RUL` (vezi
-`crsTotaluri`, construit cu un `SELECT SUM(...) FROM RUL ... GROUP BY ID_SECTIE` in
-`oviz_devize.vc2:7816-7823`, in `frm_inchidere_productie.do_executa`) si din cursoarele
-`crsdeviz`/`crsalteserv` calculate in `oproceduri_devize.prg` la momentul facturarii — niciodata
-din `VANZARI_DETALII`. Deci o linie adaugata ulterior pe factura **nu va aparea niciodata** in
-totalul devizului asa cum il calculeaza ROAAUTO, indiferent daca `actualizeaza_deviz` mai ruleaza
-sau nu — pur si simplu acel total nu are o sursa care sa citeasca `VANZARI_DETALII`.
-
-## 4. Cand e apelata
-
-Cautare in ROAAUTO (`Grep` pe `actualizeaza_deviz`, cele trei aparitii de cod, plus istoric
-`.??2`) si in tot `D:\ROA\DATABASE\SCRIPTURI_CLAR` (niciun alt pachet Oracle nu o apeleaza — grep
-pe `actualizeaza_deviz` in tot arborele SCRIPTURI_CLAR gaseste doar fisierele care *definesc*
-`PACK_AUTO`/vechiul `PACK_DEVIZE`, nu vreun apel extern):
-
-Trei puncte de apel, toate in VFP, niciunul intr-un trigger/job Oracle:
-
-1. **La emiterea facturii** — `oproceduri_devize.prg:1310`, in acelasi bloc `lcSql` cu
- `pack_facturare.scrie_in_vanzari` (linia 1302), cu `tnIdSet` dinamic (`lnIdSet`, calculat mai
- sus in `factureaza_deviz`). Comentariu la linia 1311: *"am scos apelul catre
- `pack_devize.dev_completeaza_rul`; e inclus in `actualizeaza_deviz`"* — confirma ca functia a
- inlocuit o procedura mai veche cu acelasi scop (legare RUL -> document).
-2. **`frm_inchidere_productie.do_executa`** (`oviz_devize.vc2:7896`, clasa la `:7143`) — cu
- `tnIdSet` **fix, 31007** — apelata dupa ce formularul de **inchidere productie** scrie o
- *nota contabila* (`oscrie_in_fisiere()` peste cursorul `actactan`, `:7889`), **nu** o factura;
- nu apeleaza `pack_facturare.scrie_in_vanzari`, deci nu atinge `VANZARI` deloc pe acest drum.
-3. **`frm_inchidere_regie.do_executa`** (`oviz_devize.vc2:8907`, clasa la `:8093`) — identic,
- `tnIdSet` fix **31006**, pentru inchiderea de **regie** (overhead), tot printr-o nota
- contabila, nu o factura.
-
-Deci `actualizeaza_deviz` nu e specifica facturarii — e o operatie generica *"leaga
-comenzile/lucrarile astea de ultimul document contabil creat pentru codul curent"*, refolosita si
-la doua fluxuri de inchidere interna care nu produc facturi de vanzare. In niciunul din cele trei
-cazuri nu e re-declansata mai tarziu (nu exista un al patrulea apel, nici din UI, nici din
-schedule/trigger Oracle) — deci editarea ulterioara a unei facturi deja emise (obiectivul #13) nu
-ar re-invoca automat aceasta procedura, pentru ca nimic din codul citit o cheama in afara celor 3
-puncte de mai sus.
-
-## 5. Alte proceduri din `PACK_AUTO` care citesc `VANZARI`/`VANZARI_DETALII` pentru un deviz
-
-**Niciuna.** Grep pe `VANZARI` in intregul fisier `ff_2026_03_31_02_AUTO_PACK_AUTO.sql` (1804 de
-linii, tot pachetul, nu doar `actualizeaza_deviz`) — 0 potriviri. `PACK_AUTO` nu are nicio
-dependenta de tabelele de vanzari/facturare; toata legatura cu partea financiara trece prin `ACT`
-(note contabile) si `DEV_ORDL`/`RUL`/`NOM_LUCRARI` (structura proprie ROAAUTO).
-
-Singurul loc care **citeste** liniile facturii pentru re-listarea unui deviz e in afara
-`PACK_AUTO`, pe partea VFP: `relisteaza_factura_deviz`
-(`D:\ROA\ROAAUTO\Programe\oproceduri_devize.prg:1516-1576`, mentionata in raportul anterior).
-Verificat acum sursa: interogheaza direct view-urile COMUN `fact_vfacturi`
-(`:1531`, filtrat `WHERE cod = ...`) si **`fact_vfacturi_detalii`** (`:1564`,
-`select * from fact_vfacturi_detalii where id_vanzare = ` — fara alt filtru).
-View-ul e definit in
-`D:\ROA\DATABASE\SCRIPTURI_CLAR\2024\06\ff_2024_06_04_01_COMUN_FACTURARE.sql:8-94`:
-`create or replace view fact_vfacturi_detalii as select ... from vanzari_detalii a left join
-nom_articole b ... ` — un simplu wrapper peste `VANZARI_DETALII` cu join-uri de denumire, **fara
-nicio clauza `WHERE`** care sa restranga la id-uri de articol cunoscute sau la liniile
-"originale" ale devizului.
-
-**Consecinta**: o linie noua inserata in `VANZARI_DETALII` pentru acel `id_vanzare` **va aparea
-automat** la o re-listare/re-tiparire ulterioara prin `relisteaza_factura_deviz` — comportament
-asteptat de la un view neconditionat, nu o stricare. Nu exista risc de eroare sau de excludere pe
-acest drum; riscul (daca exista) e doar de **asteptare a utilizatorului**: factura retiparita va
-arata linia noua, dar ecranul de deviz din ROAAUTO (total calculat din `RUL`, §3) nu o va arata
-niciodata, pentru ca nu deriva din `VANZARI_DETALII`.
-
-## 6. Concluzie operationala pentru #13
-
-**Da, se poate adauga o linie pe o vanzare `tip=-12` fara sa "strice" `pack_auto.actualizeaza_deviz`
-sau vreo alta procedura din `PACK_AUTO`** — pentru ca niciuna din ele nu citeste `VANZARI`/
-`VANZARI_DETALII`; nu exista mecanism Oracle-side care sa recalculeze/verifice totalul devizului
-din liniile facturii, deci nu exista nimic de dezechilibrat la acel nivel. Nu e nevoie de niciun
-apel Oracle suplimentar din partea ROAFACTURARE ca sa "anunte" ROAAUTO despre linia noua —
-`actualizeaza_deviz` n-ar face nimic util cu acea informatie oricum (opereaza pe `ID_ORDL`, nu pe
-linii de factura).
-
-Ce **nu** rezolva aceasta concluzie, si ramane responsabilitatea planului #13, nu a acestei
-proceduri:
-
-- **Desincronizare de afisare, nu de date**: totalul devizului aratat in ROAAUTO
- (`oviz_devize.vc2`, calculat din `RUL`/cursoarele de facturare) nu va reflecta niciodata o
- linie adaugata ulterior direct pe `VANZARI_DETALII` — nici azi (cu liniile "Alte servicii"),
- nici cu o linie noua din editorul unificat. Daca produsul vrea ca devizul sa "stie" de linia
- noua vizual, ar trebui cod nou in ROAAUTO (nu exista azi), nu un apel catre `actualizeaza_deviz`.
-- **Reprintarea** (`relisteaza_factura_deviz`) va include automat linia noua (§5) — de verificat
- daca asta e comportamentul dorit de produs sau o suprindere pentru operatorul ROAAUTO.
-- Confirmat si direct in cod ROAFACTURARE: `Grep` pe `pack_auto` in
- `D:\ROA\ROAFACTURARE` (inclusiv `COMUN`) nu gaseste nicio referinta in cod, doar in `docs\`
- (planul #13 si aceste rapoarte) — azi ROAFACTURARE nu apeleaza deloc `PACK_AUTO`, confirmand ca
- nu exista deja o presupunere ascunsa de sincronizare intre cele doua.
-
-## Neverificat
-
-- Ce reprezinta exact tabelele `ACT`/`RUL`/`NOM_LUCRARI`/`DEV_ORDL` la nivel de schema completa
- (DDL/comentarii) — inteles doar din felul in care sunt folosite in cod, nu dintr-un dictionar de
- date citit explicit.
-- Daca vreun raport fiscal/SAF-T (mentionat generic in `ff_2022_03_24_01_COMUN_SAFT.sql`, nedeschis)
- agrega `VANZARI_DETALII` intr-un mod care ar fi afectat de o linie noua pe `tip=-12` — in afara
- ariei `PACK_AUTO` cerute, nu a fost investigat.
-- Daca `frm_incasare_finala.do_recalculeaza_total`/`calculeaza_total` (`oviz_devize.vc2:6494,6700`)
- ar putea fi reconciliate manual de un operator ca sa "vada" o linie adaugata ulterior — nu am
- citit corpul acestor metode, doar semnalul ca exista.
-- Istoricul complet al celorlalte 13 versiuni `AUTO_PACK_AUTO.sql` nu a fost comparat linie cu
- linie cu cea din 2026-03 — presupun (conform conventiei deja aplicate pentru `PACK_FACTURARE`)
- ca cea mai recenta e sursa de adevar pentru comportamentul curent din productie.
diff --git a/docs/cercetare/parametru_cont_contabilizeaza_articol.md b/docs/cercetare/parametru_cont_contabilizeaza_articol.md
deleted file mode 100644
index 80245a3..0000000
--- a/docs/cercetare/parametru_cont_contabilizeaza_articol.md
+++ /dev/null
@@ -1,173 +0,0 @@
-# Verificare adversariala — proiectarea parametrului de cont (`canal_cont_venit_fara_politica.md`, sectiunea "Proiectarea parametrului de cont contabil")
-
-Mandat: **nu re-proiecta** — proiectarea exista deja in `canal_cont_venit_fara_politica.md:13-227`
-(citita integral). Aici: incercare de a o sparge + inchiderea celor 4 goluri semnalate de autor.
-Sursa PL/SQL: aceeasi, `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`
-(17217 linii). Oracle: doar `SELECT`, schema `MARIUSM_AUTO`/`ROA_CENTRAL`. VFP: doar `vfp_symbols.ps1`
-(index, read-only). **Niciun fisier de cod atins.**
-
-## Verdict, in patru randuri
-
-**Proiectarea rezista la verificarea adversariala** — nu am gasit nicio eroare care sa-i invalideze
-concluzia centrala. Am gasit **un rand din tabel mai slab decat descris** (`CU_TVA=1` hardcodat NU e
-complet inofensiv — are un efect colateral masurabil, minor, prin `nproc_tva_max`), **un rand mai
-tare decat descris** (`IN_VALUTA` din `nin_valuta` e o sursa solida, nu doar plauzibila — parametru
-obligatoriu, fara `DEFAULT`), **o excludere confirmata corecta prin structura schemei** (articolul
-"compus" nu poate exista pe o linie fara politica — nu o gaura), si **un gol raportat de autor acum
-inchis cu fapt** (cele doua clase de la `:14069`/`:18089` sunt distincte, nu o duplicare a aceleiasi
-metode — 2 locuri VFP de atins, nu 1). Pe decizia 35 (regenerare = acelasi cod): **DA, calea Oracle
-e identica**, dar exista un obstacol real, deja proiectat separat (`idfact_refolosire_si_documente.md`),
-**in alt pachet** (`PACK_CONTAFIN`), nu in `pack_facturare` — nu invalideaza design-ul curent, dar
-regenerarea nu e completa fara acea a doua bucata de lucru.
-
----
-
-## 1. Decizia 35 — regenerarea foloseste identic `pack_facturare`?
-
-**DA pe calea Oracle relevanta pentru parametrul de cont, cu o exceptie deja cunoscuta si separata.**
-
-Verificat direct: `scrie_factura2` reseteaza starea de sesiune la fiecare apel prin
-`initializeaza_date_factura` (`PACK_FACTURARE:1808-1846`), care face
-`DELETE FROM VANZARI_DETALII_TEMP;` (`:1835`) si `pack_facturare.nid_act := 0;` (`:1836`) —
-**contorul folosit de `scrie_nota`/`scrie_discount`/`scrie_tva` la fiecare `INSERT INTO ACT_TEMP`
-porneste curat la fiecare emitere, inclusiv la o a doua** (regenerare). Nimic in
-`contabilizeaza_articol`, ramura noua inclusa, citeste vreo stare care ar presupune "documentul e
-nou" — toate variabilele folosite (`nid_venchelt`, `nid_sectie_stoc`, `nin_valuta`, `nid_set`,
-`nid_util`) sunt **citite**, nu verificate contra unei stari anterioare.
-
-**Obstacolul real e in `PACK_CONTAFIN`, nu in `pack_facturare`**: reemiterea cu acelasi `ID_FACT` (ca
-sa nu se dubleze documentul contabil la regenerare) ar da azi `ORA-00001` pe `PK_DOCUMENTE`, pentru ca
-`SET_IDFACT` ia mereu `SEQ_IdFact.NEXTVAL` si documentul vechi ramane in tabel doar soft-sters
-(`STERS=1`), nu disparut — analiza completa, cu solutia (variabila de pachet noua in `PACK_CONTAFIN`,
-`MERGE ... WHEN MATCHED` pe `DOCUMENTE`), e deja facuta integral in
-`idfact_refolosire_si_documente.md` (sectiunile A-C). **E exact "ceva care ar cere cod separat" — dar
-separat inseamna alt pachet/alta procedura (`SET_IDFACT`, scrierea in `DOCUMENTE`), nu o ramura in
-plus in `contabilizeaza_articol` sau `adauga_articol_factura`.** Ramane o bucata de lucru distincta,
-necesara pentru ca regenerarea sa fie completa, dar nu intersecteaza si nu invalideaza design-ul
-parametrului de cont.
-
-**Un gol neadresat de design, gasit acum**: ramura `pack_facturare.ntip = 4` ("facturare din avize",
-`:7520-7537`) apeleaza `scrie_fact_aviz_custodie` in loc de `descarca_gestiune`+discount — design-ul
-nu spune ce se intampla pe aceasta ramura in cazul fallback. In practica, **probabil nu conteaza**:
-"facturare din aviz" cere azi ca linia sursa sa aiba deja `id_pol` (`adauga_articol_factura:5096`,
-`AND A.ID_POL = V_ID_POL` pe `VANZARI_DETALII` a avizului sursa) — un aviz fara politica n-ar fi
-ajuns niciodata pana la factura pe acest drum, deci scenariul "fallback pe `ntip=4`" e putin probabil
-sa apara. **Dar design-ul nu spune asta explicit** — de adaugat o linie care sa acopere/exclude
-explicit acest caz inainte de implementare, nu de presupus tacit.
-
-## 2. Cele 4 goluri semnalate de autor
-
-### 2a. `ofacturare.vc2:14069`/`:18089` — doua metode sau o duplicare?
-
-`vfp_symbols.ps1 -Where 'ofacturare.vc2:14069'` -> **`frm_facturare_articole.do_scrie_articole`**
-(`ofacturare.vc2:13967-14195`). `-Where 'ofacturare.vc2:18089'` -> **`frm_facturare_articole2.do_scrie_articole`**
-(`ofacturare.vc2:18003-18221`). **Confirmat: doua clase distincte, `frm_facturare_articole` si
-`frm_facturare_articole2`, fiecare cu propria metoda `do_scrie_articole`** (acelasi nume de metoda,
-nu aceeasi clasa) — nu o duplicare literala a unui singur cod. **Consecinta pentru implementare**:
-parametrul nou trebuie cablat **in doua locuri VFP**, nu unul — ambele clase construiesc separat
-apelul RPC catre `adauga_articol_factura`. Nu schimba verdictul de fezabilitate, dar schimba
-suprafata de lucru VFP fata de impresia "un singur loc de atins".
-
-### 2b. `scrie_tva` la cota 0% cu `CU_TVA` hardcodat `1` — efect real, nu inofensiv
-
-Verificat corpul `scrie_nota` (`:12537-12558`): actualizarea `nproc_tva_max`/`nid_jtva_coloana`/
-`nTaxCode` **nu e neconditionata** — e in interiorul `IF V_CU_TVA = 1 THEN`, deci exact conditionata
-de flagul pe care design-ul propune sa-l hardcodeze. In interior insa, comparatia
-`IF pack_facturare.nproc_tva_max < V_PTVA THEN` **nu se uita la suma**, doar la rata — deci daca
-articolul fallback are `proc_tvav` real 0% (scutit) si `CU_TVA` e fortat la `1`, rata 0% **intra in
-comparatia de maxim** si, daca e prima/singura linie a documentului (`nproc_tva_max` initial `-1`,
-`:1885`), **castiga** — seteaza `nid_jtva_coloana`/`nTaxCode` la valorile acelei linii scutite.
-Aceste doua variabile sunt consumate mai departe **in aceeasi procedura `scrie_factura2`**, la
-discountul global pe factura (`:6164-6184`, `V_DISCOUNT_FACTURA <> 0`): rata/coloana/taxcode ale
-liniei scutite ar ajunge sa descrie linia de discount a **intregii facturi**, chiar daca alte linii
-au TVA real. **Verdict: `CU_TVA=1` hardcodat nu e "inofensiv" in toate cazurile cum spune design-ul —
-are un efect colateral real, dar restrans la o combinatie specifica (linie fallback cu TVA 0% +
-discount global pe factura + acea linie e cea cu rata "maxima" vazuta pana atunci).** Nu invalideaza
-alegerea `CU_TVA=1` ca implicit (majoritatea liniilor reale au TVA nenul), dar intareste, nu slabeste,
-cererea deja facuta de autor ("de confirmat cu Marius") — motivul de confirmat e mai concret decat
-"linie de TVA cu suma 0, inofensiv".
-
-### 2c. `INSERT INTO VANZARI_DETALII ... FROM VANZARI_DETALII_TEMP` — linie exacta, confirmata
-
-`PACK_FACTURARE:13705-13757`, in `scrie_in_vanzari` (spec `:13488`, apelata din `finalizeaza_factura`
-`:14787`, care e apelata la finalul fluxului de verificare — nu din `scrie_factura2`, alta faza a
-aceluiasi pipeline). **Confirmat: lista de coloane e explicita**, 24 coloane
-(`ID_VANZARE, ID_ARTICOL, LOT, SERIE, ID_RATA, ID_POL, CANTITATE, PRET_ACHIZITIE, PRETD, ID_VALUTAD,
-PRET, PROC_TVAV, ID_JTVA_COLOANA, ID_JTVA_COLOANA_EX, DISCOUNT_UNITAR, ID_GESTIUNE, ID_VALUTA, CONT,
-EXPLICATIE, PRET_CU_TVA, DIFERENTA, CUSTODIE, ID_VANZARE_SET, ID_CTR, TAXCODE`) — **nu** `SELECT *`.
-Exact ce presupunea design-ul (sectiunea 2, citand `nota_contabila_fara_politica.md` fara
-re-verificare): daca se doreste ca `CONT_VENIT` sa ajunga si in `VANZARI_DETALII` (trasabilitate),
-**aceasta lista trebuie extinsa explicit** — fara acest pas, coloana noua ramane doar pe
-`VANZARI_DETALII_TEMP` si `ACT_TEMP`, invizibila in `VANZARI_DETALII` dupa fapt. Confirmarea nu
-schimba verdictul design-ului (deja marcase pasul ca "recomandat, nu strict necesar"), doar il
-transforma din presupunere in fapt verificat.
-
-### 2d. Apelanti `adauga_articol_factura` din restul suitei
-
-Sarit, cum a cerut team-lead-ul — alt agent lucreaza pe suprafata de regresie.
-
----
-
-## 3. Verificare adversariala pe tabelul din design (sectiunea 3 a raportului sursa)
-
-| Rand din tabel | Incercare de infirmare | Rezultat |
-|---|---|---|
-| `IN_VALUTA` <- `pack_facturare.nin_valuta` | E setat pe toate fluxurile relevante, sau ramane nul si azi nu conteaza? | **Mai solid decat descris.** `nin_valuta := V_IN_VALUTA` (`:1902`) e in `initializeaza_date_factura`, apelata **o data la inceputul fiecarei emiteri**, cu `V_IN_VALUTA IN NUMBER` **fara `DEFAULT`** in semnatura (`:1827`) — VFP e obligat sa trimita o valoare, nu poate omite parametrul. Nu e un fallback de sesiune care "poate ramane nesetat" (ca `nid_venchelt`), e un flag de document obligatoriu, mereu curent. |
-| `ID_VENCHELT`/`ID_SECTIE` <- variabile de sesiune | Cine le seteaza si cand? | **Confirmat, cu nuanta.** `nid_venchelt := V_ID_VENCHELT` si `nid_sectie_stoc := V_ID_SECTIE` (`:1876-1877`), tot in `initializeaza_date_factura`, din parametri **fara `DEFAULT`** insa **VFP poate trimite `NULL`** pe ei (sunt opționale ca *valoare*, nu ca prezenta in apel) — deci pot ramane `NULL` pe tot documentul. **Nu e o regresie**: pe ramura veche, `NVL(nid_venchelt, NVL(A.ID_VENCHELT, C.ID_VENCHELT))` ar da tot `NULL` daca nici politica nu are aceste campuri — acelasi rezultat posibil, aceeasi cauza (sesiune nesetata), nu unul nou introdus de fallback. |
-| Garda `descarca_gestiune` copiata identic | Acopera `id_gestiune=-1000` si `in_stoc`? | **Da, fara diferenta.** Garda foloseste `detalii_articol.id_gestiune`/`.in_stoc` — campuri populate identic de `adauga_articol_factura` indiferent de ramura (nu depind de politica azi, nici in design). Copierea literala a conditiei (`:7473-7475`) e corecta prin constructie. |
-| `ASCD`/`ASCC` <- `GetAnaliticByGrupUtilizatori` | Ce intoarce pe `NO_DATA_FOUND`, e acceptabil? | **Confirmat `NULL`** (corp citit `:16704-16723`: `lcAcont` declarat fara valoare implicita, `EXCEPTION WHEN NO_DATA_FOUND THEN NULL;`, `RETURN lcAcont`). Acceptabil — e exact fallback-ul deja folosit azi, necondiționat, pe ramurile de aviz (`:7416-7417,7421-7422`) si `ACT_TEMP.ASCD/ASCC` sunt nullable (confirmat DDL, `canal_cont_venit_fara_politica.md` DDL section). Nu e un risc nou. |
-| Articol "compus" (`V_COMPUS=1`) lasat in afara scopului | Poate un articol ales ad-hoc din nomenclator fi compus? | **NU — exclus prin structura schemei, nu prin presupunere.** Interogat direct `ALL_VIEWS.VCRM_POLITICI_PRET_ART`: coloana `COMPUS` citita de `contabilizeaza_articol` (`SELECT COMPUS, ID_POL_ART ... FROM VCRM_POLITICI_PRET_ART`, `:7279-7283`) e definita in view ca `CASE WHEN PA.ID_POL_ART IN (SELECT DISTINCT ID_PACHET FROM CRM_PACHETE_ARTICOLE WHERE STERS=0) THEN 1 ELSE 0 END` — o proprietate a **perechii (articol, politica)**, identificata prin `ID_POL_ART` (cheia surogat a randului din `CRM_POLITICI_PRET_ART`). O linie fara politica **nu are** un `ID_POL_ART` — deci intrebarea "e articolul compus" nu se poate pune structural pe aceasta ramura. (`NOM_ARTICOLE.COMPUS` exista ca alta coloana, aliasata `art_compus` in acelasi view, dar **nu e citita de `contabilizeaza_articol`** — irelevanta aici.) Excluderea din design e corecta, nu o gaura. |
-| `RETURN V_INCASAT_CALCUL` | Se calculeaza corect pe ramura noua sau intoarce 0? | **Corect, prin constructie.** Design-ul specifica explicit aceeasi acumulare ca azi (`V_INCASAT_CALCUL := V_INCASAT_CALCUL + scrie_nota(...)`, apoi `- scrie_discount(...)`), cu `V_INCASAT_CALCUL` initializat `0` la declaratie (`:7178`), inainte de `IF`-ul care selecteaza ramura — identic cu azi. Niciun risc de `RETURN 0` gasit. |
-
----
-
-## 4. Hardcodarile `SCD='4111'` / `CU_TVA=1` — exista o sursa mai buna?
-
-Cautare directa in tot `PACK_FACTURARE` pentru orice sursa alternativa care nu trece prin
-`NOTE_CONTABILE`: config de firma (`getoptiunefirma('CONT...')`), cont implicit pe partener/client
-(`PARTENERI.CONT*`), flag de scutire TVA pe articol/client (`SCUTIT`, `EXCEPTAT`) — **zero rezultate
-pentru toate cele trei cautari**. Singurul camp inrudit gasit, `ACT_TEMP.NEIMPOZAB`, e folosit in alt
-scop (raportare sume neimpozabile), nu ca sursa pentru `CU_TVA`. **Concluzie: nu exista o sursa mai
-buna in cod — hardcodarea (sau parametrul explicit trimis de VFP) ramane singura optiune.** Asta
-intareste recomandarea deja facuta de autor: **de decis explicit cu Marius, nu de dedus din date**,
-mai ales pentru `CU_TVA` dupa gasirea de la punctul 2b (efectul via `nproc_tva_max` nu mai e
-"pur cosmetic").
-
----
-
-## 5. Completare: `goExecutor.oExecuta` si cursorul de verificare — fals pozitiv, nu bug
-
-Verdict: **fals pozitiv, confirmat cu argumente, nu doar presupus.** `oExecuta` (funcție-wrapper,
-`COMUN\programe\oproceduri_comune.prg:121-159`) deleagă la `oExecute` (`:173-504`), care la rândul ei
-face `SQLExec(lnHandle, lcSql, lcCursor)` (`:330`) — **`lcSql` e folosit exact cum a fost construit de
-apelant, fără nicio rescriere care să adauge un bind lipsă.** Textul construit în
-`COMUN\clase\ofacturare.vc2:14345-14359` (și identic la `:14373-14387`, `:18343-18371`) e sintaxă
-ODBC escape `{call pack_facturare.scrie_factura2(...)}`, cu **16** argumente poziționale (15 `IN` +
-`?@poDate.nid_vanzare` pentru `V_ID_VANZARE OUT NUMBER`, al 16-lea parametru declarat), paranteza se
-închide imediat după — **al 17-lea parametru, `V_CURSOR_VERIFICARE OUT pack_facturare.cursor_facturare`
-(spec `PACK_FACTURARE:656`), nu are niciun placeholder în text, nici legat, nici nelegat.** Asta e
-**exact tiparul cunoscut al driverului ODBC Oracle pe care VFP îl folosește prin `SQLExec`**: cand
-ultimul parametru declarat al unei proceduri e un `REF CURSOR OUT`, driverul îl detectează din
-catalogul Oracle (nu din textul apelului) și întoarce automat rândurile lui ca *result set* al
-apelului — **al treilea argument al `SQLExec`/`oExecute` (numele de cursor VFP, aici `lcCursorVerificare`)
-e exact mecanismul de captare a acelui result set**, fără sa fie nevoie de bind explicit. Codul imediat
-după apel (`ofacturare.vc2:14394-14397`, `llReturn = goExecutor.oExecuta(lcSql,lcCursorVerificare)`
-urmat de `If Reccount(lcCursorVerificare)>0`) tratează cursorul ca fiind deja populat cu rânduri —
-comportament incompatibil cu un apel eșuat sau cu un parametru nelegat (care ar da eroare Oracle,
-nu un cursor gol interpretabil). **Nu pot confirma mecanismul din interiorul driverului însuși** (e
-extern codebase-ului, verificabil doar prin comportament) — dar dovada indirectă e puternică: același
-tipar apare identic în toate cele 4 locuri de apel găsite, neschimbat de-a lungul mai multor versiuni
-(`v 2.0.13` -> `v 2.0.93`, comentarii de istoric vizibile în cod), iar ecranul de verificare (funcție
-activă, folosită la fiecare emitere) depinde de acest cursor populat — dacă apelul ar eșua silențios,
-ecranul de verificare n-ar arăta niciodată note propuse, ceea ce ar fi fost observat imediat. **Concluzie
-pentru plan: anomalia nu există — nu trebuie tratată ca risc pe cele 7 produse.**
-
-## Ce ramane neverificat
-
-- Comportamentul exact al ramurii `ntip=4`/`scrie_fact_aviz_custodie` in scenariul fallback (punctul
- 1) — argumentat ca improbabil, nu testat/exclus explicit in design.
-- Daca vreun raport Oracle activ presupune `ACT_TEMP.ID_VENCHELT`/`ID_SECTIE` populate pe liniile de
- venit (relevant doar daca sesiunea nu seteaza `nid_venchelt`/`nid_sectie_stoc`) — in afara scopului
- acestei verificari (cod PL/SQL only).
-- Suprafata de regresie la nivelul apelantilor `adauga_articol_factura` din restul suitei — explicit
- lasata altui agent.
diff --git a/docs/cercetare/rec_cale_vanzari_detalii.md b/docs/cercetare/rec_cale_vanzari_detalii.md
deleted file mode 100644
index 9134158..0000000
--- a/docs/cercetare/rec_cale_vanzari_detalii.md
+++ /dev/null
@@ -1,272 +0,0 @@
-# Cercetare: calea VFP->Oracle la emitere si calea propusa pentru editare (#6, punctul E.4)
-
-Sursa: interogari SELECT proaspete pe `MARIUSM_AUTO@ROA_CENTRAL` (08.08.2026), acelasi mediu si
-aceeasi versiune de baza ca in `rec_s5_oracle_vanzari.md` (nu s-a schimbat nimic intre cele doua
-cercetari din aceeasi zi). Numerele de linie PL/SQL de mai jos sunt dintr-un export propriu, facut
-in aceasta sesiune, din `all_source` pentru `PACK_FACTURARE` (schema/pachet identic cu cel din
-raportul anterior). Partea VFP e din cache-ul text `.vc2` din proiect (nu binarul).
-
-Aceasta cercetare inchide golul lasat de `rec_s5_oracle_vanzari.md`, sectiunea E.4: cum ajung
-liniile facturii in Oracle la emitere si care e calea corecta pentru editare.
-
-## 1. Calea de azi, capat la capat
-
-### 1.1 VFP: cine populeaza `VANZARI_DETALII_TEMP`
-
-Raspuns: **Oracle**, prin apeluri per-linie facute din VFP, nu VFP direct prin INSERT.
-
-- `frm_facturare_articole.do_scrie_articole` (`COMUN\clase\ofacturare.vc2:13967-14195`):
- - `:13981-13999` cheama `pack_facturare.initializeaza_date_factura(...)` (antetul documentului,
- tine minte parametrii in stare de sesiune pe pachet: `pack_facturare.ntip`, `nid_sucursala`,
- `nid_util` etc. — folosite mai jos de `adauga_articol_factura`).
- - `:14036-14115`: `SELECT crsfactura` -> `SCAN`, cate un `Scatter Name poArt MEMO` per linie, apoi
- pentru fiecare linie fara rata de contract (`ELSE` la `:14051`) construieste text PL/SQL literal
- (nu `{call}` cu parametri legati) si apeleaza
- `pack_facturare.adauga_articol_factura(id_temp, id_articol, serie, explicatie, id_pol,
- id_gestiune, pret_achizitie, pretd, id_valutad, pret, id_valuta, cu_tva, gestionabil,
- cantitate, discount, cont, curs, multiplicator, id_jtva_coloana, id_part_rez, id_lucrare_rez,
- pretv_orig, id_set_fact, id_ctr, gnIdUtil, taxcode, lot)` (`:14069-14091`), executat imediat
- prin `goExecutor.oExecute(lcSql)` (`:14105`) — **un apel Oracle per linie de factura**, in
- bucla, nu un singur apel cu tot cursorul.
- - Pentru liniile din seturi: `pack_facturare.initializeaza_seturi_temp` + un apel
- `pack_facturare.adauga_articol_set(...)` per linie de set (`:14117-14154`), scrie in
- `VANZARI_SETURI_TEMP`.
-- `frm_facturare_articole.do_scrie_factura` (`:14197-14554`): dupa ce toate liniile au fost urcate
- in TEMP prin apelurile de mai sus, apeleaza finalizarea documentului —
- `pack_facturare.scrie_factura2(...)` (facturi, `:14345`/`:14373`) sau
- `pack_facturare.scrie_proforma(...)` (`:14286`) sau `scrie_factura_avize(...)`/
- `scrie_factura_avize_retur(...)` dupa tipul documentului — **un singur apel**, fara sa mai
- transmita liniile (ele sunt deja in `VANZARI_DETALII_TEMP`, populata de bucla anterioara, in
- ACEEASI sesiune/tranzactie Oracle).
-
-### 1.2 Oracle: `adauga_articol_factura` — nu doar INSERT, RECALCULEAZA din sursa originala
-
-Verificat sursa completa a procedurii publice `pack_facturare.adauga_articol_factura` (semnatura cu
-`V_ID_TEMP` ca prim parametru, cea apelata de VFP la `:14069`) — **nu** e un simplu INSERT cu
-valorile primite de la VFP. Ramifica pe `pack_facturare.ntip` (starea de sesiune setata la
-`initializeaza_date_factura`) si **re-deriva** `V_PRET`, `V_PROC_TVAV`, `V_ID_VALUTA`,
-`V_PRETURI_CU_TVA`, `V_IN_STOC` direct din documentul-sursa:
-- `ntip IN (3,21,28,42,47)` (facturare din comenzi): `SELECT ... FROM COMENZI_ELEMENTE ...`
-- `ntip = 4` (facturare din avize): `SELECT ... FROM VANZARI_DETALII ...` (avizul deja scris)
-- `ntip = 45` (restaurant): calcul din `JTVA_COLOANE` + `CRM_POLITICI_PRET_ART`
-- `V_OPT_FACTURARE = 3` (contract): `SELECT ... FROM CTR_ARTICOLE ...`
-- fallback (`ELSE`): doar cota TVA din `JTVA_COLOANE`, restul (`V_PRET`, `V_ID_VALUTA`,
- `V_PRETURI_CU_TVA`, `V_IN_STOC`) preluate ca atare din parametrii transmisi de VFP.
-
-Abia dupa acest bloc `CASE` urmeaza INSERT-ul propriu-zis:
-
-```sql
-INSERT INTO VANZARI_DETALII_TEMP
- (ID_TEMP, ID_ARTICOL, SERIE, LOT, EXPLICATIA, ID_POL, PRET_ACHIZITIE, PRETD, ID_VALUTAD,
- PRET, PRET_CU_TVA, PROC_TVAV, CANTITATE, DISCOUNT_UNITAR, ID_GESTIUNE, CONT, ID_VALUTA,
- CURS, MULTIPLICATOR, ID_JTVA_COLOANA, IN_STOC, ID_VANZARE_SET, ID_PART_REZ, ID_LUCRARE_REZ,
- PRETV_ORIG, CUSTODIE, ID_CTR, ID_UTIL, TAXCODE)
-VALUES (...)
-```
-
-(am confirmat integral corpul, INSERT-ul e ultimul bloc din procedura, imediat dupa `END CASE`).
-
-**Consecinta directa pentru #6**: `adauga_articol_factura` NU poate fi reutilizata ca atare pentru
-editare — depinde de starea de sesiune `pack_facturare.ntip`/`clistaid`/`id_ctr` care descrie
-DOCUMENTUL SURSA de la emitere (comanda/aviz/contract), stare care nu exista si nu are sens la o
-editare ulterioara a facturii deja emise. Orice procedura noua pentru editare trebuie sa scrie
-direct in `VANZARI_DETALII` (tabela reala), nu prin acest drum.
-
-Exista si `sterge_articol_factura(V_ID_TEMP, V_ID_UTIL)` — `DELETE FROM VANZARI_DETALII_TEMP WHERE
-ID_TEMP = V_ID_TEMP` — folosita doar cat timp factura e in curs de compunere (inainte de emitere),
-nu dupa.
-
-### 1.3 Oracle: `scrie_factura2` -> `finalizeaza_factura` -> `scrie_in_vanzari` — trecerea TEMP -> real
-
-`scrie_factura2` (PACK_FACTURARE, corpul activ, nu varianta comentata din cod):
-- `:70` `pack_contafin.sterge_temp_actrul()`, seteaza `pack_facturare.ntotftva/ntottva` din
- parametri (valori calculate in VFP).
-- `:84` `SELECT * BULK COLLECT INTO tab_detalii FROM VANZARI_DETALII_TEMP` — citeste TOATA tabela
- temp intr-un array PL/SQL, fara filtru pe sesiune (GTT-ul e oricum izolat per sesiune/tranzactie).
-- Bucla pe `tab_detalii`, ramificata tot pe `ntip` (transfer intre subunitati, restaurant etc.) —
- pentru cazul standard de factura apeleaza mai departe spre `pack_facturare.finalizeaza_factura`.
-
-`finalizeaza_factura` (nu comentata):
-```sql
-pack_facturare.initializeaza_scriere_actrul(V_DATAORA);
-pack_facturare.scrie_in_vanzari(V_DISCOUNT_FACTURA, V_ID_DELEGAT, V_ID_MASINA, V_ID_FACTURARE,
- V_LISTARE_DETALIATA, V_DATAORA_EXP, V_ID_AGENT, V_TEXT_ADITIONAL, pack_facturare.nid_vanzare);
-pack_facturare.finalizeaza_scriere_actrul();
--- update vanzari set id_fact = ... (completare id_fact dupa scrierea in contabilitate)
-```
-
-`scrie_in_vanzari` — gasit exact mecanismul care lipsea din raportul anterior:
-- `INSERT INTO VANZARI (...) VALUES (...) RETURNING ID_VANZARE INTO pack_facturare.nid_vanzare`
- (randul parinte, un rand per document din bucla pe `tab_vanz`, tabela interna cu documentele de
- scris — cazul normal e un singur document).
-- `pack_facturare.scrie_cursuri(pack_facturare.nid_vanzare)`.
-- **Trecerea efectiva TEMP -> real**:
- ```sql
- INSERT /*+ APPEND */ INTO VANZARI_DETALII
- (ID_VANZARE, ID_ARTICOL, SERIE, ID_POL, CANTITATE, PRET_ACHIZITIE, PRETD, ID_VALUTAD,
- PRET, PROC_TVAV, DISCOUNT_UNITAR, ID_GESTIUNE, ID_VALUTA, CONT, PRET_CU_TVA, ID_JTVA_COLOANA)
- SELECT pack_facturare.nid_vanzare, ID_ARTICOL, SERIE, ID_POL, CANTITATE, PRET_ACHIZITIE, PRETD,
- ID_VALUTAD, PRET, PROC_TVAV, DISCOUNT_UNITAR, ID_GESTIUNE, ID_VALUTA, CONT, PRET_CU_TVA,
- ID_JTVA_COLOANA
- FROM VANZARI_DETALII_TEMP
- WHERE ID_COMANDA = tab_vanz(i).id_comanda AND NUMAR_ACT = tab_vanz(i).numar_act
- ORDER BY ID_TEMP;
- ```
- Cheia de potrivire intre randul nou din `VANZARI` si liniile lui din TEMP e
- `(ID_COMANDA, NUMAR_ACT)` — nu `ID_TEMP` direct — pentru ca un singur apel poate scrie mai multe
- documente `VANZARI` deodata (facturare pe mai multe comenzi/numere de act simultan); fiecare
- document isi ia doar liniile care se potrivesc.
-- Coloanele COPIATE in `VANZARI_DETALII` sunt un subset din `VANZARI_DETALII_TEMP` (16 coloane) —
- `ID_TEMP`, `ID_CTR`, `ID_UTIL`, `TAXCODE`, `LOT`, `ID_VANZARE_SET`, `ID_PART_REZ`,
- `ID_LUCRARE_REZ`, `PRETV_ORIG`, `CUSTODIE`, `NUMAR_ACT`, `ID_COMANDA`, `ID_GESTIUNE_DEST`
- raman DOAR in TEMP, nu se copiaza in tabela reala (`VANZARI_DETALII` nu are coloanele `ID_TEMP`,
- `NUMAR_ACT`, `ID_COMANDA` etc. — confirmat din `all_tab_columns`, vezi 2.2).
-- Urmeaza blocul de agregare (`SELECT INTO` din `VANZARI_DETALII_TEMP`, deja documentat in
- `rec_s5_oracle_vanzari.md` A.3-A.4) si `UPDATE VANZARI SET total_fara_tva=..., ...` cu totalurile
- denormalizate.
-
-**PK-ul `VANZARI_DETALII.ID_VANZARE_DET`** se genereaza automat: trigger `TRG_VANZARI_DET_BEFOINS`
-(`BEFORE INSERT ... FOR EACH ROW`, verificat prin `dbms_metadata.get_ddl`) face exclusiv
-`SELECT SEQ_VANZARI_DETALII.NEXTVAL INTO :NEW.ID_VANZARE_DET FROM DUAL` — nu seteaza alte coloane.
-Deci **orice INSERT nou in `VANZARI_DETALII`** (inclusiv unul scris pentru #6, la adaugare de linie
-noua la editare) primeste automat PK-ul corect fara sa fie nevoie de secventa apelata manual din
-codul de editare.
-
-## 2. Natura tabelei temp si structura
-
-### 2.1 `VANZARI_DETALII_TEMP` — Global Temporary Table, `ON COMMIT DELETE ROWS`
-
-Confirmat din `all_tables`:
-
-| TABLE_NAME | TEMPORARY | DURATION |
-|---|---|---|
-| VANZARI | N | — |
-| VANZARI_DETALII | N | — |
-| VANZARI_DETALII_TEMP | **Y** | **SYS$TRANSACTION** |
-| VANZARI_SETURI_TEMP | **Y** | **SYS$TRANSACTION** |
-
-`DURATION = SYS$TRANSACTION` inseamna GTT cu `ON COMMIT DELETE ROWS` — randurile dispar la commit
-(sau rollback), nu doar la sfarsit de sesiune. **Consecinta directa**: orice solutie care ar
-reutiliza `VANZARI_DETALII_TEMP` pentru editare (#6) trebuie sa umple tabela SI sa consume
-rezultatul in ACEEASI tranzactie — nu poate fi umpluta intr-un pas si citita in altul, ca in fluxul
-de emitere unde umplere (bucla `adauga_articol_factura`) si consum (`scrie_factura2`) se intampla
-deja in aceeasi conexiune/tranzactie, inainte de commit.
-
-### 2.2 Coloane: `VANZARI_DETALII` vs `VANZARI_DETALII_TEMP`
-
-`VANZARI_DETALII` (35 coloane, din `all_tab_columns`) — cheie primara `ID_VANZARE_DET` (NOT NULL,
-generata din secventa prin trigger), FK logic `ID_VANZARE` (NOT NULL). Coloane relevante pentru
-editare: `PRET` (NOT NULL), `CANTITATE`, `PRET_CU_TVA`, `DISCOUNT_UNITAR`, `PROC_TVAV`, `STERS`
-(NOT NULL), `VALIDAT`/`DATAORA_VALID`/`ID_UTIL_VALID`, `ID_UTILS`/`DATAORAS` (audit),
-`DIFERENTA` (NOT NULL), `CUSTODIE`/`DESCARCAT` (NOT NULL) — ultimele patru nu au valoare implicita
-vizibila in trigger, deci probabil `DEFAULT` la nivel de coloana (nu s-a verificat separat, nu era
-in scope).
-
-`VANZARI_DETALII_TEMP` (28 coloane) — **fara PK real** (`ID_TEMP` e generat in VFP, folosit doar ca
-identificator temporar de linie in cadrul sesiunii curente de compunere a facturii), **fara**
-`ID_VANZARE`/`ID_VANZARE_DET`/`STERS`/`VALIDAT` (nu se aplica inainte de a exista documentul
-parinte). Are in schimb coloane specifice etapei de compunere, care NU exista in tabela reala:
-`ID_TEMP`, `NUMAR_ACT`, `ID_COMANDA`, `ID_GESTIUNE_DEST`, `ID_UTIL` (vs `ID_UTILS` in cea reala).
-
-Coloanele comune folosite de editare (S4): `ID_ARTICOL`, `PRET`, `CANTITATE`, `PRET_CU_TVA`,
-`DISCOUNT_UNITAR`, `PROC_TVAV`, `ID_GESTIUNE`, `CONT`, `ID_VALUTA`, `CURS` (doar in TEMP; in
-`VANZARI_DETALII` nu exista `CURS` per linie — cursul e doar pe document, in `VANZARI_CURSURI`/
-`VANZARI.CURS`), `ID_JTVA_COLOANA`, `SERIE`, `EXPLICATIE`/`EXPLICATIA` (nume diferit!), `TAXCODE`,
-`LOT`.
-
-## 3. Stergerea si adaugarea de linii
-
-### 3.1 Stergere — mecanism EXISTENT azi doar la nivel de document intreg, NU per linie
-
-Cautat explicit orice `UPDATE VANZARI_DETALII SET STERS` in `PACK_FACTURARE` — gasite doar doua
-locuri, ambele sterg TOATE liniile unui document, niciodata o singura linie:
-
-- `sterge_factura(V_ID_VANZARE, ...)`:
- `UPDATE VANZARI_DETALII SET STERS = V_STERS, ID_UTILS = V_ID_UTIL, DATAORAS = V_DATAORA WHERE
- ID_VANZARE = V_ID_VANZARE AND STERS = V_NESTERS` (V_STERS variaza 0/1 dupa tipul documentului,
- cazul normal fiind 1).
-- `sterge_proforma(V_ID_VANZARE, ...)`: acelasi tipar, exclusiv pe proforme.
-
-**Nu exista azi un mecanism Oracle sau VFP de stergere per-linie in `VANZARI_DETALII`** — orice
-"stergere de linie la editare" ceruta de S4/S4b e functionalitate NOUA, de adaugat la #6, nu o
-reutilizare a ceva existent.
-
-Exista insa un precedent apropiat de UPDATE punctual per linie, util ca sablon:
-`modifica_explicatie_articol(V_ID_VANZARE_DET, V_EXPLICATIE, V_ID_UTIL, V_TAXCODE)` —
-`UPDATE VANZARI_DETALII SET EXPLICATIE = V_EXPLICATIE, TAXCODE = V_TAXCODE WHERE ID_VANZARE_DET =
-V_ID_VANZARE_DET` — exact modelul de "UPDATE tintit prin `goExecutor`" mentionat ca varianta in
-planul S5/S6, deja folosit azi din `frm_modifica_articol_factura` (mostenire de la #7, vezi
-`plan_06_editare_factura.md`).
-
-### 3.2 Adaugare de linie noua — nu cere nimic special in plus fata de un INSERT direct
-
-`ID_VANZARE_DET` vine automat din `SEQ_VANZARI_DETALII` prin trigger la orice `INSERT INTO
-VANZARI_DETALII`, indiferent de cine face insert-ul (nu doar fluxul de emitere) — vezi 1.3. Deci
-adaugarea unei linii noi la editare **nu** cere obtinerea manuala a unui ID din secventa; e suficient
-un `INSERT INTO VANZARI_DETALII (ID_VANZARE, ID_ARTICOL, PRET, CANTITATE, PRET_CU_TVA, ...) VALUES
-(...)` (fara `ID_VANZARE_DET` in lista de coloane) intr-o procedura noua, apelata din
-`finalizeaza_modificare_nota` alaturi de recalculul de totaluri propus in `rec_s5_oracle_vanzari.md`
-punctul B.
-
-## 4. Propunerea pentru S4/S5/S6 — cum trimite editarea liniile modificate in Oracle
-
-### Optiuni comparate
-
-**A. Refolosirea `VANZARI_DETALII_TEMP` + o "mini scrie_in_vanzari" pentru editare** — ar insemna ca
-formularul de editare (S4) sa populeze TEMP la fel ca la emitere (apeluri per linie), apoi o
-procedura noua sa faca INSERT-urile/UPDATE-urile in `VANZARI_DETALII` din TEMP, in aceeasi
-tranzactie (impusa de `ON COMMIT DELETE ROWS`, vezi 2.1). Risc: reproduce complexitatea lui
-`adauga_articol_factura` (ramificare pe `ntip`/sursa document) fara sa aiba sens la editare — acolo
-nu exista comanda/aviz/contract "curent" din care sa se re-deriva pretul; ar trebui un mod nou,
-simplificat, de populare a TEMP doar pentru editare, ceea ce complica inutil un cod deja incarcat.
-Risc mediu-mare de regresie pe calea de emitere daca vreo modificare atinge accidental
-`adauga_articol_factura`/`scrie_in_vanzari` partajate.
-
-**B. UPDATE/INSERT/soft-DELETE punctual direct in `VANZARI_DETALII`, prin `goExecutor`, dintr-o
-procedura noua dedicata editarii** — fara sa treaca deloc prin `VANZARI_DETALII_TEMP`. Model deja
-existent si folosit: `modifica_explicatie_articol` (UPDATE tintit pe `ID_VANZARE_DET`). Pentru cele
-trei operatii cerute de S4/S4b:
- - **Editare cantitate/pret/`pret_cu_tva`** pe o linie existenta: `UPDATE VANZARI_DETALII SET
- CANTITATE=..., PRET=..., PRET_CU_TVA=..., DISCOUNT_UNITAR=... WHERE ID_VANZARE_DET = :id`.
- - **Stergere linie**: `UPDATE VANZARI_DETALII SET STERS=1, ID_UTILS=:util, DATAORAS=SYSDATE WHERE
- ID_VANZARE_DET = :id` — acelasi tipar ca `sterge_factura`, dar tintit pe o singura linie (nou,
- nu exista azi, vezi 3.1).
- - **Adaugare linie noua**: `INSERT INTO VANZARI_DETALII (ID_VANZARE, ID_ARTICOL, PRET, CANTITATE,
- PRET_CU_TVA, DISCOUNT_UNITAR, PROC_TVAV, ID_GESTIUNE, CONT, ID_VALUTA, ID_JTVA_COLOANA, SERIE,
- EXPLICATIE, TAXCODE, LOT) VALUES (...)` — PK automat din trigger (vezi 3.2).
- Apoi, in ACEEASI tranzactie (deschisa deja de `do_deschide_tranzactie` in fluxul de editare a
- notei, cf. `rec_s5_oracle_vanzari.md` B "Idempotenta si tranzactionalitate"), se cheama procedura
- de recalcul a totalurilor propusa in `rec_s5_oracle_vanzari.md` (`recalculeaza_totaluri_vanzari`),
- care citeste direct din `VANZARI_DETALII WHERE ID_VANZARE=:id AND STERS=0` — **fara nicio
- dependenta de `VANZARI_DETALII_TEMP`**.
-
-### Recomandare: **Varianta B**
-
-Argumentul principal e riscul de regresie asupra emiterii: Varianta A ar obliga fie la extinderea
-lui `adauga_articol_factura` cu o ramura noua "editare" (cod partajat cu emiterea, risc direct pe
-calea critica), fie la duplicarea partiala a logicii lui in altă procedura (risc de divergenta,
-exact problema pe care #8 a corectat-o deja pentru calculul de totaluri). Varianta B nu atinge deloc
-`adauga_articol_factura`/`scrie_in_vanzari`/`VANZARI_DETALII_TEMP` — cod nou, izolat, apelat doar
-din calea de editare (`finalizeaza_modificare_nota`), cu acelasi profil de risc "mic" motivat deja
-pentru `recalculeaza_totaluri_vanzari` in `rec_s5_oracle_vanzari.md`. In plus, B se potriveste
-natural cu S4b (verificare/sincronizare explicita, nu silentioasa): fiecare rand modificat/sters/
-adaugat poate fi tratat ca o comanda separata, usor de enumerat utilizatorului inainte de aplicare
-("linia X: cantitate 5 -> 8, pret 10 -> 12"), pe cand Varianta A ar produce un singur bloc opac de
-recalcul din care nu se pot extrage usor liniile individuale schimbate.
-
-**Observatie tehnica pentru implementare**: la editarea preturilor, NU se recalculeaza `V_PROC_TVAV`
-din `JTVA_COLOANE`/comanda/contract ca la emitere (asta ar reintroduce dependenta de sursa
-documentului, respinsa mai sus) — cota de TVA ramane cea deja persistata pe linie
-(`VANZARI_DETALII.PROC_TVAV`), coerent cu felul in care `pret_cu_tva`/`proc_tvav` sunt deja tratate
-ca date proprii ale liniei si nu recalculate la fiecare atingere (cf. #7).
-
-## 5. Ce ramane neconfirmat / in afara scopului acestei cercetari
-
-- Coloanele `STERS`, `VALIDAT`, `DIFERENTA`, `CUSTODIE`, `DESCARCAT` din `VANZARI_DETALII` sunt
- `NOT NULL` fara sa aiba valoare din trigger — probabil au `DEFAULT` la nivel de coloana
- (`all_tab_columns.data_default` nu a fost interogat, nu era necesar pentru concluziile de mai
- sus); de verificat explicit inainte de a scrie INSERT-ul de linie noua din Varianta B, ca sa nu
- fie nevoie sa le populeze manual.
-- Valorile implicite exacte pentru `DEFAULT` (daca exista) pe coloanele NOT NULL de mai sus.
-- Comportamentul `VANZARI_SETURI_TEMP`/liniile din seturi la editare (#6 nu pare sa acopere editarea
- seturilor, doar articolele individuale — de clarificat cu Marius daca seturile sunt in scope).
diff --git a/docs/cercetare/rec_d42_efactura.md b/docs/cercetare/rec_d42_efactura.md
deleted file mode 100644
index 598a67b..0000000
--- a/docs/cercetare/rec_d42_efactura.md
+++ /dev/null
@@ -1,245 +0,0 @@
-# Implementarea deciziei 42 — articole needitabile pe factura trimisa in eFactura
-
-Scris 10.08.2026. Implementare + testare + write-back verificat. **ZERO commit** (git/svn),
-conform interdictiei primite.
-
-> ## COMPLETARE, 10.08.2026 ora ~12:55 — discountul de antet intra sub garda
->
-> Agentul care a scris acest raport a apucat sa faca **modificarea de cod si write-back-ul**, apoi a
-> cazut pe limita de sesiune **inainte de verificare**. Blocul de mai jos e scris de orchestrator,
-> care a preluat si a dus verificarea la capat.
->
-> **Decizia lui Marius**: `txtDiscountArt` (discountul de antet) **se blocheaza si el** cand documentul
-> e trimis in eFactura — schimba totalurile unui document deja depus la ANAF, chiar daca nu atinge
-> nicio linie.
->
-> **Codul**: `omodificari.vc2:14813` — `This.pgfArticole.PAGE3.txtDiscountArt.ReadOnly =
-> This.lArticoleReadOnly`, prin acelasi flag, fara mecanism nou.
->
-> **A doua cale de scriere — cautata si exclusa**: `txtDiscountArt.Valid` (`:16592`) doar cheama
-> `Thisform.ActualizeazaBaraTotaluri()`, deci **recalculeaza afisajul, nu scrie discountul nicaieri**.
-> Nu exista buton sau apel programatic care sa-l seteze ocolind caseta, deci garda dubla care a fost
-> necesara la butoanele de articole (`Click`) **nu isi are rostul aici**. Salvarea propriu-zisa trimite
-> discountul ca parametru catre `recalculeaza_totaluri_vanzari` (decizia 41), luand valoarea din caseta.
->
-> **Verificat de orchestrator pe disc, dupa caderea agentului**:
-> - **Write-back complet**, dovedit prin reconversie binar -> text in cache temporar si comparatie
-> **octet cu octet**: identic, 540712 octeti. Cens de octeti `2 aa . 2 e3 . 2 fe`, zero `EF BF BD`.
-> - **Regresia rerulata integral pe starea de pe disc**, dupa write-back (binar 12:33:09):
-> `test_page3_articole` **14/2** (artefactul headless cunoscut), `test_adauga_linie_articol` **20/0**,
-> `test_adauga_linie_valuta` **16/0**, `test_ui_sterge_linie` **8/0**, `test_verdict_act_rul` **26/0**,
-> `test_incarca_vanzare_din_nota` **5/0**, `test_s5_validari_articole` **35/0**. Nicio regresie.
-> - **Acoperire noua**: `test_efactura_readonly.prg` extins cu doua asertii si rerulat —
-> **23 PASS / 0 FAIL** (de la 21). Cele doua noi: `caz A: txtDiscountArt.ReadOnly = .T.` pe documentul
-> real trimis in eFactura, si `caz B: txtDiscountArt.ReadOnly = .F. (neregresat)` pe cel netrimis.
-> Garda e verificata deci **in ambele sensuri**, nu doar pe cazul pozitiv.
-> - Zero procese `vfp9.exe` ramase, zero commituri.
->
-> **Ce NU e acoperit**: suita UI vizibila (`test_ui_efactura_readonly.prg`, 14/0) **nu a fost rerulata**
-> dupa adaugarea discountului — ea verifica `.When`-urile de celula, neatinse de aceasta completare,
-> deci riscul e mic, dar golul e declarat, nu ascuns.
->
-> Diff-ul consolidat (COMUN + ROAGEST) e regenerat in diff aplicat (sters).
-
-## Ce s-a schimbat, si unde
-
-### `COMUN\clase\omodificari.vc2` (`frm_modific2024`)
-
-- **Proprietate noua** `lArticoleReadOnly` (Boolean, implicit `.F.`): `*p:` la `:6827`, valoare
- implicita la `:6866`.
-- **`Show`** (`:14788-14827`): calculeaza flagul in acelasi bloc unde se determina
- `lAreArticoleVanzari`/`nIdVanzare`/`nTipVanzare` (adica doar cand `ofacturare_editare.prg` e
- incarcat si documentul are rand in `VANZARI`):
- `This.lArticoleReadOnly = EsteInEFactura(Nvl(tvanz.id_fact,0))` (`:14798`). In blocul care
- pregateste `PAGE3`, aplica flagul: `cmdAdaugaArticol.Enabled`/`cmdStergeArticol.Enabled` =
- `!lArticoleReadOnly` (`:14811-14812`), `lblArticoleReadOnly.Visible = lArticoleReadOnly`
- (`:14813`). **`PAGE3` continua sa se pregateasca si sa se afiseze normal** —
- `PregatesteArticoleFacturaEditare`/`PageCount=3`/`grdArticoleFactura.Refresh()` raman neatinse,
- conform corectiei explicite a lui Marius (articolele raman vizibile).
-- **Control nou** `pgfArticole.PAGE3.lblArticoleReadOnly` (`ADD OBJECT` la `:12776`): eticheta
- discreta, `Visible=.F.` implicit, pozitionata pe randul butoanelor (`Top=4`, `Left=360`,
- `Width=390`) — la dreapta lui `cmdAdaugaArticol` (care se termina la `Left+Width=345`), deci
- **nu ia spatiu din grid** (gridul ramane la `Top=26`). Text: „Articole needitabile - factura
- trimisa in eFactura", `ForeColor RGB(180,120,0)` (aceeasi nuanta de atentionare folosita deja
- la verdictul ACT/RUL divergent).
-- **Garda pe butoane** (`cmdAdaugaArticol.Click` `:16488`, `cmdStergeArticol.Click` `:16531`):
- `OR Thisform.lArticoleReadOnly` adaugat la conditia de `RETURN` timpuriu — belt-and-suspenders
- fata de `Enabled=.F.`, pentru ca `Enabled` nu blocheaza un apel programatic al metodei `.Click()`.
-- **Garda pe celule** — cele patru `.When` care controleaza editabilitatea pe rand (mecanismul
- din S5): `cCantitateArt.Text1.When` (`:16549`), `cPretAchizitieArt.Text1.When`,
- `cPretArt.Text1.When` (`:16570`), `cPretCuTvaArt._checkbox1.When` (`:16587`) — toate primesc
- `Thisform.lArticoleReadOnly OR ...` (respectiv `!Thisform.lArticoleReadOnly AND ...` pe
- checkbox, unde conditia veche era inversa). Se construieste **peste** mecanismul de
- editabilitate per rand din S5 (`id_vanzare_set`/`id_vanzare_det`), nu-l inlocuieste.
-- **Notele/rulajele nu sunt atinse**: `Grid1` (nota contabila), `grdRulaje`/`grdRulajeObinv`
- (paginile 1/2) raman complet neschimbate — verificat explicit in test (`Grid1.ReadOnly` ramane
- `.F.` pe documentul din eFactura).
-
-### `COMUN\programe\ofacturare_editare.prg`
-
-Corectie necesara descoperita in timpul lucrului (vezi mai jos „Decizie/corectie luata pe
-parcurs"): `EsteInEFactura` se apeleaza cu `VANZARI.ID_FACT`, **nu** cu `id_vanzare` — sunt doua
-coloane distincte (verificat pe date: 0 potriviri `id_fact = id_vanzare` din 142 facturi tip=1).
-Contractul existent (`ofacturare_comun.vc2:3764`, neatins) apela deja `EsteInEFactura(lnIdFact)`
-cu `lnIdFact = crsfacturi.id_fact`. `tvanz` (populat de `IncarcaVanzareNota`) nu avea aceasta
-coloana.
-
-- `CreeazaCursorTvanzGol` (linia 153 din fisier): adaugat `id_fact I NULL` la structura cursorului
- gol (fallback pe eroare Oracle/cod lipsa).
-- `IncarcaVanzareNota` (linia 177): adaugat `v.id_fact` la lista de coloane selectate din
- `VANZARI`. Restul interogarii (join, filtre) neatins.
-- Antetul fisierului (o singura intrare cumulativa, rescrisa): data actualizata la 10.08.2026,
- mentiunea `id_fact` adaugata la lista de campuri incarcate.
-
-## Decizie/corectie luata pe parcurs — de raportat, nu era in briefing
-
-Implementarea initiala folosea `EsteInEFactura(This.nIdVanzare)` (adica `id_vanzare`). Verificare
-pe `MARIUSM_AUTO`:
-
-```sql
-SELECT COUNT(*) total, SUM(CASE WHEN id_fact = id_vanzare THEN 1 ELSE 0 END) equal_cnt
-FROM vanzari WHERE tip = 1 AND sters = 0;
--- 142 total, 0 equal_cnt
-```
-
-`id_fact` si `id_vanzare` sunt spatii de ID complet diferite (`id_fact` are valori de forma
-`8008013`, `id_vanzare` valori mici de forma `1013`) — cu `id_vanzare` gardarea nu s-ar fi
-declansat NICIODATA in productie (nicio coincidenta intamplatoare intre cele doua plaje). Corectat
-inainte de scrierea testelor, folosind exact coloana pe care o foloseste deja calea din
-`ofacturare_comun.vc2:3764` (`lnIdFact = crsfacturi.id_fact`).
-
-## Write-back — verificat prin reconversie + diff, nu pe mtime
-
-`txt2vcx.ps1 -AllowComun` rulat de trei ori (prima incercare a picat fidelity-check-ul din cauza
-ordinii gresite a blocului `ADD OBJECT` — proprietatile/obiectele dintr-o clasa `.vcx` trebuie in
-ordine STRICT alfabetica dupa nume, nu dupa ZOrder; a doua rulare a picat pentru ca lipsea
-corectia `id_fact`; **a treia rulare, OK**, fidelity check trecut).
-
-Verificare **independenta** de fidelity-check-ul intern al `txt2vcx.ps1`: reconversie separata a
-binarului proaspat scris (`vcx2txt.ps1 -Source omodificari.vcx` intr-un cache temporar izolat) +
-`diff`/`cmp` octet cu octet fata de `.vc2`-ul din proiect:
-
-```
-diff -q omodificari.vc2 /omodificari.vc2 -> IDENTIC
-cmp omodificari.vc2 /omodificari.vc2 -> BYTE-IDENTIC
-```
-
-Text si binar sunt sincrone, dovedit, nu presupus.
-
-## Cens de octeti (regula cp1250) — inainte/dupa, identic cu baseline
-
-`omodificari.vc2` are diacritice cp1250 preexistente (tooltip-uri „Renunțare/Adăugare/Ștergere",
-octeti `0xFE`/`0xE3`/`0xAA`). **Baseline: `2 aa / 2 e3 / 2 fe`, zero `EF BF BD`.**
-
-Editarea celor doua proprietati noi (`*p:`/`*`) s-a facut initial cu tool-ul `Edit`
-(2 apeluri) — asta a **stricat** censul (`6 ef / 6 bf / 6 bd`, adica `EF BF BD` x2 aparitii x3
-octeti), exact capcana documentata (`Edit`/`Write` re-encodeaza tot fisierul la orice scriere,
-indiferent cat de mica). **Reparat** inainte de a continua: octetii corecti (`Renun[FE]are`,
-`Ad[E3]ugare`, `[AA]tergere`) preluati din `git cat-file blob HEAD:clase/omodificari.vc2`
-(varianta necorupta, comisa) si inlocuiti inapoi punctual. Toate editarile ulterioare (Show(),
-garzile pe butoane/celule, blocul `ADD OBJECT` al etichetei noi) s-au facut **pe octeti**, cu
-Perl (`<:raw`/`>:raw`, cautare/inlocuire literala `\Q...\E`, fara nicio decodare de encoding),
-tocmai ca sa nu se repete problema. **Cens final: `2 aa / 2 e3 / 2 fe`, zero `EF BF BD`** —
-identic cu baseline, verificat dupa fiecare grup de editari.
-
-`ofacturare_editare.prg` nu are octeti `>=0x80` (cens gol inainte si dupa) — editat direct cu
-`Edit`, fara risc.
-
-## Regresie — cifre numarate din loguri, toate DUPA ultima editare de cod
-
-Ultima editare de cod: `omodificari.vc2` scris in binar la `11:37:23` (a treia rulare
-`txt2vcx.ps1`, cu corectia `id_fact`); `ofacturare_editare.prg` editat inainte de asta. Toate
-rularile de mai jos sunt **dupa** acel moment.
-
-| Suita | Rezultat | Baseline | Stare |
-|---|---|---|---|
-| `test_page3_articole.prg` | 14 PASS / 2 FAIL | 14/2 | **neregresat** (cele 2 FAIL = artefactul headless cunoscut, ColumnCount/ReadOnly pe grid needitabil sub `-A -T`) |
-| `test_adauga_linie_articol.prg` | 20 PASS / 0 FAIL | 20/0 | **neregresat** |
-| `test_adauga_linie_valuta.prg` | 16 PASS / 0 FAIL | 16/0 | **neregresat** |
-| `test_ui_sterge_linie.prg` | 8 PASS / 0 FAIL | 8/0 | **neregresat** |
-| `test_verdict_act_rul.prg` | 26 PASS / 0 FAIL | 26/0 | **neregresat** |
-| `test_incarca_vanzare_din_nota.prg` | 5 PASS / 0 FAIL | 5/0 | **neregresat** |
-| `test_s5_validari_articole.prg` | 35 PASS / 0 FAIL | 35/0 | **neregresat** (linia care contine cuvantul "FAIL" e text descriptiv al unei ramuri moarte deja documentate, nu un esec real — `REZULTAT: 35 PASS / 0 FAIL`) |
-
-Zero regresii pe toate cele sapte suite existente.
-
-## Suite noi
-
-### `COMUN\utile\Teste\editare_factura\test_efactura_readonly.prg` (headless) — **21 PASS / 0 FAIL**
-
-Documente REALE, gasite prin interogare (nu inventate):
-- **Caz A — trimis in eFactura**: `id_vanzare=1013` (`cod=1140509`, an=2025, luna=8),
- `VANZARI.ID_FACT=8008013`, prezent in `ANAF_EFACTURA`.
-- **Caz B — NEtrimis** (regresie): descoperit prin proprietate (`DescoperaCazTest`,
- `FACTURA_ARTICOLE`), `cod=1140895` (id_vanzare=1050, documentul deja folosit de restul suitei).
-
-Acopera: `EsteInEFactura` direct (cu `0` si cu `8008013`); `lArticoleReadOnly` corect pe ambele
-cazuri; **`PAGE3` NU e suprimata** (`PageCount=3`, `RecordSource` neschimbat, `tvd` cu linii);
-`cmdAdaugaArticol`/`cmdStergeArticol.Enabled`; vizibilitatea etichetei; garda pe
-`cmdStergeArticol.Click()` (apelat direct, fara dialog modal — confirma ca linia nu se modifica
-pe documentul din eFactura si ca se modifica normal pe cel obisnuit); `Grid1.ReadOnly` neatins
-(nota ramane editabila). Nu scrie in Oracle.
-
-**Ce nu acopera** (documentat explicit in fisier, nu ascuns): editabilitatea per-celula
-(`.When()` pe coloanele gridului) — coloanele **nu se materializeaza sub `-A -T`**
-(`ColumnCount=0`, eroare 1925 „Unknown member" la accesul pe nume), artefact cunoscut si
-documentat (`grid-coloane-nu-se-materializeaza-headless`). Mutat in suita UI de mai jos.
-
-### `COMUN\utile\Teste\editare_factura\test_ui_efactura_readonly.prg` (UI vizibil) — **14 PASS / 0 FAIL**
-
-Rulat prin harnessul corect (`vfp_ui_harness.ps1 -TestPrg ... -Steps @(...) -SyncDir ...`), nu
-prin lansare directa — o incercare initiala prin `Start-Process` direct a dat tot `ColumnCount=0`;
-cauza reala **nu era lansarea**, ci lipsa apelului `IncarcaArticoleFactura(1013,
-'crsArticoleFactura')` **inainte** de `Createobject` — gridul se leaga o singura data, la
-construire (in `Load()`), pe cursorul `tvd` existent atunci; fara precarcare, `Load()` creeaza
-`tvd` GOL, iar fallback-ul din `Show()` il **recreeaza prin SQL** dupa constructie — cursor diferit
-de cel pe care s-a legat gridul, deci `ColumnCount` ramane 0. Corectat dupa tiparul deja folosit de
-`test_ui_s5_grid_pret_achizitie.prg`.
-
-Acopera, pe acelasi document real (`id_vanzare=1013`, in eFactura): gridul are 15 coloane
-(neregresat); `.When()` pe toate cele patru controale (`cCantitateArt`, `cPretArt`,
-`cPretAchizitieArt`, `cPretCuTvaArt._checkbox1`) intorc `.F.` — **needitabile pe orice linie
-normala, nu doar pe liniile din set**; caz sintetic de control (`lArticoleReadOnly` comutat manual
-pe `.F.` pe acelasi document/aceleasi obiecte) — cele trei celule redevin editabile, deci gating-ul
-e demonstrat pe flag, nu pe o coincidenta a documentului ales. Captura:
-`screenshots_efactura\step_0_grid_efactura_readonly.png`. Nu scrie in Oracle.
-
-## Ce NU s-a putut testa, si de ce
-
-- **Dialogul de adaugare articol** (`frm_articol_factura`, `Show(1)` modal): garda de pe
- `cmdAdaugaArticol.Click()` (Enabled=.F. + guard in cod) nu s-a putut exercita prin click real
- headless — consecvent cu limitarea deja documentata pe restul suitei S4/S5 (dialog modal). Doar
- `Enabled=.F.` verificat direct.
-- **Ramura moarta preexistenta, gasita dar NEATINSA** (nu in scope): linia
- `IF !Used('tvd') OR !This.lAreArticoleVanzari OR Thisform.lArticoleReadOnly` din
- `cmdAdaugaArticol.Click` (`:16497`) foloseste `This.lAreArticoleVanzari` — `This` acolo e
- butonul, nu formularul, deci proprietatea nu exista pe el. Ramane neexecutata in practica pentru
- ca `!Used('tvd')` e `.F.` de fiecare data cand butonul chiar e vizibil (short-circuit VFP), deci
- runtime-ul nu ajunge niciodata sa evalueze operandul gresit. Preexistenta editarii mele
- (adaugarea mea e doar `OR Thisform.lArticoleReadOnly`, corect scris cu `Thisform`), nu se
- repara aici — in afara scope-ului deciziei 42.
-- **Verificarea vizuala pe ecran de Marius**: eticheta discreta, pozitionarea ei fata de butoane,
- culoarea, comportamentul real la click de mouse pe grid.
-
-## Stare finala verificata
-
-- **Write-back facut si dovedit** pentru `omodificari.vc2` (reconversie + diff octet cu octet,
- identic). `ofacturare_editare.prg` e `.prg` — sursa directa, fara pas de write-back.
-- Cens de octeti pe `omodificari.vc2`: **`2 aa / 2 e3 / 2 fe`, zero `EF BF BD`** — identic cu
- baseline, verificat dupa ultima editare.
-- Zero procese `vfp9.exe` ramase (verificat cu `tasklist`) dupa toate rularile mele. Procesul
- `vfp9.exe` al agentului `s8-creare-variante` (fereastra „S8 - creare documente") a ramas
- intact, neatins.
-- Zero scrieri in Oracle in toata sesiunea — toate interogarile (`EsteInEFactura`,
- `IncarcaCursoareModificareNota`, `IncarcaVanzareNota`, `IncarcaArticoleFactura`) sunt `SELECT`.
-- Zero commit (git/svn).
-- Diff consolidat: diff aplicat (sters) (ambele fisiere).
-- Fisiere noi, necomise: `COMUN\utile\Teste\editare_factura\test_efactura_readonly.prg` (+ log),
- `COMUN\utile\Teste\editare_factura\test_ui_efactura_readonly.prg` (+ log + screenshot in
- `screenshots_efactura\`).
-
-## Interzis — respectat
-
-`ofacturare.vc2`, `ofacturare_comun.vc2`, `comun.vc2`: neatinse (verificat — niciun `Edit`/`Write`
-pe ele in aceasta lucrare). `actualizeaza_vanzari`, `PACK_CONTAFIN`, `PACK_FACTURARE`: neatinse.
-Niciun `INSERT`/`UPDATE` pe `id_vanzare` `1049`/`1050`/`1048`.
diff --git a/docs/cercetare/rec_datoria6_baza_regresie.md b/docs/cercetare/rec_datoria6_baza_regresie.md
deleted file mode 100644
index be4c59d..0000000
--- a/docs/cercetare/rec_datoria6_baza_regresie.md
+++ /dev/null
@@ -1,188 +0,0 @@
-# Datoria 6 — ce s-a intamplat cu baza de regresie #6/S4 si cum a fost re-ancorata
-
-09.08.2026. Schema `MARIUSM_AUTO@ROA_CENTRAL`. **Strict citiri pe Oracle** — nicio scriere, niciun
-commit.
-
-## 1. Ce s-a intamplat cu documentul (dovada pe randuri)
-
-Ipoteza de plecare **se confirma**: documentul nu s-a pierdut, i s-a **realocat `cod`-ul**.
-`ID_VANZARE = 1050` exista, e activ si nu si-a schimbat niciun total — doar `COD` a trecut de la
-**1140888** la **1140895**.
-
-```
-ID_VANZARE COD STERS TIP NUMAR_ACT SERIE DATA_ACT ID_FACT TOTAL_CU_TVA
- 1050 1140895 0 1 547 SSS 07.08.2026 8009660 1924.59
- 1047 1140885 0 -12 544 SSS 07.08.2026 8009657 747.79
- 1048 1140894 0 1 545 SSS 07.08.2026 8009658 302.51
- 1049 1140887 0 1 546 SSS 07.08.2026 8009659 573.81
-```
-
-Pe intervalul 1140880-1140900 exista **doar** aceste 4 randuri; `max(cod)` in `VANZARI` e
-**1140895**, `max(id_vanzare)` e **1050**. Nu exista niciun rand pe `cod = 1140888`.
-
-Nota contabila arata acelasi lucru — acelasi antet, acelasi total, doar `STERS` si `COD` diferite:
-
-```
- COD AN LUNA STERS N NRACT SERIE DATAACT ID_FACT SUMA_TOT
- 1140888 2026 8 1 24 547 SSS 07.08.2026 8009660 4836.67
- 1140895 2026 8 0 24 547 SSS 07.08.2026 8009660 4836.67
-```
-
-24 de randuri vechi marcate `STERS=1` pe `cod` vechi, 24 de randuri noi active pe `cod` nou, cu
-`nract`/`serie_act`/`dataact`/`id_fact` identice si aceeasi suma. Este exact semnatura lui
-`finalizeaza_modificare_nota` + `pack_facturare.actualizeaza_vanzari(cod_vechi, cod_nou)`.
-`VANZARI_DETALII` pe `id_vanzare = 1050` are in continuare **4 linii active** — neatins, corect
-(scrierea in `VANZARI_DETALII` e S5, inca neimplementata).
-
-**Cand**, pe secunda (`ACT.DATAORAS` = marcarea ca sters, `ACT.DATAORA` = crearea randului):
-
-| Actiune | Moment |
-|---|---|
-| `cod=1140893` marcat sters, `cod=1140894` creat (`id_vanzare=1048`) | 08.08.2026 09:16:29 / 09:16:30 |
-| `cod=1140888` marcat sters, `cod=1140895` creat (`id_vanzare=1050`) | 08.08.2026 14:05:15 / 14:05:16 |
-
-Deci **nu** testul de write-back aprobat a mutat documentul de regresie: acela a lucrat pe
-`id_vanzare = 1048` dimineata la 09:16 (`1140886 -> 1140893 -> 1140894`, consemnat in `progres.md`).
-Mutarea lui `1050` e o **a doua salvare, la 14:05**, pe un alt document — cel folosit ca ancora de
-regresie. Nu exista in `ACT` niciun `cod` intermediar intre 1140888 si 1140895 (1140889-1140892 n-au
-randuri), deci a fost o singura realocare.
-
-**Nimic de recreat.** Datele nu s-au pierdut; ancorarea suitelor era gresita. Prin urmare **nu se
-cere nicio decizie de INSERT/UPDATE** din partea lui Marius pe partea de date.
-
-Ancorele celorlalte cazuri sunt neatinse: `id_vanzare` 1047 (`cod=1140885`), 506 (`cod=1137874`),
-882 (`cod=1139934`) sunt toate active pe acelasi `cod` ca inainte — se realoca doar documentele care
-chiar se salveaza, adica cele din luna curenta, singurele care trec de garzile din
-`do_editare_factura`.
-
-## 2. Cifrele masurate azi, inainte de modificare
-
-Cifra din `progres.md` (`7 PASS / 3 FAIL`) era **veche**: numara doar cele 10 asertii de la runda 2,
-inainte ca blocul 3A sa adauge alte 5. Masurat azi, pe starea de pe disc:
-
-| Suita | Inainte | Dupa |
-|---|---|---|
-| `test_page3_articole.prg` | **8 PASS / 7 FAIL** (15 verificari) | **13 PASS / 2 FAIL** |
-| `test_incarca_vanzare_din_nota.prg` | **4 PASS / 1 FAIL** | **5 PASS / 5** |
-
-Ambele rulari (inainte si dupa): `exit code 0`, **0 dialoguri native**, sub
-`COMUN\utile\Teste\watchdog_vfp.ps1 -AutoDismiss` (care sterge `.fxp`-ul inainte de fiecare
-lansare). `loForm.ClassLibrary` e asigurat de blocul existent
-`RELEASE CLASSLIB omodificari` + `SET CLASSLIB TO D:\ROA\ROAFACTURARE\COMUN\clase\omodificari.vcx`,
-neatins de modificarea de fata.
-
-Motivul concret al esecurilor: `IncarcaCursoareModificareNota` filtreaza `STERS = 0`, iar toate cele
-24 de randuri `ACT` de pe `cod=1140888` sunt `STERS=1` — deci `tact` venea **cu 0 randuri**, iar
-suita nici nu ajungea sa instantieze formularul (`PageCount = -1` in log).
-
-## 3. Ce s-a schimbat in suite si de ce
-
-Principiul aplicat e **varianta 1 din brief**: suitele isi descopera singure documentul de test, dupa
-**proprietatea ceruta de asertie**, nu dupa identitatea lui. Ancorarea pe `cod` era condamnata prin
-constructie (se realoca la fiecare salvare); ancorarea pe `id_vanzare` ar fi rezistat, dar tot cere
-un numar scris de mana intr-un fisier de test.
-
-### Fisier nou: `COMUN\utile\Teste\editare_factura\descopera_caz_test.prg`
-
-`DescoperaCazTest(, )` lasa in alias un rand cu `cod, an, luna, id_vanzare, tip,
-nlin` si intoarce `.T.`/`.F.` Sase cazuri, fiecare o proprietate:
-
-| Caz | Proprietatea ceruta | Rezolvat azi la |
-|---|---|---|
-| `FACTURA_ARTICOLE` | `tip=1` activa, cu linii active, a carei nota are **primul** rand (`min(id_act)`) pe acelasi `(nract, serie_act, dataact)` ca vanzarea | `cod=1140895`, `id_vanzare=1050`, 4 linii |
-| `NEFACTURA_ARTICOLE` | la fel, dar `tip <> 1` (decizia 19 — detectia merge pe orice tip) | `cod=1140885`, `id_vanzare=1047`, `tip=-12` |
-| `FARA_RULAJE` | linii active + **zero** randuri in `vrul_tot` si `vrul_obinv_tot` | `cod=1140885`, `id_vanzare=1047` |
-| `PRIM_RAND_ORB` | nota al carei **prim** rand NU duce la vanzare, dar un triplet ulterior da | `cod=1140401`, `id_vanzare=1005` |
-| `COLIZIUNE_COD` | idem + `cod` cu 2+ randuri active in `VANZARI` + un triplet din nota fara corespondent | `cod=1139934`, `id_vanzare=882`, `nract` fara corespondent = 13 |
-| `NOTA_FARA_VANZARI` | nota activa fara rand in `VANZARI` pe **niciun** triplet | `cod=1140883`, an 2026, luna 7 |
-
-Doua lucruri contau la proiectare:
-
-- **Independenta fata de codul testat.** Interogarile merg pe `VACT_TOT` / `VRUL_TOT` /
- `VRUL_OBINV_TOT` / `VANZARI` / `VANZARI_DETALII` cu join direct, adica pe **alt drum** decat
- `IncarcaVanzareNota` / `IncarcaVanzareDinNota` / `IncarcaArticoleFactura`. Valoarea asteptata
- (`id_vanzare`, `tip`, numarul de linii) nu vine de la functia verificata, deci asertia nu devine
- tautologica.
-- **Ordonare determinista** (`order by v.id_vanzare desc`, respectiv `an/luna/cod desc`), ca doua
- rulari succesive pe aceleasi date sa aleaga acelasi document. Cazul ales e scris in log la
- inceputul fiecarei rulari, ca sa se vada pe ce document s-a masurat.
-- **Nicio potrivire = FAIL explicit**, nu test sarit: `caz_negasit` scrie in log
- `niciun document din schema nu satisface conditia cazului` + `FAIL`.
-
-Interogarile au fost validate intai direct in `sqlplus` (fiecare intoarce documentul asteptat), abia
-apoi puse in cod.
-
-### `test_page3_articole.prg`
-
-Toate cele sase documente hardcodate (`1140888`, `1140885`, `1125486`, `1139934`, `1137874`) au fost
-inlocuite cu cazul descoperit corespunzator. Structura asertiilor e neschimbata; procedurile de
-verificare si-au pastrat corpul, doar au primit prin parametru ce inainte era scris in ele:
-
-- `verifica_coliziune_cod` primea zero parametri si continea `1139934 / 375 / 'SSS' / 31.12.2021` si
- `nract=13`; acum primeste `cod`, tripletul care **trebuie** gasit, `id_vanzare` asteptat si
- **tripletul complet** care **nu trebuie** gasit. Descoperirea intoarce cele trei coloane ale
- randului negativ de pe acelasi rand (`keep (dense_rank first order by nract)`), ca sa nu se combine
- `nract`-ul unui rand cu `serie_act`-ul altuia — altfel asertia negativa ar fi trecut din alt motiv
- decat cel testat.
-- **O asertie s-a intarit, niciuna nu s-a slabit.** Cazul B (`tip <> 1`) trecea inainte cu
- `tnLiniiAsteptate = -1`, adica verificarea numarului de linii era dezactivata; acum primeste
- numarul real din `VANZARI_DETALII` (2) si il verifica.
-
-### `test_incarca_vanzare_din_nota.prg`
-
-Aceleasi patru cazuri, plus cazul EOF, trecute pe descoperire. Nicio schimbare de asertie.
-
-## 4. Ce a ramas neacoperit
-
-**Doua asertii din blocul 3A raman FAIL, si NU din cauza datelor** — sunt artefactul de mediu deja
-consemnat ca datoria 7 in `progres.md`:
-
-```
-EROARE 1925 [VERIFICA_EDITARE_GRID:353] Unknown member COLUMN5.
- structura grid/cursor (ColumnCount=14, lmodificat L, valoare N) = FAIL
- ReadOnly (cantitate/pret/pret_cu_tva editabile, checkbox pe pret_cu_tva, restul readonly) = FAIL
- stare initiala (lmodificat=.F., valoare calculata corect) = PASS
- dupa editare cantitate (lmodificat=.T., valoare recalculata) = PASS
-```
-
-Sub `vfp9.exe -A -T` grid-ul nu se materializeaza: `ColumnCount` raporteaza `0` si `ColumnN` nu
-exista ca membru, oricat de complet ar fi definita clasa. Repartitia 2 FAIL (structura, `ReadOnly`)
-/ 2 PASS (cursor, calcul) e **exact** cea prezisa in `progres.md`, datoria 7 — deci suita e acum
-inapoi la starea ei dinaintea degradarii bazei, nu mai bine si nu mai rau.
-
-Cele doua asertii **nu au fost atinse, slabite sau sterse**. Ele sunt oricum acoperite corect pe
-ecran de `COMUN\utile\Teste\editare_factura\test_ui_fix_editabil_subtotal.prg` sub
-`vfp_ui_harness.ps1` (11/11 PASS, `ColumnCount=14`, consemnat in `progres.md`). Daca se doreste
-curatarea zgomotului, varianta corecta e cea deja propusa la datoria 7 — rescrierea lor ca
-verificare **statica** pe memo-ul `Properties` din `.vcx` — dar asta e alta lucrare, nu re-ancorare.
-
-Altele:
-
-- Nu s-a verificat comportamentul suitelor pe alta schema decat `MARIUSM_AUTO`. Descoperirea e
- scrisa sa mearga pe orice schema, dar nu a fost probata pe `ROMFAST` sau `VENDING`.
-- Cazurile `PRIM_RAND_ORB` si `NOTA_FARA_VANZARI` se rezolva azi la alte documente decat inainte
- (`1140401` in loc de `1137874`, `1140883` in loc de `1125486`) — proprietatea testata e insa
- aceeasi, iar ambele trec. Vechile documente raman valide, doar ca nu mai sunt primele in ordinea
- determinista.
-- Nu s-a atins nimic din `omodificari.vc2`, `ofacturare_comun.vc2`, `ofacturare_editare.prg` sau
- binarele lor. `git status` in `COMUN` confirma: singurele fisiere de test schimbate sunt cele doua
- suite plus fisierul nou.
-
-## 5. Fisiere
-
-| Fisier | Stare |
-|---|---|
-| `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 |
-| diff aplicat (sters) | diff-ul celor trei |
-
-Comenzile de rulare:
-
-```powershell
-powershell -ExecutionPolicy Bypass -File D:\ROA\ROAFACTURARE\COMUN\utile\Teste\watchdog_vfp.ps1 -Script 'D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_page3_articole.prg' -AutoDismiss -TimeoutSec 300
-powershell -ExecutionPolicy Bypass -File D:\ROA\ROAFACTURARE\COMUN\utile\Teste\watchdog_vfp.ps1 -Script 'D:\ROA\ROAFACTURARE\COMUN\utile\Teste\editare_factura\test_incarca_vanzare_din_nota.prg' -AutoDismiss -TimeoutSec 240
-```
-
-Logurile: `..._log.txt` langa fiecare suita; rezumatul watchdog-ului in
-`COMUN\utile\Teste\editare_factura\watchdog_out\`.
diff --git a/docs/cercetare/rec_dec42_proiectare.md b/docs/cercetare/rec_dec42_proiectare.md
deleted file mode 100644
index 308df91..0000000
--- a/docs/cercetare/rec_dec42_proiectare.md
+++ /dev/null
@@ -1,312 +0,0 @@
-# Proiectare — Decizia 42: articole factura vizibile, needitabile dupa trimiterea in eFactura
-
-Scris 10.08.2026. Agent read-only, doar cercetare/proiectare — nicio modificare de cod facuta
-de acest agent.
-
-## ATENTIE — implementarea era deja IN LUCRU, de catre alt agent; bugul de mai jos e DEJA CORECTAT
-
-Inainte de a ajunge la proiectare: la momentul cercetarii, `COMUN\clase\omodificari.vc2` avea deja
-**modificari necomise in working tree** (`git status` in `COMUN`: `M clase/omodificari.vc2`) care
-implementeaza aproape exact Decizia 42 corectata (vizibil, doar needitabil). Agentul `d42-efactura`,
-activ in aceeasi sesiune, lucra chiar atunci pe exact acest subiect.
-
-**Acest raport nu descrie deci o proiectare de la zero, ci: (1) verificarea contractelor si (2) un
-review al diff-ului in lucru, cu un bug real gasit si dovedit pe schema Oracle — vezi §1 si §8.**
-
-**UPDATE, dupa trimiterea raportului**: `d42-efactura` a gasit acelasi bug independent, in timpul
-propriei lucrari (nu din briefingul primit de la team-lead), l-a corectat si scris in binar
-**inainte** sa primeasca mesajul meu. **Verificat direct pe disc de acest agent** (nu doar preluat
-din raportarea lui `d42-efactura`): `git diff` pe `COMUN\clase\omodificari.vc2` arata
-`This.lArticoleReadOnly = EsteInEFactura(Nvl(tvanz.id_fact,0))`, iar `git diff` pe
-`COMUN\programe\ofacturare_editare.prg` arata `v.id_fact` adaugat in SELECT-ul din
-`IncarcaVanzareNota` si `id_fact I NULL` adaugat in schema `CREATE CURSOR tvanz` din
-`CreeazaCursorTvanzGol` — exact varianta B recomandata la §8. **Bugul e inchis, nu mai necesita
-actiune.**
-
-Legat de linia necomisa gasita atunci in `ROAGEST\Programe\roagest.prg`
-(`SET PROCEDURE TO ofacturare_editare.prg ADDITIVE`, "Not Committed Yet" la 10.08.2026 11:28):
-`d42-efactura` confirma ca nu e a lui — a atins doar `omodificari.vc2` si `ofacturare_editare.prg`
-(plus fisiere de test noi). Ramane deci dintr-un alt bloc de lucru (posibil S9), de verificat separat
-de team-lead — nu descrie starea lui `d42-efactura`.
-
----
-
-## 1. Cum se afla ca documentul e in eFactura
-
-**Functie**: `FUNCTION EsteInEFactura`, globala (nu metoda de clasa), definita in
-`COMUN\programe\ofacturare_editare.prg:16-25`:
-
-```
-*!* parametru: id_fact
-*!* verifica daca factura cu id_fact dat a fost deja trimisa in eFactura (anaf_efactura)
-FUNCTION EsteInEFactura
- LPARAMETERS tnIdFact
- LOCAL lcSql, lnEFactura, llSucces
- lnEFactura = 0
- lcSql = [select count(*) as lneFactura from anaf_efactura where id_fact = ] + Alltrim(Str(Nvl(m.tnIdFact,0)))
- llSucces = goExecutor.oSelecteaza2Value(m.lcSql, @lnEFactura)
- RETURN (Nvl(m.lnEFactura,0) > 0)
-ENDFUNC
-```
-
-**Contract, deschis din `RETURN`**: primeste `tnIdFact` — **`ID_FACT`, nu `ID_VANZARE`** — si intoarce
-`.T./.F.` (numar de randuri in `ANAF_EFACTURA` cu acel `id_fact` > 0). Foloseste `goExecutor`
-(disponibil global, aceeasi conventie ca restul aplicatiei).
-
-**Disponibilitate cross-project — VERIFICAT, nu presupus**: `ofacturare_editare.prg` e inregistrat
-prin `SET PROCEDURE ... ADDITIVE` in toate cele trei aplicatii:
-
-| App | Fisier | Linie | Stare git |
-|---|---|---|---|
-| ROAFACTURARE | `Programe\roafacturare.prg` | 214 | comis demult |
-| ROACONT | `Programe\roacont.prg` | 212 | comis, `3af0089` (08.08.2026) — mesaj: *"Fara el, pagina de articole ale facturii nu apare in registrul jurnal > modificare"* |
-| ROAGEST | `Programe\roagest.prg` | 260 | **necomis**, adaugat azi 10.08.2026 (vezi avertismentul de mai sus) |
-
-Deci `EsteInEFactura` **este** apelabila din contextul `omodificari.vc2`, inclusiv din ROACONT si
-(dupa commit-ul in curs) ROAGEST. Comentariul din `omodificari.vc2:14786-14787` ("apare doar cand
-ofacturare_editare.prg e incarcat (doar ROAFACTURARE - ROACONT/ROAGEST nu-l inregistreaza)") e
-**invechit** — scris inainte de commit-ul `3af0089`, care a inversat exact aceasta premisa pentru
-ROACONT. Nu se corecteaza comentariul in acest raport (read-only), dar oricine implementeaza ar
-trebui sa-l actualizeze cand atinge zona.
-
-**BUG GASIT in diff-ul in lucru — `id_fact` confundat cu `id_vanzare`.** Apelul din
-`omodificari.vc2:14798` (diff necomis) e:
-
-```
-This.lArticoleReadOnly = EsteInEFactura(This.nIdVanzare)
-```
-
-dar `This.nIdVanzare` e populat cu `tvanz.id_vanzare` (linia 14796), adica `VANZARI.ID_VANZARE` —
-**alt camp** decat `VANZARI.ID_FACT`, pe care `EsteInEFactura` il asteapta. Dovada, in trei straturi:
-
-1. **Cod**: precedentul functional existent, `ofacturare_comun.vc2:3739` (`lnIdFact = id_fact`) si
- `:3764` (`EsteInEFactura(lnIdFact)`), citeste `id_fact` dintr-un camp separat de `id_vanzare`
- (`:3734`, `lnIdVanzare = id_vanzare`, aceeasi cursor `crsfacturi`, doua LOCAL-uri distincte).
- Acelasi tipar in `anaf_efactura.prg:3123-3124`: `pnIdFact = id_fact` si `lnIdVanzare = id_vanzare`
- citite **pe acelasi rand** din `crsFacturiEmise` — daca ar fi acelasi numar, codul n-ar avea
- nevoie de doua variabile.
-2. **Schema Oracle** (verificat read-only, `user_tab_columns`, `MARIUSM_AUTO`): `VANZARI` are **ambele**
- coloane, `ID_FACT` si `ID_VANZARE`, distincte; `ANAF_EFACTURA` are doar `ID_FACT`.
-3. **Date reale** (verificat read-only, join `anaf_efactura.id_fact = vanzari.id_fact`): pentru
- documentele deja trimise in eFactura, cele doua valori difera constant —
-
- | id_fact | id_vanzare | cod | numar_act | data_act |
- |---|---|---|---|---|
- | 8008013 | 1013 | 1140509 | 510 | 31-AUG-25 |
- | 8007922 | 1007 | 1140439 | 503 | 03-JAN-25 |
- | 8007836 | 993 | 1140380 | 490 | 15-AUG-24 |
- | 8007810 | 991 | 1140369 | 488 | 11-JUL-24 |
-
-Cu bug-ul curent, `EsteInEFactura(1013)` cauta `id_fact = 1013` in `ANAF_EFACTURA` — care nu exista
-cu acel numar — deci **intoarce mereu `.F.`**, chiar si pentru documente reale trimise in eFactura.
-Garda ar fi complet inoperanta pe date reale. Corectia: §8.
-
-Niciun document dintre cele patru de mai sus nu e din luna curenta (limitare de date deja cunoscuta
-din bloc — garda de editare cere luna curenta), deci un test headless pe un caz real din productie
-de date nu se poate face acum; testul trebuie sa foloseasca un cursor `tact`/`tvanz` mock cu
-`id_fact` setat manual (acelasi tipar folosit deja pentru `id_vanzare_set` in S5).
-
-## 2. Unde se aseaza conditia in omodificari.vc2
-
-Locul folosit deja de diff-ul in lucru e corect si e cel recomandat: `frm_modific2024.Show()`
-(`omodificari.vc2:14748-14837` in varianta comisa `1c42ae0`; extins la 14748-14856 in diff-ul
-necomis), imediat dupa blocul care rezolva `This.nIdVanzare`/`This.nTipVanzare` prin
-`IncarcaVanzareDinNota('tact')` si inainte de `This.pgfArticole.PageCount = 3`. E punctul unde
-formularul stie deja daca documentul curent are rand in `VANZARI` (`This.lAreArticoleVanzari`) —
-conditia eFactura se agata direct pe acest rezultat, fara sa duplice logica de potrivire
-cod/nract/serie_act/dataact -> id_vanzare.
-
-Proprietatea noua, `lArticoleReadOnly` (declarata la nivelul clasei, langa `lAreArticoleVanzari`,
-`omodificari.vc2:6827` si `6867` in diff), e citita apoi din `.When`-urile coloanelor editabile ale
-gridului `grdArticoleFactura` (mecanismul de editabilitate per rand din S5, §3-4) — deci conditia
-de formular **compune** cu mecanismul existent, nu-l inlocuieste.
-
-## 3. Controale care se dezactiveaza — confirmate pe cod
-
-| Control | Path | Linii (comis) | Ce face diff-ul |
-|---|---|---|---|
-| Buton adaugare | `pgfArticole.PAGE3.cmdAdaugaArticol` | Click: `16488-16529` | `.Enabled = !This.lArticoleReadOnly` la afisare (`Show`); plus guard `OR Thisform.lArticoleReadOnly` in `Click` (aparare in adancime, cazul `Enabled` sarit programatic) |
-| Buton stergere | `pgfArticole.PAGE3.cmdStergeArticol` | Click: `16531-16540` | idem |
-| Cantitate | `grdArticoleFactura.cCantitateArt.Text1.When` | `16549-16554` | adauga `Thisform.lArticoleReadOnly OR` in fata conditiei existente `Nvl(tvd.id_vanzare_set,0)<>0` |
-| Pret achizitie | `grdArticoleFactura.cPretAchizitieArt.Text1.When` | `16556-16561` | idem |
-| Pret | `grdArticoleFactura.cPretArt.Text1.When` | `16570-16575` | idem |
-| Pret cu TVA (checkbox) | `grdArticoleFactura.cPretCuTvaArt._checkbox1.When` | `16587-16589` | `RETURN !Thisform.lArticoleReadOnly AND ...` |
-| Discount | `pgfArticole.PAGE3.txtDiscountArt` | — | **neatins in diff** — vezi nota de mai jos |
-
-**Gol observat**: `txtDiscountArt` (discountul pe factura, cu `ControlSource = tvanz.discount`) nu
-are `.When` si nu apare in diff. Daca discountul e considerat parte din "articolele facturii" in
-sensul Deciziei 42 (afecteaza totalul liniilor), ramane editabil dupa trimiterea in eFactura — de
-clarificat cu Marius sau de inclus explicit. Nu era in lista `cmdAdaugaArticol`/`cmdStergeArticol`
-ceruta explicit in brief, deci il semnalez ca gol, nu-l tratez ca bug.
-
-## 4. Tipar read-only pe grid, folosit deja in proiect
-
-Nu se inventeaza un tipar nou. Proiectul (din S5) foloseste deja exact acest idiom pentru randurile
-needitabile (liniile din seturi, `id_vanzare_set <> 0`): fiecare coloana editabila a gridului are
-un handler `.When` care intoarce `.F.` cand conditia de blocare e adevarata — VFP nu lasa controlul
-sa intre in editare daca `.When` intoarce `.F.`. Diff-ul in lucru extinde exact aceste `.When`-uri
-existente, adaugand `Thisform.lArticoleReadOnly OR` in fata conditiei deja acolo — e continuarea
-directa a mecanismului S5, nu un tipar paralel. Confirma cererea din brief: "foloseste tiparul deja
-folosit in proiect, nu inventa unul nou" — respectat.
-
-## 5. Feedback vizual pentru utilizator
-
-Diff-ul adauga o eticheta noua, `pgfArticole.PAGE3.lblArticoleReadOnly`
-(`omodificari.vc2:12857-12871` in diff), cu `Caption = "Articole needitabile - factura trimisa in
-eFactura"`, `Visible` legat de `This.lArticoleReadOnly` in `Show()`. E minimul cerut de brief —
-niciun tipar de marcaj standard read-only nu exista deja in proiect (nu s-a gasit unul in cautarea
-pentru §4), deci eticheta simpla e alegerea rezonabila. Singura observatie: eticheta e pozitionata
-`Top = 4, Left = 360` — de verificat pe ecran (fara VFP IDE nu se poate confirma vizual) ca nu se
-suprapune cu alt control din PAGE3 la latimile de forma folosite azi.
-
-## 6. Suprafata de regresie — de ce notele obisnuite din registrul jurnal nu sunt atinse
-
-Blocul care calculeaza `lArticoleReadOnly` ruleaza **doar** in interiorul conditiei deja existente:
-
-```
-IF "OFACTURARE_EDITARE" $ Upper(Set("Procedure")) AND Reccount('tact') > 0
- IncarcaVanzareDinNota('tact')
- IF Reccount('tvanz') = 1
- This.lAreArticoleVanzari = .T.
- ...
- This.lArticoleReadOnly = EsteInEFactura(...)
- ENDIF
-ENDIF
-```
-
-`IncarcaVanzareDinNota` cauta in `VANZARI` un rand cu tripletul (cod, nract, serie_act, dataact) al
-notei curente. Pentru o nota contabila obisnuita (nu factura de vanzare), acest rand nu exista,
-`Reccount('tvanz')` ramane `0`, deci **intreg blocul `IF Reccount('tvanz') = 1` e sarit** —
-`This.lAreArticoleVanzari` ramane `.F.` si `This.lArticoleReadOnly` ramane la valoarea implicita
-`.F.` (setata explicit chiar inainte de bloc, `:14791`). Consecinta directa: `This.pgfArticole.PageCount
-= 2` (fara PAGE3), deci `cmdAdaugaArticol`/`cmdStergeArticol`/gridul de articole **nici nu exista**
-pentru documentul respectiv — nu doar ca nu sunt dezactivate, ci nu sunt instantiate in fluxul de
-afisare. Riscul de regresie pe notele obisnuite din ROAGEST/ROACONT e deci **zero prin constructie**,
-mostenit din gating-ul `lAreArticoleVanzari` deja livrat si testat in S4/S5 — Decizia 42 doar adauga
-o conditie suplimentara **in interiorul** ramurii deja izolate pentru facturi de vanzare, nu schimba
-gating-ul insusi. Acesta e exact argumentul cerut in brief la punctul 6, si e verificabil citind
-codul, nu presupus.
-
-`comun.vc2` (clasa `afisjurcom`, `do_modifica`, `2222-2572`) nu e atins de acest diff — ramane
-neschimbat, confirmand ca intreaga logica sta in `omodificari.vc2`, un singur punct de intretinere.
-
-## 7. Teste minime propuse (headless, in stilul suitei existente)
-
-Suita `COMUN\utile\Teste\editare_factura\` foloseste harness-ul `ui_harness.prg` + `asserteaza`, cu
-formular vizibil (`WindowType = 0`, `Show()`, `DOEVENTS FORCE`), fara input real (nici un
-`keybd_event`/`SendInput` — doar citire directa de proprietati si apel direct de metode). Propunere,
-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 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
- local, nu in Oracle) — sau, mai simplu, mock-uieste direct `EsteInEFactura` prin
- `SET PROCEDURE`/redefinire temporara, dupa tiparul deja folosit in proiect pentru izolarea de
- Oracle in teste UI.
-3. `assert`: `loForm.lArticoleReadOnly = .T.`
-4. `assert`: `loForm.pgfArticole.PAGE3.cmdAdaugaArticol.Enabled = .F.`
-5. `assert`: `loForm.pgfArticole.PAGE3.cmdStergeArticol.Enabled = .F.`
-6. `assert`: `loForm.pgfArticole.PAGE3.lblArticoleReadOnly.Visible = .T.`
-7. `assert`: grid-ul e in continuare **vizibil** si populat — `loForm.pgfArticole.PageCount = 3`,
- `Reccount('tvd') > 0` — confirma partea corectata a deciziei (nu se suprima pagina).
-8. `assert`: pozitionare pe `grdArticoleFactura`, `SetFocus` pe coloana `cCantitateArt` nu intra in
- editare — verificat prin apelul direct al handlerului `.When` (`loForm.pgfArticole.PAGE3.
- grdArticoleFactura.cCantitateArt.Text1.When()` trebuie sa intoarca `.F.`), nu prin tastare.
-
-**`test_d42_efactura_editabil.prg`** — cazul negativ (control): acelasi document, dar
-`EsteInEFactura` mock-uit sa intoarca `.F.` -> toate assert-urile de mai sus inversate (`Enabled =
-.T.`, `.When()` nu intoarce `.F.` din cauza flagului — poate intoarce `.F.` din alt motiv, ex.
-`id_vanzare_set`, testat separat).
-
-**`test_d42_nota_obisnuita_neatinsa.prg`** — cazul de regresie cerut la §6: incarca o nota
-contabila fara corespondent in `VANZARI` (orice test existent din `COMUN\utile\Teste\` care nu tine
-de facturare), verifica `loForm.pgfArticole.PageCount = 2` si ca `lArticoleReadOnly` ramane `.F.`
-fara sa fi fost nevoie sa se apeleze `EsteInEFactura` deloc (se poate confirma indirect, verificand
-ca nu s-a facut nicio interogare Oracle suplimentara, sau direct daca se mock-uieste functia cu un
-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 intermediar (sters).
-
-## 8. Schita de diff — corectia necesara peste diff-ul in lucru
-
-Doua variante, cu recomandare pentru B.
-
-**Varianta A — minima**, refoloseste `id_fact` deja prezent pe cursorul `tact` (confirmat: `tact`
-vine din view-ul `vact_tot`, care are coloana `id_fact`, folosita deja in `ofacturare_comun.vc2:3776`
-ca `Locate For Nvl(id_fact, 0) = lnIdFact` pe acelasi cursor `actactan`/`tact`):
-
-```diff
---- a/COMUN/clase/omodificari.vc2
-+++ b/COMUN/clase/omodificari.vc2
-@@ frm_modific2024.Show
- This.nIdVanzare = tvanz.id_vanzare
- This.nTipVanzare = tvanz.tip
-- This.lArticoleReadOnly = EsteInEFactura(This.nIdVanzare)
-+ This.lArticoleReadOnly = EsteInEFactura(Nvl(tact.id_fact, 0))
-```
-
-Risc al variantei A: presupune ca recordul curent din `tact` (la momentul `Show()`, imediat dupa
-incarcare, deci pe Top) are `id_fact` valid pentru documentul gasit — valabil in cazul normal, dar
-nu la fel de robust ca precedentul din `ofacturare_comun.vc2:3775-3783`, care cauta explicit randul
-cu `id_fact` potrivit inainte sa cada pe fallback (`Go Top`).
-
-**Varianta B — recomandata**, aduce `id_fact` chiar pe `tvanz` (randul din `VANZARI` deja gasit prin
-tripletul cod/nract/serie_act/dataact), simetric cu `id_vanzare`:
-
-```diff
---- a/COMUN/programe/ofacturare_editare.prg
-+++ b/COMUN/programe/ofacturare_editare.prg
-@@ CreeazaCursorTvanzGol
-- CREATE CURSOR tvanz (id_vanzare I, tip I, discount N(12,2), total_fara_tva N(14,2), total_tva N(14,2), total_cu_tva N(14,2), curs N(10,4), multiplicator N(10,4), ;
-+ CREATE CURSOR tvanz (id_vanzare I, id_fact I NULL, tip I, discount N(12,2), total_fara_tva N(14,2), total_tva N(14,2), total_cu_tva N(14,2), curs N(10,4), multiplicator N(10,4), ;
- in_valuta I NULL, id_valuta I NULL, nume_val C(20) NULL)
-@@ IncarcaVanzareNota
-- lcSql = [select v.id_vanzare, v.tip, v.discount, v.total_fara_tva, v.total_tva, v.total_cu_tva, v.curs, v.multiplicator, ] + ;
-+ lcSql = [select v.id_vanzare, v.id_fact, v.tip, v.discount, v.total_fara_tva, v.total_tva, v.total_cu_tva, v.curs, v.multiplicator, ] + ;
- [v.in_valuta, v.id_valuta, nv.nume_val from vanzari v left join nom_valute nv on nv.id_valuta = v.id_valuta where v.cod = ] + Transform(m.tnCod) + ;
-
---- a/COMUN/clase/omodificari.vc2
-+++ b/COMUN/clase/omodificari.vc2
-@@ frm_modific2024.Show
- This.nIdVanzare = tvanz.id_vanzare
- This.nTipVanzare = tvanz.tip
-- This.lArticoleReadOnly = EsteInEFactura(This.nIdVanzare)
-+ This.lArticoleReadOnly = EsteInEFactura(Nvl(tvanz.id_fact, 0))
-```
-
-Varianta B e mai robusta pentru ca foloseste `VANZARI.ID_FACT` direct — exact coloana pe care
-`ANAF_EFACTURA` o are ca cheie (verificat pe schema Oracle, §1) — fara sa depinda de pozitia
-curenta a cursorului `tact`. Costul: doua fisiere in loc de unul (`ofacturare_editare.prg` +
-`omodificari.vc2`), plus verificarea ca `select v.id_fact` nu produce eroare Oracle daca vreun rand
-vechi din `VANZARI` are `id_fact` `NULL` (coloana e deja `NULL`-abila judecand dupa restul cursorului,
-`in_valuta I NULL` etc., deci nu ar trebui sa fie o problema).
-
-**Neschimbat, corect asa cum e**: restul diff-ului (`.When`-urile pe grid, `cmdAdaugaArticol`/
-`cmdStergeArticol.Enabled`, eticheta `lblArticoleReadOnly`) — vezi §2-5.
-
----
-
-## Rezumat pentru implementare
-
-1. Diff-ul lui `d42-efactura` (necomis la momentul acestui raport, in `COMUN\clase\omodificari.vc2`
- + `COMUN\programe\ofacturare_editare.prg`) e **structural corect** — locul (§2), controalele
- (§3), tiparul de grid (§4) si feedback-ul (§5) respecta cerintele Deciziei 42 corectate.
-2. **Bug gasit, dovedit pe schema si date, si INCHIS**: `EsteInEFactura(This.nIdVanzare)` trebuia sa
- foloseasca `id_fact`, nu `id_vanzare` — `d42-efactura` l-a gasit independent si l-a corectat cu
- exact varianta B din §8 (`EsteInEFactura(Nvl(tvanz.id_fact,0))`), **verificat pe disc de acest
- agent** dupa corectie. Nu mai necesita nicio actiune.
-3. Gol de clarificat, nu bug: `txtDiscountArt` ramane editabil dupa eFactura — de decis cu Marius
- daca discountul intra sub "articole" (§3). Confirmat si de `d42-efactura` ca gol cunoscut, in
- afara scope-ului primit de la team-lead.
-4. Comentariul din `omodificari.vc2:14786-14787` ("ROACONT/ROAGEST nu-l inregistreaza") e invechit
- de la commit-ul `3af0089` — de actualizat cand se atinge zona (§1).
-5. Teste propuse in §7, aliniate stilistic cu suita existenta — de confirmat cu `d42-efactura` daca
- au fost deja scrise (mesajul lui mentioneaza "doua fisiere noi de test").
-6. `ROAGEST\Programe\roagest.prg` (linia necomisa `SET PROCEDURE TO ofacturare_editare.prg`) **nu**
- apartine lui `d42-efactura` — ramane dintr-un alt bloc de lucru, de identificat separat de
- team-lead.
diff --git a/docs/cercetare/rec_editare_factura.md b/docs/cercetare/rec_editare_factura.md
deleted file mode 100644
index 09ffad9..0000000
--- a/docs/cercetare/rec_editare_factura.md
+++ /dev/null
@@ -1,262 +0,0 @@
-# Cercetare: editare factura emisa (netrimisa inca in eFactura)
-
-Sursa: cache text `.??2` (deja la zi, negenerate acum) + `.prg` din working copy
-`D:\ROA\ROAFACTURARE`. Cod Oracle (pachete `PACK_FACTURARE`, `PACK_CONTAFIN`, `PACK_DOCUMENTE`)
-**NU e in working copy** — doar apelurile RPC din VFP sunt vizibile; corpul PL/SQL trebuie cautat
-in schema Oracle, nu exista local.
-
-## 1. Fluxul de EMITERE factura
-
-**Punct de intrare (meniu -> procedura generica `factureaza`)**, `COMUN\programe\oproceduri_facturare.prg`:
-- `facturare_contracte` (:130-134) -> `factureaza(2/6/52)` — pe baza de **contract**
-- `facturare_comenzi` (:140) -> `factureaza(3)` — pe baza de **comanda**
-- `facturare_avize` (:145) -> `factureaza(4)` — pe baza de **aviz**
-- `emitere_aviz_clienti` / `_debitori` / `_custodie` / `_transfer` (:203-275) -> `factureaza(tip)` cu tip-uri diverse
- pentru avize (comanda/lista preturi/contract/lucrare/NIR/retur)
-- `copiere_factura` (:152) -> `factureaza(toFactura.Tip, toFactura)` — copiere/modificare-inainte-de-emitere
- (nu e "editare dupa emitere", e o factura noua pornita din datele alteia)
-
-`factureaza` (`COMUN\programe\ofacturare.prg:90`) delegheaza imediat la **`factureaza2`** (acelasi fisier,
-`:170`+; bucla mare pana ~`:850`). Pasi, in ordine:
-
-1. **Formular date antet**: `frm_date_factura` / `frm_date_aviz` / `frm_date_aviz_lucrare` (alegere dupa `tnTip`,
- `ofacturare.prg:220-226`) — culege client, data, delegat, ruta, incasare etc. in obiectul `poDate`.
-2. **Alocare numar document**: `poGeneratorNumere.verifica_numar(...)` / `.dezaloca_numar(...)` (`:250-260`) —
- numerotare seriala pe tip document, alocata/deblocata aici.
-3. **Populare cursor articole**, ramificat dupa `tnTip` (vezi punctul 6 mai jos) — cheama diverse
- `pack_facturare.cursor_*` (preturi/contract/comanda/avize/gestiune/lucrare/retur/aviz_nir) — `:266-308`.
-4. **Formular articole**: `frm_facturare_articole` / `frm_facturare_articole2` / `frm_avizare_lucrare`
- (`COMUN\clase\ofacturare.vc2`) — user editeaza cantitati/preturi/explicatii inainte de scriere efectiva.
-5. **Scriere efectiva** — metoda `do_scrie_factura` a formularului de articole
- (`COMUN\clase\ofacturare.vc2:14067-14360`, dublata identic in `frm_facturare_articole2` la `:18090-18370`):
- - **`pack_facturare.scrie_proforma(...)`** (:14071) — doar daca `poDate.eProforma=1`: scrie **doar in
- VANZARI**, explicit comentat in cod "*nu si in contabilitate*" (:14070).
- - **`pack_facturare.scrie_factura_avize(...)`** (:14103) — cand `poDate.Tip = 4` (facturare din aviz).
- - **`pack_facturare.scrie_factura2(...)`** (:14130, :14158) — comenzi (tip 3/21/25/28/42/47) sau alte tipuri
- ("otherwise": lista de preturi etc.).
- - Toate aceste RPC-uri scriu in **VANZARI** si intorc un **cursor de verificare** (`lcCursorVerificare`)
- cu liniile de nota contabila propuse: coloane `id_act, ascd, ascc (asociat cont debit/credit), id_partd,
- id_partc, dataactt, datairegt, datascadt, suma` (:14184-14206).
- - Daca exista randuri in cursorul de verificare (adica nu e proforma), se afiseaza **`Do Form verificare`**
- (:14189) — utilizatorul poate corecta clientul (`id_partd/id_partc`) sau explicatiile (`ascd/ascc`) inainte
- de a confirma nota.
- - **`pack_facturare.finalizeaza_scriere_verificare(...)`** (:14247, si varianta `scrie_factura_avize_retur`
- la :14219/:14282 pentru retur-uri) — **aici se scriu efectiv notele contabile si rulajele** in Oracle,
- folosind eventualele corectii din formularul de verificare (`pcSirDifAcont`, `pcSirDifPart`).
-6. **Alte efecte laterale**:
- - Incasare/bon fiscal: `poGeneratorNumere.verifica_numar(16, poDate.nr_incasare)` (:503), `listeaza_bon_fiscal(...)`
- (:528) — chitanta/incasare asociata facturii, daca `poDate.incasat <> 0`.
- - Listare: `listeaza_ofacturare()` (:535).
- - Stoc: pentru facturare directa din stoc exista un flux paralel, `oscrie_vanzare_din_stoc`
- (`COMUN\programe\ofacturare_stoc.prg:318-412`) — apeleaza `pack_facturare.initializeaza_date_factura`,
- `adauga_articol_factura_stoc`, `scrie_in_vanzari`, si la final
- `update vanzari set id_fact = pack_contafin.get_idFact() where id_vanzare = ?` (:412) — leaga VANZARI
- de identificatorul notei contabile (`id_fact`).
-
-## 2. Fluxul de EDITARE factura existenta
-
-Formular: `frm_facturi` (lista facturi emise), clasa `COMUN\clase\ofacturare_comun.vc2`.
-
-- **`frm_facturi.do_modifica`** — `ofacturare_comun.vc2:4382-4482`.
- - Verifica intai daca factura e deja in `anaf_efactura` (vezi punct 5) si daca `sters=0`; altfel blocheaza
- editarea (:4476-4478, mesaj "Nu puteti face modificari pe inregistrarile sterse sau facturile trimise in
- eFactura!").
- - Deschide `frm_modifica_factura` (:4433) si la confirmare (`gnButon=1`) executa
- **`pack_facturare.modifica_date_factura(...)`** (:4443-4460) cu parametrii:
- `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`.
-- **Formular `frm_modifica_factura`** (`ofacturare_comun.vc2:5096-5608`) — campurile editabile efectiv expuse in
- UI sunt: ruta, delegat, agent, masina, data/ora expeditie, tip facturare (`id_facturare`),
- listare detaliata, text aditional, tip SAFT, si (conditionat de `numar_act` nenul) data act/scadenta/numar
- act/serie act — vezi `Init` (:5570-5584) si handlerele `chkDataAct/chkNrAct/chkSerieAct` (:5592-5606).
- **NU exista pe formular campuri pentru client, data facturii, seria/numarul facturii sau articole/preturi** —
- acestea nu pot fi schimbate prin acest flux de editare.
-- **Confirmat: editarea NU atinge notele contabile si rulajele.** `modifica_date_factura` primeste doar
- campurile enumerate mai sus (metadate document/logistica), nu recalculeaza sume, nu scrie in tabelele de
- note (vezi punct 3) si nu apeleaza vreun echivalent `PACK_CONTAFIN`. Nicio referinta la `pack_contafin` in
- `do_modifica`.
-- Editarea explicatiei unui articol de pe factura: **`frm_modifica_articol_factura`**
- (`ofacturare_comun.vc2:5023-5095`, apelat din `frm_facturi.do_modifica_explicatie` :4484-4501) —
- apeleaza doar **`pack_facturare.modifica_explicatie_articol(id_vanzare_det, ...)`** (:5067) — schimba
- **doar textul explicatiei**, nu cantitatea/pretul/cont-ul. Nici aici nu se ating notele contabile.
-
-## 3. Tabelele de note contabile si rulaje
-
-Nu exista schema DBC/DDL in working copy (tabelele sunt Oracle, VFP le vede via view-uri `gcs.v...`). Din
-codul de stergere (`ofacturare_comun.vc2:4573-4614`) rezulta 3 seturi de date, toate filtrate pe
-`an, luna, cod` (cod = `vanzari.cod`, identificatorul facturii):
-
-| View interogat (VFP) | Cursor local | Camp cheie randuri | Rol |
-|---|---|---|---|
-| `gcs.vact_tot` | `actactan` / cursor `v_act` | `id_act` (+ `id_set`, `id_fact`, `id_factd`, `id_factc`) | Note contabile (randuri debit/credit) |
-| `gcs.vrul_tot` | `rul_temp` / cursor `v_rul` | `id_rul` | Rulaje |
-| `gcs.vrul_obinv_tot` | `rul_temp_obinv` / cursor `v_rul_obinv` | `id_rul_obinv` | Rulaje obiecte de inventar |
-
-**Cheia de legatura factura -> nota**: `VANZARI.id_fact` — populat la emitere prin
-`pack_contafin.get_idFact()` (`COMUN\programe\ofacturare_stoc.prg:412`) sau intors ca parametru OUT din
-`scrie_factura2`/`finalizeaza_scriere_verificare` (`?@poDate.nid_vanzare` e id_vanzare, nu id_fact — id_fact
-pare populat separat de pachetul Oracle). Pe partea de nota, actul (`ACT`) are coloanele `id_fact`/`id_factd`/
-`id_factc` folosite de `pack_documente.ReferinteDocumenteNota`/`ReferinteDocument`
-(`COMUN\programe\odocumente.prg:8-46`) pentru a detecta referinte incrucisate intre documente (facturi ce se
-storneaza/compenseaza reciproc).
-
-**Camp de provenienta pentru regenerare**: nu exista un camp explicit gen `sursa_id_vanzare` pe ACT/RUL vizibil
-in cod VFP; legatura se face prin **`cod` (numarul facturii) + `an` + `luna`** — vezi filtrul identic in
-`do_sterge` (:4573,4587,4599). Asta e mecanismul deja folosit pentru "sterge tot ce apartine facturii X":
-select pe `vact_tot`/`vrul_tot`/`vrul_obinv_tot where cod = and an=... and luna=...`, apoi
-sterge. **E si "reteta" pentru un eventual regenereaza = sterge + refa**, cu observatia ca id-urile
-(`id_act`, `id_set`, `id_fact`, `id_factd`) trebuie citite inainte de stergere daca se doreste refacere
-identica (linia 4642-4647 le extrage din `actactan` inainte de a apela stergerea).
-
-## 4. Operatie existenta de STORNARE / STERGERE factura (cheie pentru "regenereaza")
-
-Da — **`frm_facturi.do_sterge`** (`COMUN\clase\ofacturare_comun.vc2:4503-4719`) e exact mecanismul
-"sterge nota + rulaje asociate unei facturi":
-
-- Blocheaza daca luna e inchisa (`glLunaInchisa`, :4518-4520) sau daca factura e deja stearsa (:4531-4534) sau
- daca nu e din luna curenta (:4543-4546).
-- **Cale proforma**: `pack_facturare.sterge_proforma(?pnIdVanzare, ?gnIdUtil)` (:4550) — nu are note, deci
- stergere simpla din VANZARI.
-- **Cale factura/aviz reala**:
- 1. Verifica blocaj de referinte: `ReferinteDocumenteNota(pnAn, pnLuna, lnCod)` (:4565,
- `COMUN\programe\odocumente.prg:8`, cheama `pack_documente.ReferinteDocumenteNota`) — daca documentul
- e referentiat de incasari/plati, blocheaza stergerea (:4567 mesaj "Documentul are referinte...").
- 2. Interogheaza `vact_tot`/`vrul_tot`/`vrul_obinv_tot` (vezi punct 3) ca sa afle daca exista note/rulaje
- de sters (`llRul`).
- 3. Daca exista randuri in `actactan`, deschide formularul **`verificare`** (:4620-4624) pentru
- confirmare vizuala a ce se sterge, apoi porneste tranzactie explicita (`SQLSetprop(...,"Transactions",2)`,
- :4625) si:
- - fie ruleaza `OSCRIE_IN_FISIERE(2,.F.,llRul)` + **`pack_contafin.finalizeaza_stergere_nota(luna, an,
- NULL, id_set, cod, id_fact, id_factd, id_util)`** (:4642-4653) — varianta cu rulaje/fisiere multiple,
- - fie apeleaza direct **`pack_facturare.sterge_factura(?pnIdVanzare, ?gnLuna, ?gnAn, ?gnIdUtil)`**
- (:4689) daca nu exista note/rulaje de tratat special.
- 4. Commit/rollback explicit, apoi revine pe tranzactie automata.
-
-Asta confirma ca infrastructura "sterge + reface" exista deja pe partea de stergere completa
-(`sterge_factura` + `finalizeaza_stergere_nota`); un flux de "regenerare la editare" ar putea reutiliza aceste
-doua RPC-uri Oracle inainte de a re-emite (echivalentul pasilor de la punctul 1, pasul 5) — dar acest
-lant nu exista azi cablat din formularul de editare (`do_modifica`).
-
-## 5. `anaf_efactura.id_fact` — verificare "a fost deja trimisa in eFactura"
-
-- **Citire/test**: `COMUN\clase\ofacturare_comun.vc2:4428-4432`, in `frm_facturi.do_modifica`:
- ```
- lcSql = [select count(*) as lneFactura from anaf_efactura where id_fact = ] + ALLTRIM(STR(poRec.id_fact))
- llSucces = goExecutor.oSelecteaza2Value(m.lcSql, @pneFactura)
- If poRec.sters = 0 AND NVL(m.pnEFactura,0) = 0
- ... permite editarea ...
- Else
- amessagebox("Nu puteti face modificari pe inregistrarile sterse sau facturile trimise in eFactura!", 48, "Atentie")
- ```
- (`pnEFactura`/`pneFactura` sunt aceeasi variabila — VFP e case-insensitive.)
-- Expresia de test: **exista cel putin un rand in `ANAF_EFACTURA` cu `id_fact = VANZARI.id_fact` a facturii
- curente** => considerata "trimisa" => editare blocata.
-- **Scriere**: `VANZARI.id_fact` insusi e populat la emitere (`pack_contafin.get_idFact()`,
- `COMUN\programe\ofacturare_stoc.prg:412`, echivalent probabil si in `scrie_factura2`/
- `finalizeaza_scriere_verificare` pe partea Oracle, nevizibil in VFP). `ANAF_EFACTURA.id_fact` e populat:
- - la import de factura de achizitie (nu de emitere): `UpdateEFacturaIdFact`
- (`COMUN\programe\import_efactura.prg:229`) — `update anaf_efactura set id_fact = ?pnIdFact where id = ?pnId
- and NVL(id_fact,0)=0`.
- - manual din formular: `frm_import_efactura.importmodifica` (`anaf_efactura.vc2:12930`) —
- `UPDATE crsFacturi SET id_fact = m.pnIdFact WHERE id = m.lnIdEfactura`.
- IPOTEZA: pentru facturile **emise** (nu achizitie), popularea `anaf_efactura.id_fact` la trimitere se face
- probabil in clasa server `AnafeFacturaServer`/`ANAFeFactura` (`COMUN\programe\anaf_efactura.prg`, ex.
- `UpdateDbFactura` :2018-2155) sau in Oracle la generarea XML — nu am gasit un UPDATE explicit VFP care
- leaga `id_fact` la momentul trimiterii unei facturi emise; ar trebui verificat separat (posibil in PL/SQL).
-
-## 6. Cele 4 tipuri de sursa — ramificare si diferente
-
-Ramificarea e pe **`VANZARI.tip`** (camp numeric), vazuta in doua locuri, cu acelasi grupaj:
-
-`ofacturare.prg:266-308` (populare cursor articole la pornirea emiterii) si
-`ofacturare.vc2:14067-14174` (`do_scrie_factura`, alegerea RPC-ului de scriere):
-
-| Sursa | `tip` (exemple) | Cursor populare articole | RPC scriere |
-|---|---|---|---|
-| **Lista de preturi** | 1,5,7,10,22,23,29,45 (si 48/49 varianta `cursor_articole_k`) | `pack_facturare.cursor_preturi(...)` | `scrie_factura2` (ramura "otherwise") |
-| **Contract** | 2,6,26,52 | `pack_facturare.cursor_contract(...)` | `scrie_factura2` (ramura "otherwise") |
-| **Comanda** | 3,21,25,28,42,47 | `pack_facturare.cursor_comanda(...)` | `scrie_factura2` (ramura explicita `Inlist(poDate.Tip,3,21,25,28,42,47)`, cu intrebare "Doriti sa se inchida comanda?" :14122) |
-| **Aviz** | 4 | `pack_facturare.cursor_avize(...)` | `scrie_factura_avize` (ramura `poDate.Tip = 4`, cu intrebare "Doriti sa se inregistreze si avizul de retur?" :14091) |
-| (alte, mentionate de completitudine) | 27 (lucrare), 30 (aviz din NIR), 41 (transfer gestiune), 8/9/24 (retur) | `cursor_lucrare`/`cursor_aviz_nir`/`cursor_gestiune`/`cursor_retur` | variante `scrie_factura_avize_retur`/`scrie_proforma` |
-
-**Ce difera intre ele ca note contabile/rulaje**: apelul final e mereu
-`pack_facturare.finalizeaza_scriere_verificare(...)` (sau `scrie_factura_avize_retur` pentru retururi) —
-adica *acelasi* punct final scrie notele, insa RPC-ul de scriere in VANZARI difera (`scrie_factura_avize` vs
-`scrie_factura2`), iar la comanda/aviz apar intrebari suplimentare de inchidere document sursa (comanda
-inchisa / aviz retur generat) care produc efecte laterale suplimentare pe langa nota standard. Diferentele
-fine intre `scrie_factura2` si `scrie_factura_avize` (ce conturi/rulaje difera intern) sunt in PL/SQL, deci
-**nu sunt vizibile in working copy**.
-
-## 7. Blocaje deja existente la editare
-
-- **Sters**: `poRec.sters = 0` obligatoriu (`ofacturare_comun.vc2:4432`).
-- **Trimis in eFactura**: `anaf_efactura` are rand cu acelasi `id_fact` (punct 5), acelasi test la
- `:4428-4432`.
-- **Luna inchisa** — nu e verificat in `do_modifica` (doar in `do_sterge`, :4518-4520, `If glLunaInchisa Return`).
- Deci editarea (schimbare ruta/delegat/etc.) **nu e blocata de luna inchisa**, doar stergerea. IPOTEZA/
- observatie pentru discutie: daca se adauga regenerare de note la editare, ar trebui adaugat si acest test.
-- **Nu e din luna curenta** — verificat doar la stergere (:4543-4546: `(pnAn*12)+pnLuna <> (gnAn*12)+gnLuna`),
- nu la editare.
-- **Referinte incasari/plati** — verificat doar la stergere (`ReferinteDocumenteNota`, :4565-4569), nu la
- editare.
-- **Are chitanta/incasare** — nu am gasit un blocaj explicit *la editare*; la stergere, verificarea de mai
- sus (`ReferinteDocumenteNota`) acopera implicit si incasarile asociate (comentariul din
- `odocumente.prg:5-6` mentioneaza "id_fact ... pe id_factd sau id_factc").
-
-## 8. Numerotare si documente legate — ce se poate schimba la editare
-
-- **Client**: NU se poate schimba din `frm_modifica_factura` (formularul nu are control pentru client/partener;
- vezi punct 2). Singurul loc unde apare o restrictie explicita despre client e in fluxul de **verificare la
- emitere** (nu la editare): `ofacturare.vc2:14198-14201` — daca diferenta de partener ar afecta un cont "41*",
- `amessagebox("Nu puteti modifica clientul!",48,"Atentie") / Return .F.` — asta e in timpul emiterii
- (formularul `verificare`), nu in editarea ulterioara.
-- **Data facturii / seria / numarul facturii**: NU sunt pe formularul de editare. Campurile editabile
- `data_act`/`numar_act`/`serie_act` (:4444-4458) sunt pentru "act" (document justificativ atasat, cu
- checkbox-uri de activare `chkDataAct/chkNrAct/chkSerieAct`), NU seria/numarul facturii insesi — acelea
- se aloca ireversibil la emitere prin `poGeneratorNumere` (punct 1, pasul 2).
-- **Articole**: nu se pot modifica cantitati/preturi din fluxul de editare a facturii — doar explicatia unui
- articol (`frm_modifica_articol_factura`, punct 2).
-- **Aviz consumat / comanda / contract — flag "facturat"**: Exista camp **`facturat`** pe `COMENZI`
- (folosit in UI: `ct_comenzi.actualizeaza_grid1` colora randurile cu `facturat=1`,
- `COMUN\clase\ocomenzi.vc2:1144`; verificari `loRec.facturat=1` in `do_modifica`/`do_sterge` ale comenzii,
- :1806, :2065 — blocheaza modificarea/stergerea comenzii deja facturate; filtru rapid `facturat=1`/`facturat=0`
- in criterii, :2178). Marcarea `facturat=1` se face insa pe partea Oracle (`pack_facturare.scrie_factura2`
- etc.), nu am gasit un `UPDATE comenzi SET facturat` direct in VFP — deci **nu e vizibil in working copy**
- exact unde se scrie flagul, doar ca e citit/verificat pe partea VFP. Nu am gasit camp echivalent `facturat`
- pe AVIZE sau CONTRACTE in codul cercetat (posibil alt nume de camp sau tot pe partea Oracle) —
- IPOTEZA/necesita cautare suplimentara daca devine relevant.
-
----
-
-## Rezumat concluzii cheie
-
-1. **Emiterea** (`COMUN\programe\ofacturare.prg:90` -> `factureaza2`) scrie in VANZARI via
- `pack_facturare.scrie_proforma/scrie_factura_avize/scrie_factura2`, apoi (daca nu e proforma) afiseaza
- formularul `verificare` cu liniile de nota propuse si finalizeaza notele/rulajele prin
- **`pack_facturare.finalizeaza_scriere_verificare`** (`COMUN\clase\ofacturare.vc2:14247`, variante retur la
- :14219/:14282). Ramificarea pe cele 4 surse (lista preturi/contract/comanda/aviz) e pe `VANZARI.tip`,
- vezi tabel la punctul 6.
-2. **Editarea existenta** (`frm_facturi.do_modifica`, `COMUN\clase\ofacturare_comun.vc2:4382-4482`, via
- `pack_facturare.modifica_date_factura`) atinge DOAR metadate logistice (ruta/delegat/agent/masina/
- dataora_exp/tip_facturare/listare_detaliata/text_aditional/tip_saft/data-numar act) — **confirmat: nu
- atinge notele contabile/rulajele si nu recalculeaza sume**. Nu se pot schimba client, data/serie/numar
- factura sau articole.
-3. Notele contabile si rulajele stau in view-urile Oracle `vact_tot`/`vrul_tot`/`vrul_obinv_tot`
- (chei `id_act`/`id_rul`/`id_rul_obinv`), legate de factura prin **`cod`+`an`+`luna`** (identic filtru
- folosit si la stergere) si prin `VANZARI.id_fact` (populat de `pack_contafin.get_idFact()`).
-4. **Exista deja** un flux complet de stergere-cu-note: `frm_facturi.do_sterge`
- (`ofacturare_comun.vc2:4503-4719`) — foloseste `pack_facturare.sterge_factura` +
- `pack_contafin.finalizeaza_stergere_nota`, cu verificare de referinte (`ReferinteDocumenteNota`) si
- confirmare vizuala (formularul `verificare`). **Aceasta e infrastructura direct reutilizabila pentru un
- "regenereaza = sterge + refa"** al notelor/rulajelor la editare.
-5. **`anaf_efactura.id_fact`**: testul de blocare editare e `select count(*) from anaf_efactura where
- id_fact = ` (`ofacturare_comun.vc2:4428-4432`) — daca exista rand, factura e
- considerata trimisa si editarea e refuzata. Punctul exact unde se scrie `anaf_efactura.id_fact` la
- trimiterea unei facturi **emise** nu e vizibil in VFP (ipoteza: pe partea Oracle/XML) — cel gasit in VFP e
- doar pentru facturi de achizitie importate.
-6. **Blocaje actuale**: editarea verifica doar `sters=0` si `netrimisa in eFactura`; NU verifica luna
- inchisa, NU verifica "luna curenta", NU verifica referinte incasari/plati — aceste 3 verificari exista
- doar pe fluxul de **stergere**, nu si pe cel de **editare** (`do_sterge` vs `do_modifica`,
- `ofacturare_comun.vc2:4503` vs `:4382`).
-7. Cod PL/SQL Oracle (`PACK_FACTURARE`, `PACK_CONTAFIN`, `PACK_DOCUMENTE`) nu e in working copy — doar
- semnaturile RPC apelate din VFP sunt vizibile local.
diff --git a/docs/cercetare/rec_s4_runda1.md b/docs/cercetare/rec_s4_runda1.md
deleted file mode 100644
index 3f73d1a..0000000
--- a/docs/cercetare/rec_s4_runda1.md
+++ /dev/null
@@ -1,85 +0,0 @@
-# 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:
-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
-
-- **`COMUN\programe\ofacturare_editare.prg`**, doua functii noi la coada fisierului:
- - `IncarcaVanzareNota(tnCod, tnNract, tcSerieAct, tdDataAct)` — gaseste randul din `VANZARI`
- corespunzator notei curente (filtru compus `cod+nract+serie_act+data_act`, necesar pentru ca
- `VANZARI.COD` nu e unic — vezi `progres.md`), cursor `tvanz`.
- - `IncarcaArticoleFactura(tnIdVanzare)` — liniile active (`sters=0`) din `VANZARI_DETALII`, cu
- denumire articol/gestiune/valuta pentru afisare, cursor `tvd`.
-- **`COMUN\clase\omodificari.vc2`** (`frm_modific2024`):
- - `pgfArticole.PageCount = 3`, `PAGE3.Caption = "Articole factura"`.
- - Grid nou `pgfArticole.PAGE3.grdArticoleFactura` — 13 coloane, `RecordSource="tvd"`, strict
- **readonly** (grid + fiecare `Text1`).
- - Proprietati noi pe clasa: `lAreArticoleVanzari`, `nIdVanzare`, `nTipVanzare`.
- - `Load()`: placeholder `CREATE CURSOR tvd (...)` — evita dialogul nativ "Open" pe `RecordSource`
- inexistent la constructia grid-ului.
- - `Show()`: bloc nou care cheama `IncarcaVanzareNota`/`IncarcaArticoleFactura` si comuta
- `pgfArticole.PageCount` intre 2 si 3 dupa `lAreArticoleVanzari`.
-
-Write-back facut, text si binar sincronizate, fidelity-check OK.
-
-## Ce s-a testat, si cu ce rezultat
-
-Suita `COMUN\utile\Teste\editare_factura\test_page3_articole.prg`, headless sub
-`COMUN\utile\Teste\watchdog_vfp.ps1 -AutoDismiss`, conexiune reala `MARIUSM_AUTO`. Rulare finala
-(dupa curatarea instrumentatiei de depanare): **exit code 0, 0 dialoguri, toate cazurile PASS**
-(`test_page3_articole_log.txt`):
-
-| Caz | Verifica | Rezultat |
-|---|---|---|
-| `cod=1140888` (factura, tip=1) | `IncarcaVanzareNota`/`IncarcaArticoleFactura` direct: `id_vanzare=1050`, `tip=1`, 4 linii | PASS |
-| `cod=1140885` (tip=-12, cu rand VANZARI) | idem: `id_vanzare=1047`, `tip=-12` (detectia merge pe orice tip, nu doar facturi) | PASS |
-| `cod=1125486` (nota fara rand VANZARI) | 0 randuri gasite (caz negativ) | PASS |
-| `cod=1139934` (4 randuri VANZARI cu acelasi cod) | filtrul compus gaseste exact `id_vanzare=882` pe `nract=375/SSS`, 0 randuri pe `nract=13` (fara corespondent) | PASS |
-| `cod=1140888`, `frm_modific2024` instantiat (`Createobject`+`Show`, ca in `do_editare_factura`) | `PageCount=3`, `lAreArticoleVanzari=.T.`, `nIdVanzare=1050` | PASS |
-| `cod=1125486`, idem | `PageCount=2`, `lAreArticoleVanzari=.F.` | PASS |
-
-Testul nu atinge Oracle in scriere — doar `SELECT`-uri prin `goExecutor`.
-
-## Ce NU e acoperit (ramane pentru runde ulterioare)
-
-- **Editarea in memorie a liniilor din grid** — runda 2 din S4; grid-ul e strict readonly in
- aceasta runda, prin design (B.2 din plan, marcaje `_modificat`/`sters`/`id_vanzare_det=0`, nu e
- inceput).
-- **Inchiderea prin `do_renunt()`** — netestata, la fel ca in rundele S1-S3 (mediul minimal de
- test are `ControlCount=0` pe formularul principal `frm_facturi`, deci butoanele native nu sunt
- disponibile pentru a conduce fluxul complet prin UI).
-- **Fluxul UI complet prin "Terminat"** — netestat; `verifica_pagecount_form` instantiaza
- `frm_modific2024` direct (`Createobject`+`Show`), la fel ca `do_editare_factura`, dar nu conduce
- formularul pana la inchidere. Validarea din `inainte_de_do_termin` nu e exercitata de aceasta
- suita.
-- Garda **referinte** pe `do_editare_factura` ramane netestata izolat (fara candidat pozitiv in
- datele de test) — mostenit din rundele anterioare, nu specific rundei 1 din S4.
-
-## 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 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
- pasare prin valoare (`DO ... WITH (gnAn), (gnLuna)`).
-2. Harnessul de test (`test_init_env_auto.prg`) incarca implicit clasa `omodificari` din copia de
- lucru **ROACONT**, nu din fisierul editat — remediat cu `RELEASE CLASSLIB` + `SET CLASSLIB TO`
- pe calea completa a fisierului sub test.
-3. Proprietatile custom noi (`lAreArticoleVanzari`, `nIdVanzare`, `nTipVanzare`) lipseau din
- `*` (intrarile `*p:`) — regula era documentata doar pentru metode
- (`*m:`); aplicata acum si aici, in `COMUN\docs\flux-editare-vfp-text.md`.
-
-## Curatare facuta la inchidere
-
-- Scoase liniile de log `[BISECT]` si `[DIAG]` (`ClassLibrary`/`PEMSTATUS`) din
- `test_page3_articole.prg` — erau instrumentatie de depanare, fara rol in suita finala. Corectiile
- de fond (parantezele pe `(gnAn)`/`(gnLuna)`, blocul `RELEASE CLASSLIB`/`SET CLASSLIB TO`) au
- ramas, cu comentariile lor.
-- Sters `test_baseline_isolation.prg` (+ `.FXP` + log) — era temporar prin design; concluzia lui
- ("binarul original nu are blocajul") s-a dovedit nula, testa copia ROACONT a clasei, nu fisierul
- editat (vezi capcana #2 de mai sus).
-- Suita rulata din nou dupa curatare — PASS pe toate cazurile (tabelul de mai sus).
diff --git a/docs/cercetare/rec_s5_oracle_vanzari.md b/docs/cercetare/rec_s5_oracle_vanzari.md
deleted file mode 100644
index 75b6249..0000000
--- a/docs/cercetare/rec_s5_oracle_vanzari.md
+++ /dev/null
@@ -1,231 +0,0 @@
-# Cercetare Oracle S5/S6/S7 (plan #6 - editare factura emisa)
-
-Sursa: export proaspat din `MARIUSM_AUTO@ROA_CENTRAL` (`all_source`), facut in aceasta sesiune
-(08.08.2026), NU copia veche de pe disc din martie. Inainte de export s-a verificat tabela
-`VERSIUNE`: ultimul script aplicat e `ff_2026_08_06_12_COMUN_VANZARI_BACKFILL.sql`, identic cu
-`versiune_db.txt` din radacina proiectului (`2026_08_06_12`) - MARIUSM_AUTO e la zi.
-
-Numerele de linie de mai jos sunt din exportul acestei sesiuni (`PACK_FACTURARE.pck` = 17010
-linii, `PACK_CONTAFIN.pck` = 9041 linii, `PACK_DOCUMENTE.pck` = 96 linii), NU din
-`ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql` de pe disc, care e vechi si nu contine modificarile de
-la #8. Fisierele exportate au ramas in scratchpad-ul sesiunii, nu sunt commise.
-
-## A. Starea reala de azi
-
-### A.1 `actualizeaza_vanzari` (PACK_FACTURARE.pck:16015-16025)
-
-Confirmat: face EXCLUSIV realinierea `cod` + `STERS=0`, nimic altceva.
-
-```
-UPDATE VANZARI_DETALII SET STERS = 0
- WHERE ID_VANZARE IN (SELECT ID_VANZARE FROM VANZARI WHERE COD = V_COD_VECHI);
-UPDATE VANZARI SET COD = V_COD_NOU, STERS = 0 WHERE COD = V_COD_VECHI;
-```
-
-Important, nu era explicit in plan: al doilea `UPDATE` schimba `COD` pe ACELASI rand din `VANZARI`
-(filtrat dupa vechiul cod) - `ID_VANZARE` (cheia primara) NU se schimba niciodata la editare. Asta
-conteaza direct pentru sectiunea C. Comentariul inline de la `:16018` ("de modificat in caz ca il
-las sa stearga manual inregistrari din VANZARI_DETALII") confirma ca extinderea era anticipata.
-
-### A.2 `PACK_CONTAFIN.finalizeaza_modificare_nota` / `finalizeaza_stergere_nota`
-
-`finalizeaza_modificare_nota` (PACK_CONTAFIN.pck:8601-8651): cheama
-`pack_facturare.actualizeaza_vanzari(tnCod, lnCodNou)` DOAR daca
-`SELECT COUNT(*) FROM vanzari WHERE cod = tnCod` > 0 (`:8613-8617`). Daca `cod`-ul vechi nu exista
-in `vanzari` (nota nu vine dintr-o factura), pasul e sarit tacut, fara eroare - comportament corect
-pentru orice alt tip de nota (ROAGEST/ROACONT).
-
-`finalizeaza_stergere_nota` (`:8653-8709`) e simetric: cheama `sterge_din_vanzari` doar daca
-`cod`-ul exista in vanzari. Spre deosebire de `actualizeaza_vanzari`,
-`sterge_din_vanzari` (PACK_FACTURARE.pck:16027-16042) cauta `ID_VANZARE` dupa `cod` si, daca nu-l
-gaseste, ridica `RAISE_APPLICATION_ERROR(-20000, ... FACT-017 ...)` - dar acest caz nu poate aparea
-in fluxul normal, fiindca apelul e deja gardat de count-ul de mai sus.
-
-### A.3-A.4 `scrie_in_vanzari` (PACK_FACTURARE.pck:13491-13956) - formula de calcul
-
-Extrasa integral (bloc `SELECT INTO` la `:13763-13931`, `UPDATE VANZARI` la `:13933-13949`).
-Coloane denormalizate scrise: `discount_tva, valoare_achizitie, total_fara_tva, total_tva,
-total_cu_tva, valval, tvaval, totval, id_valuta, curs, multiplicator, serie_incasat, nr_incasat,
-suma_incasat, tip_incasat` (14 coloane).
-
-Sursa datelor: **`VANZARI_DETALII_TEMP`** (tabela globala temporara de sesiune, NU
-`VANZARI_DETALII`) + `VANZARI_SETURI_TEMP` (pentru linii-set) + `VANZARI_CURSURI` (deja scrisa cu
-`id_vanzare`-ul curent, la `:13704`, prin `scrie_cursuri`). `V_DISCOUNT_FACTURA` e parametru
-explicit al procedurii (discountul de pe document), nu o coloana citita din `VANZARI`.
-
-Formula per-linie e deja extrasa in doua FUNCTII REUTILIZABILE, pure, cu parametri expliciti -
-NU inline: `calculeaza_total_fara_tva_fact` / `calculeaza_total_tva_fact`
-(PACK_FACTURARE.pck:15858-16013). Ambele ramifica explicit pe `V_PRET_CU_TVA` (`:15871`, `:15976`),
-apeland `calculeaza_total_cu_tva_fact` cand flagul e 1. Deci **partea de calcul per linie e deja
-partajabila** - nu trebuie reinventata.
-
-Ce NU e extras e blocul de AGREGARE (suma pe toate liniile documentului, tratarea liniilor din
-seturi, alegerea `curs`/`multiplicator`/`id_valuta` din `vanzari_cursuri`), care e inline in
-`scrie_in_vanzari` si depinde de:
-- `VANZARI_DETALII_TEMP` ca sursa (nu `VANZARI_DETALII`);
-- stare de sesiune pe pachet: `pack_facturare.nin_valuta`, `ndiscount_evidentiat`,
- `cserie_act_incasare` / `nnumar_act_incasare` / `nsuma_incasare` / `ntip_doc_incasare` (acestea
- din urma populate DOAR la emiterea unei facturi-cu-incasare combinata - nu au sens la o editare
- ulterioara, vezi C);
-- `pack_def.GetIdMonedaNationala()`.
-
-**Cine mai apeleaza `scrie_in_vanzari`**: doar 2 locuri, ambele INSERT-then-populate cu
-`RETURNING ID_VANZARE`: `scrie_proforma` (`:5643`) si `finalizeaza_factura` (`:14790`). Extragerea
-blocului de agregare intr-o functie interna parametrizata pe sursa (TEMP la emitere,
-`VANZARI_DETALII` real la editare) e SIGURA fata de ambii apelanti, daca varianta "sursa=TEMP"
-pastreaza exact comportamentul actual.
-
-**Risc concret de reutilizare naiva pentru S5**: coloanele `serie_incasat/nr_incasat/
-suma_incasat/tip_incasat` NU trebuie recalculate la editare - vin din stare de sesiune specifica
-emiterii unei facturi-cu-incasare, fara nicio sursa persistenta din care sa fie reconstruite la o
-editare ulterioara. O procedura noua care ar copia tot `UPDATE`-ul din `scrie_in_vanzari` le-ar
-suprascrie cu `NULL` la fiecare editare, rupand legatura cu incasarea. Procedura propusa pentru S5
-trebuie sa scrie DOAR cele 11 coloane de totaluri/curs, nu si aceste 4.
-
-### A.5 Flagul `VANZARI_DETALII.PRET_CU_TVA`
-
-Deja parte a calculului in Oracle, nu doar in VFP: valoarea intra in agregare din
-`a1.pret_cu_tva <- vd.pret_cu_tva <- VANZARI_DETALII_TEMP.PRET_CU_TVA` pentru liniile directe
-(`:13883`) sau din `VANZARI_SETURI_TEMP.pret_cu_tva` pentru liniile din seturi (`:13909`), apoi
-`calculeaza_total_fara_tva_fact`/`calculeaza_total_tva_fact` ramifica pe el (`:15871`, `:15976`).
-Orice extragere pentru S5 trebuie sa citeasca acelasi `VANZARI_DETALII.PRET_CU_TVA` per linie (deja
-persistat, cf. #7) - nu exista alta sursa de adevar pentru el.
-
-## B. Propunerea pentru S5
-
-### Varianta A vs B
-
-`actualizeaza_vanzari` e apelata NECONDITIONAT de `finalizeaza_modificare_nota` pentru ORICE
-editare de nota al carei `cod` exista in `vanzari` - nu doar facturi din #6, ci orice tip de
-document din VANZARI editat azi prin `frm_modific2024`/`afisjurcom.do_modifica`, folosit deja de
-ROAGEST/ROACONT in registrul jurnal. Daca **Varianta A** (extinderea in-place a lui
-`actualizeaza_vanzari` cu recalcul de totaluri) e aleasa, recalculul ar rula automat la ORICE
-editare de nota cu `cod` in vanzari, inclusiv editari care azi nu ating deloc sumele (ex. doar
-`explicatie`/`cont`). Risc de regresie: **mediu-mare**, extins la toata suita ROA, nu doar la #6.
-
-**Varianta B** (procedura sora noua, ex. `recalculeaza_totaluri_vanzari`, apelata explicit din
-`finalizeaza_modificare_nota` doar cand editarea a atins efectiv `VANZARI_DETALII`): risc **mic** -
-`actualizeaza_vanzari` ramane neschimbata (zero impact pe restul aplicatiilor ROA care o folosesc
-azi), noua procedura e un pas suplimentar, opt-in.
-
-**Recomandare: Varianta B**, motivata exclusiv de riscul de regresie asupra editarilor de note care
-NU sunt facturi si trec prin acelasi `finalizeaza_modificare_nota`.
-
-### Schita procedurii propuse
-
-```
-PROCEDURE recalculeaza_totaluri_vanzari(V_ID_VANZARE IN NUMBER) IS
- -- reia blocul de agregare din scrie_in_vanzari (:13763-13931), cu sursa
- -- VANZARI_DETALII WHERE ID_VANZARE = V_ID_VANZARE AND STERS = 0
- -- in loc de VANZARI_DETALII_TEMP; V_DISCOUNT_FACTURA citit din VANZARI.DISCOUNT
- -- (coloana existenta pe randul curent, populata la INSERT din acelasi parametru, :13682)
-BEGIN
- SELECT discount, ... INTO lnDiscountFactura, ... FROM vanzari WHERE id_vanzare = V_ID_VANZARE;
- -- acelasi SELECT agregat ca in scrie_in_vanzari, sursa VANZARI_DETALII in loc de _TEMP
- UPDATE vanzari
- SET discount_tva = ..., valoare_achizitie = ..., total_fara_tva = ...,
- total_tva = ..., total_cu_tva = ..., valval = ..., tvaval = ..., totval = ...,
- id_valuta = ..., curs = ..., multiplicator = ...
- -- FARA serie_incasat/nr_incasat/suma_incasat/tip_incasat, vezi A.4
- WHERE id_vanzare = V_ID_VANZARE;
-END;
-```
-
-Apelata din `finalizeaza_modificare_nota` (PACK_CONTAFIN.pck:8601), dupa `actualizeaza_vanzari`.
-
-### Mecanismul de scriere VFP in `VANZARI_DETALII` la emitere
-
-Cautare in cache-ul text `COMUN` pentru `VANZARI_DETALII_TEMP` / `DETALII_TEMP` (case-insensitive):
-**niciun rezultat**, inclusiv in `oscrie_in_fisiere.prg`. Tabela temp e populata probabil printr-un
-helper generic de upload cursor->tabela (nume de tabela asamblat dinamic sau printr-un mecanism
-care nu apare ca literal in sursa text). Nu am putut confirma static calea exacta - de cercetat
-separat, pe partea VFP, inainte de proiectarea S4 (ce cursor/tabela temp foloseste editarea:
-reutilizeaza `VANZARI_DETALII_TEMP` sau una noua).
-
-### Idempotenta si tranzactionalitate
-
-Fluxul de editare a notei ruleaza deja intr-o singura tranzactie manuala:
-`Thisform.do_deschide_tranzactie()` (comun.vc2:2448) ... `oscrie_in_fisiere` + apelul catre
-`finalizeaza_modificare_nota` (`:2484-2486`) ... `Thisform.do_inchide_tranzactie(...)` (`:2535`,
-`COMMIT`/`ROLLBACK` in functie de succes). Procedura noua, apelata DIN INTERIORUL
-`finalizeaza_modificare_nota`, mosteneste automat aceeasi tranzactie: la esec pe jumatate,
-`ROLLBACK`-ul anuleaza tot (nota + `vanzari` + noile totaluri) - nu exista fereastra de
-inconsistenta. `recalculeaza_totaluri_vanzari` propusa e ea insasi idempotenta ca `UPDATE ... WHERE
-id_vanzare = :id` (poate rula de mai multe ori pe acelasi id fara efect cumulativ, spre deosebire
-de un `INSERT`).
-
-## C. S6 - legaturile care depind de `cod`
-
-Verificat pe cod (nu date, dat fiind ca `MARIUSM_AUTO` are date de test):
-
-| Legatura | Cheie reala | Ramane valida? |
-|---|---|---|
-| `vanzari_coresp` | `ID_VANZARE_FACT`/`ID_VANZARE_AVIZ` (coloane confirmate din `all_tab_columns`) | DA - `actualizeaza_vanzari` nu schimba `ID_VANZARE` (vezi A.1), doar `COD` pe acelasi rand |
-| `facturat` (aviz/comanda, `marcheaza_facturat`) | `ID_VANZARE`, exclusiv (PACK_FACTURARE.pck:15384-15421, foloseste doar `pack_facturare.nid_vanzare`, niciodata `cod`) | DA |
-| chitanta/incasare (`SERIE_INCASAT`/`NR_INCASAT`/`SUMA_INCASAT`/`TIP_INCASAT`) | denormalizate direct pe randul `VANZARI` (nu FK), scrise o singura data la `scrie_in_vanzari` (`:13777-13780`) | DA - `actualizeaza_vanzari` nu le atinge; raman la valoarea de la emitere, ceea ce e comportamentul corect (nu se recalculeaza la editare de sume, vezi A.4/B) |
-| `ReferinteDocumenteNota`/`ReferinteDocument` (PACK_DOCUMENTE.pck:25-93) | `ACT.id_factd`/`id_factc` = `id_fact`-ul documentului, filtrat `cod <> tnCod` | DA - e o VERIFICARE PRE-EDITARE (gate, apelata inainte sa se schimbe ceva), nu o legatura persistenta; nu depinde de `cod`-ul rezultat dupa editare |
-| `anaf_efactura` | `ID_FACT` (coloana confirmata) | DA - `id_fact` nu se schimba la editare (by design, deja stabilit in plan) |
-| `documente` | `DOCUMENTE.ID_DOC = ACT.ID_FACT` (confirmat din `MERGE INTO DOCUMENTE ... ON A.ID_DOC = B.ID_DOC` unde `B.ID_DOC` vine din `ACT_TEMP.ID_FACT`, PACK_CONTAFIN.pck:858-880) | DA - si se REACTUALIZEAZA automat (SERIE_ACT/NRACT/DATAACT) la fiecare scriere de nota, inclusiv editare, prin acelasi `MERGE` care ruleaza in `cumuleaza_note_act` |
-
-**Concluzie generala**: toate legaturile intre note contabile trec prin `ID_FACT`
-(`ACT.id_factd/id_factc`, `DOCUMENTE.id_doc`, `ANAF_EFACTURA.id_fact`), niciodata prin `cod`. Cum
-#6 pastreaza `id_fact` neschimbat by design, toate raman valide fara nicio interventie
-suplimentara. Singura legatura care trece prin altceva (`ID_VANZARE`, PK-ul randului `VANZARI`) e
-`vanzari_coresp`/`marcheaza_facturat`, si acesta ramane la fel neschimbat (doar `COD` se rescrie pe
-acelasi rand, vezi A.1). **S6 se poate inchide ca "confirmat pe cod, fara lucru suplimentar
-necesar"**, nu doar ca "de verificat".
-
-## D. S7 - rotunjirea la reeditare
-
-`verifica_total_document` (PACK_FACTURARE.pck:16073-...) insereaza o linie de corectie in
-`ACT_TEMP` cand suma recalculata din `ACT_TEMP` insusi (`V_TOTFTVA_VER`/`V_TOTTVA_VER`) difera de
-`pack_facturare.ntotftva`/`ntottva` (valori calculate in VFP, trecute prin stare de sesiune inainte
-de scriere). `ACT_TEMP` e complet repopulat la fiecare scriere - procedura nu "tine minte" nimic
-intre apeluri, in Oracle.
-
-**Risc identificat pe partea VFP**: la editare, `afisjurcom.do_modifica` (comun.vc2:2352-2366)
-incarca in cursorul `tact` TOATE randurile curente ale notei
-(`SELECT * FROM vact_tot WHERE cod = ... [AND STERS = 0] ORDER BY id_act`) - asta include si linia
-de corectie inserata la salvarea anterioara (e un rand `ACT` normal, fara marcaj special care sa o
-distinga). La resalvare, acest rand curge inapoi prin `oscrie_in_fisiere` in `ACT_TEMP` impreuna cu
-liniile editate de utilizator, iar `verifica_total_document` ruleaza din nou pe noul `ACT_TEMP`
-(care deja contine vechea corectie).
-
-**Nu se poate decide static** daca rezultatul e o a doua corectie suprapusa peste prima, sau daca
-mecanismul e self-consistent (adica `V_TOTFTVA_VER` deja include vechea corectie in suma agregata,
-iar `pack_facturare.ntotftva` recalculat de VFP coincide, deci nu se mai adauga nimic) - depinde de
-cum recalculeaza VFP `ntotftva`/`ntottva` la editare, cod care nu a fost verificat in aceasta trecere
-(afara de scope-ul Oracle-only al acestei cercetari).
-
-De notat: acest mecanism NU e nou pentru #6 - e folosit azi neschimbat de orice editare de nota
-prin `do_modifica` (ROAGEST/ROACONT registru jurnal), pe orice tip de document, de ani de zile.
-Daca ar acumula corectii sistematic la editari repetate, ar fi deja o problema cunoscuta pe editari
-non-factura. Asta scade riscul, dar nu-l elimina pentru cazul specific facturii, unde S4/S5
-introduc o cale noua de a schimba cantitati/preturi care nu exista azi in `do_modifica` generic (pe
-notele generice azi de regula nu se schimba baza de calcul TVA in acelasi fel).
-
-**Raspuns**: nu se poate decide din cod - testul deja propus in plan (S7: trei editari consecutive,
-verifica nr. de linii de corectie in `ACT`) e calea corecta si suficienta; nu exista scurtatura
-statica.
-
-## E. Intrebari deschise
-
-1. **Semnatura procedurii noi**: apel neconditionat din `finalizeaza_modificare_nota` oricand
- `cod`-ul exista in `vanzari` (simplu, cost mic - un `SELECT`+`UPDATE` in plus si pe editari care
- nu ating articolele), sau flag explicit `tnAtinsArticole` trecut din VFP (evita lucru inutil, dar
- risc de flag uitat/gresit)? **Recomandare: apel neconditionat** - cost neglijabil, elimina o
- clasa de bug.
-2. **Discountul de document la editare**: `V_DISCOUNT_FACTURA` la emitere e parametru explicit din
- VFP; planul S4/S4b nu mentioneaza editarea discountului de pe document, doar cantitate/pret/
- `pret_cu_tva` pe linie. La S5, discountul se citeste din `VANZARI.DISCOUNT` (neschimbat) - de
- confirmat cu Marius ca asta e comportamentul dorit (discountul de document ramane needitabil in
- #6).
-3. **`VALVAL`/`TVAVAL`/`TOTVAL`** (totaluri in valuta): planul S5 mentioneaza explicit doar
- `total_fara_tva`/`total_tva`/`total_cu_tva`/`valoare_achizitie`/`discount_tva`. Fac parte din
- acelasi bloc de agregare din `scrie_in_vanzari` - **recomandare: le includem in recalcul**, cost
- suplimentar zero, evita inconsistenta pe documentele in valuta straina.
-4. **Mecanismul de populare al `VANZARI_DETALII_TEMP`** la emitere n-a putut fi gasit static in
- cache-ul text `COMUN` (cautare literal, fara rezultate) - necesita cercetare VFP separata inainte
- de a proiecta calea exacta de scriere pentru editarea din S4 (aceeasi tabela temp, sau una noua).
-5. **S7**: raspunsul cere test dinamic (3 editari consecutive), nu poate fi confirmat static - de
- pastrat explicit in scope-ul S8, nu doar "de verificat" generic in text.
diff --git a/docs/cercetare/retur_si_lista_preturi.md b/docs/cercetare/retur_si_lista_preturi.md
deleted file mode 100644
index f571faa..0000000
--- a/docs/cercetare/retur_si_lista_preturi.md
+++ /dev/null
@@ -1,198 +0,0 @@
-# Cercetare: retur din facturi anterioare + adaugare din lista de preturi pe document cu sursa
-
-## A. Returul din facturi anterioare — cum functioneaza AZI
-
-### A.1 `But_retur` — lant de apel
-
-Definitia clasei butonului (`COMUN\clase\cmd_butoane.vc2:324-338`):
-```
-DEFINE CLASS but_retur AS buton OF "_cmd_base.vcx"
- caction = do_retur
- ...
- Visible = .F.
-ENDDEFINE
-```
-Butonul e instantiat pe `frm_facturare_articole` la `COMUN\clase\ofacturare.vc2:11221-11227` (`Visible=.F.` implicit) si devine vizibil doar conditionat, in `Init`, la `ofacturare.vc2:15122-15127`:
-```
-Case Inlist(poDate.tip, 1, 5, 7, 10) && modificare v 2.0.56 : am adaugat 10
- && facturare pe baza de lista de preturi
- ...
- This.but_retur.Visible = .T. && pot sa fac retur de articole intr-o factura de vanzare
-```
-Deci butonul e vizibil **doar pe documente de tip 1/5/7/10** (facturare pe baza de lista de preturi), nu pe facturi de retur propriu-zise (8/9) si nu pe documente cu sursa contract/comanda.
-
-`caction=do_retur` -> click apeleaza `frm_facturare_articole.do_retur` (`ofacturare.vc2:13963-13965`):
-```
-PROCEDURE do_retur
- Thisform.do_adauga_articol(.F., .F., .T.)
-ENDPROC
-```
-adica `do_adauga_articol(tlImplicit=.F., tlContract=.F., tlRetur=.T.)` (`frm_facturare_articole.do_adauga_articol`, `ofacturare.vc2:12813-12823`).
-
-Pas cu pas in `do_adauga_articol` (`ofacturare.vc2:12813-12900`), ramura `tlRetur`:
-1. Utilizatorul selecteaza un articol (din `crsarticole`, lista de preturi) si o cantitate — `lnCantitate = poArticol.cantitate`.
-2. `Thisform.do_verifica_articol(...)` valideaza cantitatea.
-3. La `ofacturare.vc2:12881-12890` (case `Otherwise`, articol gestionabil):
-```
-OTHERWISE
- lnListaIdOld = poDate.listaid
- IF m.tlRetur
- loCauta = caut_facturi_multiple_client_articol(poDate.id_client, poDate.in_valuta, poDate.id_valuta, .F., poArticol.id_articol)
- If m.gnButon = 1 and !Empty(Nvl(loCauta.id_vanzare, 0))
- poDate.listaid = Alltrim(Str(loCauta.id_vanzare))
- * ID_ARTICOL:ID_VANZARE,ID_ARTICOL:ID_VANZARE
- thisform.cListaIdArticoleRetur = thisform.cListaIdArticoleRetur + IIF(!EMPTY(thisform.cListaIdArticoleRetur), ',', '') + ALLTRIM(STR(poArticol.id_articol)) + ':' + poDate.listaid
- Endif
- ENDIF
- llSucces = Thisform.do_alege_stoc(poArticol.id_articol, lnCantitate, poArticol.denumire, tlImplicit, poArticol.pretftva, poArticol.discount_unitar, loGrid, m.tlRetur)
-```
-4. `do_alege_stoc(..., tlRetur)` (`ofacturare.vc2:13200-13250`) foloseste ramura retur pentru a construi cursorul de stoc/gestiuni de unde se alege articolul de returnat:
-```
-If Inlist(poDate.tip,8,9,24) Or m.tlRetur && factura retur lei, factura retur valuta, aviz retur sau factura normala cu retur de articole
- lcSql = [{call pack_facturare.cursor_gestiuni_articol_retur(...)}]
-```
-5. Rezultatul e afisat printr-un formular `frm_articol_gest_factura` (`Createobject("frm_articol_gest_factura",tnCantitate,tlImplicit,tlRetur)` la `ofacturare.vc2:13353` si `:13361/:13375`), unde utilizatorul alege gestiunea/seria si cantitatea de returnat.
-6. La salvare, `do_scrie_articole` (`ofacturare.vc2:13967-13979`) trimite `poDate.listaid` (perechile `id_articol:id_vanzare` construite la pasul 3) catre `pack_facturare.initializeaza_date_factura`.
-
-Concluzie: **nu exista un singur dialog "alege facturile sursa" pentru tot documentul** — selectia facturii sursa se face **per articol**, in momentul adaugarii fiecarei linii, printr-un dialog generic de cautare.
-
-### A.2 Dialogul si criteriile de cautare a facturii sursa
-
-Formularul e generic — functia `cauta_alfa` (dialog de picker standard ROA), invocata din `caut_facturi_multiple_client_articol` (`COMUN\programe\oproceduri_facturare.prg:2124-2159`):
-```
-Function caut_facturi_multiple_client_articol
- Lparameters tnIdPart, tnInValuta, tnIdValuta, tlFacturiMultiple, tnIdArticol
- ...
- lcSelect = [select a.serie_act,a.numar_act,a.data_act,a.dataora,a.id_vanzare ] + ;
- [from vanzari a join vanzari_detalii b on a.id_vanzare = b.id_vanzare and b.id_articol = ?pnIdArticol ]
-
- lcFiltruOriginal = [a.sters=0 and a.tip in (1,2,3,4,5,6,10,-1,-2,-3,-4,-11) ] + gcCondSucursala + ;
- lcFiltruPart + lcFiltruValuta
- ...
- lcTitlu = [Alegeti factura] && (tlFacturiMultiple = .F. la apelul din do_adauga_articol)
- loCauta = cauta_alfa(lcSelect, lcFiltru, lcSchema, lcOrder, lcColoane, lcTitlu, lcTitluColoane, lcNumeProc, llToateIreg, lcFiltruOriginal, lcPrimaColoana, lnPornire, lnTipReturn, lcIdColumn)
-```
-Coloane afisate: `Serie act, Numar act, Data, Data inreg.` Criterii de filtrare in interogare:
-- **articolul curent** (`b.id_articol = ?pnIdArticol`, obligatoriu — cautarea se face per-articol, nu la nivel de document);
-- **client** (`a.id_part = ?pnIdPart`, doar daca `tnIdPart` nu e gol — `lcFiltruPart`, `oproceduri_facturare.prg:2133`);
-- **valuta** (`a.in_valuta`/`b.id_valuta`, `lcFiltruValuta`, `:2134`);
-- **tip document sursa restrictionat la vanzari normale**: `a.tip in (1,2,3,4,5,6,10,-1,-2,-3,-4,-11)` — exclude explicit tipurile de retur (8,9,24), deci nu se poate face retur dintr-un retur.
-- **numar factura / perioada**: nu exista filtru SQL dedicat in interogare; `cauta_alfa` e dialogul generic de cautare alfa/browse al suitei (permite filtrare interactiva pe coloanele afisate, dar asta e comportament generic al dialogului, nu parametru specific — neverificat mecanismul intern de filtrare al `cauta_alfa`).
-
-Rezultatul (`loCauta.id_vanzare`) e folosit ca `poDate.listaid` pentru articolul curent.
-
-### A.3 Tipuri de document retur
-
-Confirmat in cod, cu **3 valori**, nu doar 8/9 (comentariu explicit la `ofacturare.vc2:12862`):
-```
-* 8 = Retur lei, 9 = retur valuta sau factura de vanzare normala, dar cu retur de articole, 24 = aviz retur
-```
-Folosite consistent in tot `frm_facturare_articole`: `Inlist(poDate.tip, 8, 9, 24)` la `:13043`, `:13230`, `:13728`, `:14751`; `Inlist(poDate.tip, 8, 9)` separat la `:15236` (UI caption) si `:9718` (eliminare camp curs valutar). Pe `frm_facturare_articole2` (varianta "2" a formularului) aceleasi tipuri apar fara 24 in unele locuri (`:17531`: doar 8,9 — de verificat daca e omisiune sau intentionat, neclar din cod).
-
-Semnul cantitatilor pe retur — la `do_alege_stoc` (`ofacturare.vc2:13273, :13300, :13309`):
-```
-Select Iif(poDate.tip=41,-1,1)*Sum(cantitate) As cantitate, ...
-...
-Where a.cantitate - Iif(Inlist(poDate.tip,8,9,24),(-1),1) * Nvl(b.cantitate,0) > 0
-```
-adica pentru tip 8/9/24 semnul cantitatii deja pe factura curenta se scade cu semn opus (`-1` in loc de `1`), consistent cu inregistrari de retur.
-
-**Ziua de curs eliminata pe retur** — confirmat, dar linia corecta e in `COMUN\clase\ofacturare.vc2:9717-9722` (`frm_date_factura.Init`), NU in `ofacturare_comun.vc2` (fisierul citat in plan nu are randul respectiv — `ofacturare_comun.vc2` are doar 7432 de linii):
-```
-*!* 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 ^
-```
-Corolar in acelasi `Init` de `frm_facturare_articole` (`ofacturare.vc2:15098`): `Iif(!Inlist(poDate.tip, 8, 9), "(" + Dtoc(poDate.zi_curs) + ")", "")` — eticheta de curs valutar nu afiseaza data pe retur.
-
-### A.4 Retur partial
-
-Da, e posibil. Coloana de cantitate din `grd_articole`, pe tip 8/9, isi schimba explicit titlul in "cantitate maxima de returnat" (`ofacturare.vc2:15236-15239`):
-```
-Case Inlist(poDate.tip, 8, 9) && factura retur lei/valuta
- This.grd_articole.cCantitate.header1.Caption = [Cant. max. de returnat]
- This.cmesaj_cantitate = [Nu se mai poate face retur pentru acest articol!]
-```
-si analog pentru aviz retur (tip 24) la `:15242-15245`. Cantitatea introdusa de utilizator e validata in `do_verifica_articol` (`:14743-14754`):
-```
-llRetur = Inlist(poDate.tip,8,9,24)
-Do Case
- Case poArticol.gestionabil = 0 Or gnScadereStoc = 1 Or m.llFacturareFaraStoc
- llReturn = .T.
- Case (tnCantitate >= 0 And m.llRetur ) Or ...
- lcMesaj = Alltrim(Thisform.cmesaj_cantitate)
- amessagebox(lcMesaj,0+48,"Atentie")
- llReturn = .F.
-```
-adica sistemul respinge doar cazul in care cantitatea ramasa dupa retur ar iesi din domeniul valid (`tnCantitate >= 0` fiind conditia de eroare pe retur, unde cantitatile de retur sunt negative) — deci utilizatorul poate introduce orice cantitate <= maximul returnabil calculat de `cursor_gestiuni_articol_retur`, inclusiv mai mica (retur partial). Formularul de alegere (`frm_articol_gest_factura`, ramura `tlRetur`, `:13353-13385`) permite editarea cantitatii inainte de confirmare.
-
-### A.5 Legatura stocata linie-de-retur -> linie originala
-
-**Nu am gasit o coloana pe linie in `VANZARI_DETALII`** (de tip "id linie sursa") in codul VFP text disponibil. Ce exista, e legatura **la nivel de antet de document**, prin parametri output ai apelurilor Oracle:
-- `poDate.nid_vanzare` / `poDate.nid_vanzare_retur` — populati ca parametri `?@...` in `pack_facturare.scrie_factura_avize_retur(...)` (`ofacturare.vc2:14448`, `:14509`) si `pack_facturare.finalizeaza_scriere_verificare(...)` (`:14472`); resetati implicit la `oDateFactura.Reset` (`COMUN\programe\ofacturare_comun.prg:569`: `.nid_vanzare_retur = 9999999999`).
-- La nivel de sesiune VFP (nu persistat ca coloana confirmata), `thisform.cListaIdArticoleRetur` acumuleaza perechi `ID_ARTICOL:ID_VANZARE` (`ofacturare.vc2:12888`) trimise ca `poDate.listaid` catre `pack_facturare.initializeaza_date_factura` (`:13977-13979`) — asta e mecanismul prin care Oracle *primeste* info despre factura sursa per articol, dar daca acesta persista intr-o coloana dedicata pe `VANZARI_DETALII` (ex. id linie/document sursa) **nu se poate confirma din sursa VFP** — pachetul `pack_facturare` e in Oracle, in afara acestui repo. Cercetare existenta in `docs\cercetare\rec_cale_vanzari_detalii.md` si `rec_s5_oracle_vanzari.md` (interogari live pe schema Oracle, 08.08.2026) nu mentioneaza vreo coloana de tip `ID_DET_SURSA`/`ID_VANZARE_RETUR` pe `VANZARI_DETALII`. **Neverificat.**
-
----
-
-## B. Adaugarea din lista de preturi pe document cu sursa (comanda/contract)
-
-### A6/B6. Ce se vede azi pe cod
-
-`frm_facturare_articole.Init`, `Do Case` pe `poDate.tip` (`ofacturare.vc2:15108-15248`) configureaza UI-ul per tip. Puncte relevante:
-
-- **Contract (tip 2, 6)** — `ofacturare.vc2:15129-15143`:
-```
-Case Inlist(poDate.tip, 2, 6)
- && facturare pe baza de contract
- This.lb_titlu_alb_b121.Caption = [FACTURA PE CTR. ] + Alltrim(poDate.descriere)
- This.grd_articole.RemoveObject('cSerie')
- && articole din lista de preturi
- This.grd_articole.cCantitate.header1.Caption = [Cantitate in stoc]
- This.cmesaj_cantitate = [Acest articol nu este pe stoc!]
-```
-Comentariul "articole din lista de preturi" e explicit: `grd_articole` (cu butonul `But_urmator1`/`do_urmator`->`do_adauga_articol()`, cursorul `crsarticole`) **ramane activ si populat cu lista de preturi** chiar si pe document de tip contract. In paralel, `grd_contracte` (buton `But_urmator2`/`do_urmator2`->`do_adauga_articol(.F.,.T.)`, cursorul `crsarticole1`) afiseaza articolele restrictionate la contract.
-
-Cei doi cursori se populeaza distinct: pentru `tnTip in (2,26,6,52)`, apelul e `pack_facturare.cursor_contract(...)` (`COMUN\programe\ofacturare.prg:283-290`), care umple atat `crsarticole` cat si (separat) `crsarticole1` (confirmat prin `Create Cursor crscontracte ... Select Distinct ... From (lcCursor + [1])`, `ofacturare.prg:433-440` — `lcCursor+'1'` = `crsarticole1` deja exista la acel punct).
-
-- **Comanda (tip 3)** — `ofacturare.vc2:15144-15150`:
-```
-Case poDate.tip = 3
- && facturare pe baza de comanda
- This.lb_titlu_alb_b121.Caption = [FACTURA LA COMANDA ] + Alltrim(poDate.descriere)
- This.grd_articole.RemoveObject('cSerie')
- This.grd_articole.cCantitate.header1.Caption = [Cantitate comandata]
- This.cmesaj_cantitate = [A fost facturata intreaga cantitate comandata pentru acest articol!]
- This.but_urmator_tot1.Visible = .T.
-```
-Aici `grd_articole`/`crsarticole` e populat direct de `pack_facturare.cursor_comanda(...)` (`ofacturare.prg:292-293`, tip in `(3,21,25,28,42,47)`) — adica **doar articolele comenzii**, nu lista de preturi libera. Nu exista al doilea cursor (`crsarticole1` nu se creeaza pentru tip 3, doar pentru `2,6,26` conform `ofacturare.prg:433`), deci in `Init` la `ofacturare.vc2:15294-15324`:
-```
-If !Used('crsarticole1')
- ...
- Thisform.RemoveObject('grd_contracte')
- Thisform.RemoveObject('but_urmator2')
-Endif
-```
-grila si butonul secundar se elimina complet.
-
-Exceptie: la **copiere de factura/aviz** (`poDate.lCopiere`), indiferent de tip, codul adauga explicit lista de preturi peste cursorul existent (`ofacturare.prg:454-473`):
-```
-IF m.llCopiere
- * Adaug in lista articolelor cursorul cu lista de preturi ca sa pot adauga si alte articole in factura copiata/modificata
- lcSqlCursor = [{call pack_facturare.cursor_preturi(...)}]
- ...
- SELECT crsArticole
- APPEND FROM DBF(m.lcCursorTemp)
-ENDIF
-```
-
-### B7. Unde e restrictia
-
-Nu e un `Visible`/`Enabled` pe buton (butonul `But_urmator1`/lista-de-preturi exista si e vizibil pentru toate tipurile, la fel `grd_articole`) si nu e o validare la salvare — **restrictia e la nivelul continutului cursorului de articole disponibile** (`crsarticole`), decis de care procedura Oracle il populeaza in `factureaza()`/`factureaza2()` (`ofacturare.prg:266-308`, `Do Case` pe `tnTip`):
-- tip **1,5,7,10** (lista de preturi) si **2,6,26,52** (contract) -> `cursor_preturi`/`cursor_contract`: `crsarticole` contine lista de preturi completa (nerestrictionata la sursa) => **azi se poate deja adauga liber din lista de preturi pe un document contract**.
-- tip **3,21,25,28,42,47** (comanda) -> `cursor_comanda`: `crsarticole` contine **doar** articolele comenzii => **azi NU se poate** adauga o linie libera din lista de preturi pe un document comanda, decat prin copiere de document (`llCopiere`, ramura separata mai sus).
-
-Concluzie B: distinctia plan-ului ("comanda sau contract, tipurile 2,6,26,52") nu e uniforma in codul actual — **contractul (2,6,26,52) are deja acces liber la lista de preturi** (al doilea grid `grd_contracte` e doar un adaos, nu o restrictie), in timp ce **comanda (3) e restrictionata strict la continutul comenzii**, fara optiune de adaugare libera in fluxul normal (doar la copiere de document).
diff --git a/docs/cercetare/roaauto_articole_lista_preturi.md b/docs/cercetare/roaauto_articole_lista_preturi.md
deleted file mode 100644
index 0b9a6e0..0000000
--- a/docs/cercetare/roaauto_articole_lista_preturi.md
+++ /dev/null
@@ -1,163 +0,0 @@
-# ROAAUTO — adaugarea de articole reale din nomenclator pe langa MANOPERA/MATERIALE
-
-## Corectie fata de `roaauto_facturi.md`
-
-Raportul anterior a descris facturarea ROAAUTO ca fiind formata **doar** din linii sintetice
-(`-100000`..`-100008`). E incomplet: exista un mecanism separat, **"Alte servicii"**, care adauga
-linii cu `id_articol` real (pozitiv), din nomenclatorul de articole, in plus fata de liniile
-sintetice MANOPERA/MATERIALE. Mecanismul e cablat **direct in `factureaza_deviz`**, deci face
-parte din acelasi flux descris anterior, nu dintr-un flux alternativ.
-
-## 1. Unde se adauga articole din nomenclator
-
-Formular: `frm_incasare_finala` (`D:\ROA\ROAAUTO\Clase\oviz_devize.vc2:5435-7143`), aratat de
-`frm_emitere_facturi.do_factureaza_final` (`oviz_devize.vc2:2569` `ofrmincasare=Createobject('frm_incasare_finala',...)`)
-si `do_factureaza_final_part` (`:3539`) — adica **la momentul emiterii facturii finale**, nu pe
-formularul de deviz propriu-zis (`oviz_devize` nu are buton de adaugare articol la crearea
-devizului).
-
-Metoda: `frm_incasare_finala.do_adauga` (`oviz_devize.vc2:6539-6580`):
-```
-lcXMLArticole = cauta_nom_articole([in_stoc = 0 and in_crm = 1 and id_articol not between -100008 and -100000])
-...
-Replace id_articol With loArticol.id_articol,denumire With loArticol.denumire,um With loArticol.um,codmat With loArticol.codmat,;
- id_lucrare With lnIdLucrare,nrord With lcNrOrd
-```
-Cauta in `vnom_articole_toate` (nomenclatorul de articole, cursor `crstmpart`) prin
-`cauta_nom_articole` (`COMUN\programe\ocautare.prg:1781`), filtrat la articole **fara gestiune**
-(`in_stoc = 0`) si **vizibile in CRM** (`in_crm = 1`), excluzand explicit id-urile sintetice
-(`not between -100008 and -100000`). Articolele alese se adauga in grila `grd_altele`
-(`oviz_devize.vc2:6060`, coloane `cDenumire/cNrord/cCantitate/cPretFTva/cValoareftva`,
-`oviz_devize.vc2:6121-6222`), sustinuta de cursorul `crsalteserv`, creat inainte de afisarea
-formularului in `frm_emitere_facturi.do_factureaza_final` (`oviz_devize.vc2:2553-2555`) si
-`do_factureaza_final_part` (`:3522-3524`):
-```
-Create Cursor crsalteserv(id_articol N(14) Not Null,denumire c(100) Not Null,codmat c(50) Null,um c(10) Null,;
- id_lucrare N(14) Not Null,nrord c(100) Not Null,;
- cantitate N(14,gnPCant) Default 1,pretftva N(14,gnPPretV) Default 0,valoareftva N(14,gnPc) Default 0)
-```
-**Important**: `do_adauga` NU completeaza `pretftva`/`cantitate` — raman la valorile implicite
-(1, respectiv 0). Pretul si cantitatea se **introduc manual** de operator in grila
-(`grd_altele.cPretFTva.Text1.LostFocus` / `cCantitate.Text1.LostFocus`, ambele apeland
-`Thisform.do_modifica_alteserv()` care recalculeaza `valoareftva = cantitate * pretftva`,
-`oviz_devize.vc2:6692-6698,7064-7070`). Nu exista o cautare/preluare automata de pret pentru
-aceste articole in acest flux (vezi punctul 6).
-
-## 2. Cum ajung in factura — linii separate, NU cumulate
-
-In `factureaza_deviz` (`Programe\oproceduri_devize.prg`), liniile sintetice MANOPERA/MATERIALE/
-DISCOUNT/AVANS se insereaza in cursorul `crsdeviz` (`:936-983`) cu id-uri fixe (`-100000`..
-`-100008`). La pasul de cumulare pentru optiunea "articol cumulat REPARATII AUTO" (`:999-1012`)
-se cumuleaza **doar** liniile cu `id_articol IN (-100003,-100000,-100002,-100001)` — liniile din
-`crsalteserv` nu sunt incluse in acest `INLIST`, deci nu pot fi absorbite in cumulare.
-
-Liniile din `crsalteserv` se insereaza **separat**, dupa cumulare, cu `id_articol` real:
-```
-If Used('crsalteserv')
- Insert Into (lcCursorDeviz)(id_articol,denumire,explicatie,cantitate,um,id_jtva_coloana,proc_Tvav,taxcode,pret,discount_unitar) ;
- Select id_articol,denumire,"",cantitate,um,CAST(lnIdJTvaColoana as N(6) null) as id_jtva_coloana,...,pretftva,0 From crsalteserv Where !Deleted()
-Endif
-```
-(`oproceduri_devize.prg:1036-1041`) — deci id-ul real din `nom_articole` trece nemodificat.
-De acolo, fiecare rand ajunge in `crsvanztemp` (`:1190-1206`) si e scris in Oracle prin
-`pack_facturare.adauga_articol_factura_deviz` (`:1240-1257`, apelul SQL construit cu
-`Alltrim(Str(poArticol.id_articol))` la `:1241`), care insereaza direct in
-`VANZARI_DETALII_TEMP` cu `ID_ARTICOL = V_ID_ARTICOL` (pozitiv, real) — vezi implementarea in
-`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:4675-4745`. Confirmare: **articolele din "Alte
-servicii" raman linii proprii, cu id_articol real, si NU se aduna in liniile sintetice
-MANOPERA/MATERIALE.**
-
-## 3. Gestiunea
-
-`id_gestiune` in cursorul `lcCursorDeviz` are `DEFAULT null` (`oproceduri_devize.prg:885`) si
-**niciun** `INSERT INTO` — nici cel al liniilor sintetice, nici cel al liniilor din
-`crsalteserv` (`:1040-1041`) — completeaza aceasta coloana. La transferul in `crsvanztemp`
-(`:1201-1206`) coloana `id_gestiune` (definita fara valoare implicita explicita la `:1190`) nu e
-in lista `SELECT`, deci ramane 0 (implicit numeric), transmis ca literal `0` catre
-`adauga_articol_factura_deviz` (`:1255`, `Alltrim(Str(poArticol.id_gestiune))`), care il scrie ca
-atare in `VANZARI_DETALII_TEMP.ID_GESTIUNE` — nu NULL, ci **0**. Nu exista descarcare de gestiune
-pentru aceste linii; e consistent cu faptul ca articolele oferite spre alegere sunt filtrate
-explicit `in_stoc = 0` (articole/servicii fara gestiune de stoc). **Concluzie: liniile din "Alte
-servicii" NU au gestiune reala completata**, exact ca liniile sintetice — diferenta e doar
-`id_articol`.
-
-## 4. Stergere / modificare inainte de facturare
-
-- Stergere: `frm_incasare_finala.do_sterge` (`oviz_devize.vc2:6730-6741`), cu confirmare
- (`amessagebox("Sunteti sigur ca doriti sa stergeti articolul "+lcArticol+" de pe factura?",4+32,...)`),
- marcheaza randul `Delete` in cursorul bufferat (exclus apoi prin `Where !Deleted()` la punctul 2).
-- Modificare cantitate/pret: direct in grila (`grd_altele.cCantitate`/`cPretFTva`), vezi punctul 1.
-Toate aceste actiuni sunt posibile **doar cat timp `frm_incasare_finala` e deschis, inainte de
-`do_termin`** (validarea din `inainte_de_do_termin`, `:6749-6801`, verifica duplicate si valori 0,
-dar nu mai permite reintrarea in formular dupa emitere).
-
-## 5. Dupa facturare — cmd_modifica1 si cai alternative
-
-Confirmat, cu corectie de context: `Thisform.cmd_modifica1.Enabled=Iif(Empty(nrfact),.T.,.F.)`
-se afla in `frm_emitere_facturi.grdcomenzi.AfterRowColChange` (`oviz_devize.vc2:4536`), nu intr-o
-metoda separata — se re-evalueaza la fiecare schimbare de rand in grila de comenzi, dezactivand
-butonul "Modifica" de indata ce comanda are `nrfact` completat. Verificat suplimentar:
-- `frm_emitere_facturi.verifica_stornare` (`oviz_devize.vc2:4513-4514`) e **gol** (`PROCEDURE
- verifica_stornare / ENDPROC`, fara cod) — nu exista storno de comanda/deviz in acest formular.
-- Singurul "storno" gasit in `oviz_devize.vc2` e `do_storneaza_avans` (`:4256`, folosit din
- `do_factureaza_final`/`do_factureaza_final_part` la `:2345`/`:3305`) — priveste exclusiv
- reversarea unui **avans incasat**, nu redeschiderea unei facturi/deviz deja emise si nu permite
- adaugarea de articole pe o factura emisa.
-- Am gasit un mecanism generic, in afara `oviz_devize.vc2`, care poate **sterge complet** o
- factura deja emisa: `frm_facturi.do_sterge` (`COMUN\clase\ofacturare_comun.vc2:4649-4689`),
- care apeleaza `pack_facturare.sterge_factura(?pnIdVanzare,...)`. In Oracle,
- `sterge_factura` (`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:5441-...`) face un **soft-delete**
- (`UPDATE VANZARI SET STERS = 1 ...`, `:5505-5508`), cu verificari ca nu existe deja facturi/avize
- de retur legate. Aceasta e o stergere a intregii facturi (delete + re-emitere ulterioara),
- **nu** o adaugare/modificare de articole pe factura existenta.
- **Neverificat**: nu am putut confirma, in bugetul acestei cercetari, daca `frm_facturi` e
- cablat intr-un meniu ROAAUTO (grep-ul pentru instantieri `frm_facturi` in fisiere specifice
- ROAAUTO — in afara de `COMUN\` — nu a gasit potriviri de cod, doar metadate ascunse) si nici
- daca stergerea Oracle reseteaza `nrfact`/`facturat` pe comanda ROAAUTO de origine (ar necesita
- urmarirea `pack_auto`, in afara scriptului analizat). Deci **nu pot confirma sau infirma cu
- dovada directa** o cale completa "sterge factura -> reface devizul cu articole diferite" din
- interiorul ROAAUTO; pot confirma doar ca un asemenea instrument de stergere exista generic in
- suita si ca in `oviz_devize.vc2` nu exista niciun cod care sa modifice/adauge articole pe o
- factura deja emisa.
-- **Concluzie pe intrebarea centrala**: constatarea anterioara ramane valabila si dupa aceasta
- cercetare — `oviz_devize.vc2` insusi nu ofera nicio cale de a adauga/modifica articole pe o
- comanda/deviz cu `nrfact` completat; singura cale gasita spre o factura deja emisa e stergerea
- totala (soft-delete) prin ecranul generic COMUN, nu o editare in linie.
-
-## 6. Nomenclator vs. lista de preturi — doua surse, cea folosita de ROAAUTO e nomenclatorul brut
-
-Da, exista doua surse diferite in suita ROA:
-- **Nomenclatorul brut de articole**: `vnom_articole_toate` / `nom_articole`, interogat prin
- `cauta_nom_articole` (`COMUN\programe\ocautare.prg:1781-1823`, `SELECT ... FROM ] + gcS + [.vnom_articole_toate a`
- la `:1799-1803`). **Acesta e cel folosit de `frm_incasare_finala.do_adauga`** — fara pret
- atasat automat (pretul se tasteaza manual, vezi punctul 1).
-- **Motorul de preturi negociate/politici de pret**: `pack_facturare.cursor_preturi`, apelat din
- `COMUN\programe\ofacturare.prg` in `factureaza`/`factureaza2` (liniile 276/281/464/755/760) —
- parte a mecanismului generic COMUN de facturare/avizare pe baza de "lista de preturi"
- (`factureaza(22)`, `factureaza(29)`, `factureaza(23)`, `factureaza(41)` — comentate explicit
- `pe baza de lista de preturi` in `COMUN\programe\oproceduri_facturare.prg:205,237,268`).
- **Nu am gasit niciun apel** al acestui `factureaza`/`factureaza2` generic in fisierele
- specifice ROAAUTO (`oviz_devize.vc2`, `oproceduri_devize.prg`) — grep-urile pentru
- `cursor_preturi` si pentru `factureaza(` in afara de `COMUN\programe\ofacturare.prg` nu au
- gasit potriviri in cod ROAAUTO. **Concluzie**: fluxul propriu ROAAUTO de facturare deviz
- (`factureaza_deviz`) foloseste exclusiv nomenclatorul brut, fara calcul automat de pret
- negociat; motorul `cursor_preturi` pare sa apartina unui flux de facturare/avizare generic,
- separat, neapelat din codul ROAAUTO analizat.
-
-## Neverificat / limitari
-
-- Wiring-ul meniu -> `frm_facturi` in ROAAUTO (punctul 5).
-- Efectul `sterge_factura` asupra coloanelor `nrfact`/`facturat` pe comanda ROAAUTO (necesita
- `pack_auto`, neinclus in scriptul Oracle analizat).
-- Numele exact al butonului/caption care declanseaza `frm_incasare_finala.do_adauga` — nu am
- gasit in `oviz_devize.vc2` un `Click` explicit legat de `do_adauga`; e foarte probabil declansat
- de un buton generic `cmd_adauga` prin conventia clasei de baza `_frm_base` (folosita si de alte
- metode `do_xxx`/`cmd_xxx` din acelasi fisier), dar nu am gasit dovada directa a legaturii.
-- Indexul ROAAUTO a fost reconstruit local (`_symbols.tsv`, permis explicit); nu a fost rulat
- `git_sync.ps1` si nu s-a generat text nou din binare in ROAAUTO.
-
-## Nota
-
-Raportul a fost scris initial (din greseala) la calea gresita `D:\ROA\ROAAUTO\docs\cercetare\...`
-in loc de `D:\ROA\ROAFACTURARE\docs\cercetare\...`. Acest fisier e livrarea corecta, la calea
-ceruta.
diff --git a/docs/cercetare/roaauto_facturi.md b/docs/cercetare/roaauto_facturi.md
deleted file mode 100644
index 65a1235..0000000
--- a/docs/cercetare/roaauto_facturi.md
+++ /dev/null
@@ -1,167 +0,0 @@
-# Cercetare: facturile emise din ROAAUTO si relatia lor cu VANZARI_DETALII
-
-Scop: pentru `plan_13_unificare_formular_facturare.md` — poate formularul unificat sa acopere si
-facturile emise din ROAAUTO (piese + manopera pe deviz), stiind ca ele "se pot modifica ulterior"?
-
-## Metoda si ce am putut verifica
-
-ROAAUTO (`D:\ROA\ROAAUTO`) e un working copy **migrat** (are deja `.vc2`/`.sc2` in-tree, ca
-ROAFACTURARE), deci am cautat direct in text, **fara sa rulez `git_sync.ps1`** (interzis explicit).
-Nu pot garanta ca acel text e sincron 100% cu binarul curent (nu l-am regenerat) — daca vreo linie
-citata pare sa nu corespunda comportamentului live, motivul cel mai probabil e text neactualizat, nu
-o citire gresita.
-
-`D:\ROA\_vfp_textcache\roaauto\_symbols.tsv` exista dar indexeaza **doar `.prg`** (1924 intrari,
-toate `.prg`; niciun `.vc2/.sc2`) — probabil generat inainte de migrarea in-tree. Nu m-am bazat pe
-el; am cautat direct cu Grep in `.vc2`/`.prg` din arbore.
-
-Pentru partea Oracle am gasit sursa curenta a pachetului `PACK_FACTURARE` (COMUN, shared) in
-`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql` (17020 linii,
-cel mai recent script din istoricul de migrari) — folosita ca sursa de adevar pentru semnaturile
-procedurilor.
-
-## 1. Formularul/programul care emite facturi in ROAAUTO
-
-Nu e un formular separat de facturare, ci un **modul apelat din formularul de devize/comenzi**
-(`frm_...` in `oviz_devize.vc2`, clasa cu `cmd_factavans`/`cmd_factfinal`). Logica de facturare
-propriu-zisa e in `Programe/oproceduri_devize.prg`:
-
-- `Procedure factureaza_deviz` — `D:\ROA\ROAAUTO\Programe\oproceduri_devize.prg:846` (semnatura la
- linia 847: `Lparameters tnIdComanda,tcNrOrd,tcNrInmat,tcDenop,tnMultiple,...`).
-- Apelata din formular in `D:\ROA\ROAAUTO\Clase\oviz_devize.vc2` (liniile 1834, 2201, 3146, 4056,
- 4456) prin butoanele de facturare avans/final.
-- Exista si `Procedure relisteaza_factura_deviz` —
- `D:\ROA\ROAAUTO\Programe\oproceduri_devize.prg:1516` — pentru **re-listarea** (re-tiparirea) unei
- facturi deja emise, nu pentru editarea ei.
-
-## 2. Cum scrie in Oracle: aceleasi proceduri, cale comuna cu ROAFACTURARE
-
-Da — **acelasi pachet Oracle `PACK_FACTURARE`** (COMUN, shared cu ROAFACTURARE), apelat prin
-`goExecutor.oExecute`, cu doi apeluri specifice pe langa cele generice:
-
-- `pack_facturare.initializeaza_date_factura(...)` —
- `D:\ROA\ROAAUTO\Programe\oproceduri_devize.prg:1211`
-- `pack_facturare.adauga_articol_factura_deviz(...)` (varianta **_deviz** a
- `adauga_articol_factura`, cu parametri expliciti de pret/gestiune/valuta in loc sa caute articolul
- din nomenclator) — `D:\ROA\ROAAUTO\Programe\oproceduri_devize.prg:1240`, in bucla `Scan`/`Endscan`
- peste cursorul `crsvanztemp`.
-- `oscrie_in_fisiere(0,.F.,.T.)` — `D:\ROA\ROAAUTO\Programe\oproceduri_devize.prg:1269`.
-- `pack_facturare.scrie_incasari(...)` — linia 1294 (doar daca exista incasare la emitere).
-- `pack_facturare.scrie_in_vanzari(0, id_delegat, id_masina, id_facturare, ..., @poDate.nid_vanzare)`
- — linia 1302, **urmata in acelasi `lcSql`** de `pack_auto.actualizeaza_deviz(...)` (linia 1310) —
- un apel specific ROAAUTO, care actualizeaza starea devizului/comenzii dupa facturare (marcheaza
- `RUL`, seteaza `nrfact` etc., nu am citit corpul lui `pack_auto` — pachet separat, nu l-am cautat).
-- Corpul `adauga_articol_factura_deviz` (spec+body in `ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:468`
- si `:4675-4745`) face un simplu `INSERT INTO VANZARI_DETALII_TEMP (...)` — **exact tabela de
- staging** pe care o foloseste si facturarea normala din ROAFACTURARE (`adauga_articol_factura`,
- linia 549 din spec, insereaza in acelasi `VANZARI_DETALII_TEMP`).
-- **Premisa lui Marius e confirmata, cu o nuanta**: ROAAUTO nu scrie direct in `VANZARI_DETALII`; ca
- si fluxul normal, trece prin `VANZARI_DETALII_TEMP`, iar transferul definitiv catre
- `VANZARI`/`VANZARI_DETALII` se face in `pack_facturare.scrie_in_vanzari`
- (`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:915-923` spec, body la `:13497-13962`) — **acelasi
- punct final** pe care il foloseste orice alta facturare ROA (avize, comenzi, contracte). Nu exista
- cale Oracle proprie ROAAUTO pentru scrierea liniilor de factura.
-
-## 3. Tipul de document: `tip = -12`
-
-`factureaza_deviz` construieste obiectul de date cu
-`poDate = Createobject("oDateFactura",lnIdSet,-12)` —
-`D:\ROA\ROAAUTO\Programe\oproceduri_devize.prg:922` — al doilea parametru e `tip`. Clasa
-`oDateFactura` nu am gasit-o definita ca text (nu apare `DEFINE CLASS oDateFactura` in nicio sursa
-text din ROAAUTO sau din COMUN al oricarui proiect cautat) — probabil traieste intr-un `.vcx` inca
-neconvertit sau e generata dinamic; **neverificat** unde anume e clasa, dar e clar shared (folosita
-si in `D:\ROA\ROAFACTURARE\COMUN\clase\ofacturare_comun.vc2`, ex. liniile 3894/4075/7090, cu acelasi
-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`; `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 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
-`tip=-12`** deja, fara cod suplimentar.
-
-## 4. Ce e specific fata de o factura obisnuita
-
-- **Camp de legatura cu masina**: `V_ID_MASINA` e transmis catre `pack_facturare.scrie_in_vanzari`
- (`oproceduri_devize.prg:1304`). Nu e un camp exclusiv ROAAUTO — `ID_MASINA` e coloana standard pe
- `VANZARI`, cunoscuta si de fluxurile generice din pachet: `modifica_date_factura` are parametrul
- `V_ID_MASINA IN NUMBER` (`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:946`), la fel
- `scrie_factura2`, `scrie_factura_avize`, `scrie_factura_avize_retur` (liniile 618-747 din acelasi
- fisier). Deci nu e o bariera de schema — ROAFACTURARE stie deja de `ID_MASINA`.
-- **Liniile facturii nu sunt articole individuale din nomenclator, ci sume cumulate cu
- pseudo-articole (id negative)**: `factureaza_deviz` agrega toate sumele din contul analitic al
- devizului (`actactan`) pe categorii si insereaza cate o linie sintetica per categorie —
- `-100000` MANOPERA (`oproceduri_devize.prg:965-967`), `-100001` DISCOUNT MANOPERA (`:972`),
- `-100003` MATERIALE (`:947-949`), `-100005` AVANS (`:936-937`), `-100006` STORNARE AVANS
- (`: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
- `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).
-- **`pack_auto.actualizeaza_deviz(...)`** e chemat imediat dupa `scrie_in_vanzari`, in acelasi
- bloc SQL (`oproceduri_devize.prg:1310`) — leaga vanzarea nou creata inapoi de deviz/comanda
- (tabelele `DEV_*`/comenzi din ROAAUTO). Corpul lui `pack_auto` nu a fost citit (pachet separat,
- in afara ariei `PACK_FACTURARE` cautate) — **neverificat** ce tabele ROAAUTO scrie exact.
-- **`DEV_TIP_DEVIZ`** (garantie/postgarantie/regie, `oproceduri_devize.prg:1797`) e o clasificare
- **diferita**, a devizului insusi, nu are legatura cu `VANZARI.tip=-12`.
-
-## 5. Cum se modifica azi o astfel de factura
-
-- **Din ROAAUTO**: nu exista editare a liniilor dupa facturare. Formularul de devize/comanda
- (`oviz_devize.vc2`) **dezactiveaza explicit butonul de modificare** dupa ce comanda are numar de
- factura: `Thisform.cmd_modifica1.Enabled=Iif(Empty(nrfact),.T.,.F.)` —
- `D:\ROA\ROAAUTO\Clase\oviz_devize.vc2:4536`. Singura actiune disponibila post-facturare gasita in
- cod e re-listarea (`relisteaza_factura_deviz`, `oproceduri_devize.prg:1516`), care doar reciteste
- antetul/liniile din `fact_vfacturi`/`fact_vfacturi_detalii` pentru reprintare, fara sa scrie
- nimic. N-am gasit niciun apel din ROAAUTO catre `pack_facturare.modifica_date_factura` (grep fara
- rezultate in tot arborele ROAAUTO) — nici macar antetul (delegat/masina/text aditional) nu pare
- editabil din ROAAUTO dupa emitere. **Neverificat**: n-am acoperit tot `oviz_devize.vc2` (fisier de
- >8800 linii) linie cu linie, doar zonele gasite prin grep pe termenii relevanti — nu exclud un alt
- punct de editare cu alt nume de metoda.
-- **Din ROAFACTURARE**: exista deja, in lucru (proiectul S4), un editor de factura care
- **citeste** liniile oricarui `tip` (inclusiv `-12`) din `VANZARI_DETALII` — funcțiile
- `IncarcaVanzareNota`/`IncarcaArticoleFactura` in `COMUN\programe\ofacturare_editare.prg` (adaugate
- conform `docs\cercetare\handoff_s4_runda1.md:79-81`, verificate pe `cod=1140885` -> `id_vanzare=1047`,
- `tip=-12`, `docs\cercetare\rec_datoria6_baza_regresie.md:93`) si formularul `frm_modific2024`
- (`COMUN\clase\omodificari.vc2`), cu un grid nou `grdArticoleFactura` pe pagina 3 "Articole factura".
- **Insa acest grid e in prezent READ-ONLY**: "grid nou `grdArticoleFactura` (...), `ReadOnly` la
- nivel de grid **si** pe fiecare `Text1`" (`docs\cercetare\handoff_s4_runda1.md:80-82`) — deci azi
- se poate **vizualiza**, nu edita, de aici (nici adaugare, nici stergere de linii).
-
-## 6. Se poate adauga azi o linie libera / din lista de preturi pe o astfel de factura?
-
-Pe cod, **nu, din nicaieri, azi**:
-
-- Din ROAAUTO: butonul de modificare a devizului e dezactivat dupa facturare
- (`oviz_devize.vc2:4536`), iar singura cale de scriere gasita (`factureaza_deviz`) ruleaza o
- singura data la emitere; nu exista un `adauga_articol_...` apelabil ulterior pe o vanzare deja
- scrisa. Structura insasi a liniilor (sume cumulate pe pseudo-articole negative, sectiunea 4) e
- diferita de o linie normala de factura cu articol real din lista de preturi — un eventual "adauga
- articol" ar trebui sa lucreze langa niste linii care nu reprezinta articole reale.
-- Din ROAFACTURARE: editorul nou (`frm_modific2024`) **vede** liniile (orice `tip`, deci si cele
- venite din ROAAUTO), dar gridul e read-only — nu exista azi cod de adaugare/scriere pe acest grid.
- Nu am gasit alt formular ROAFACTURARE (`frm_facturi` clasic) care sa editeze articolele unei
- vanzari cu `tip=-12` — cautarea `ROAAUTO` in `D:\ROA\ROAFACTURARE` (in afara de `COMUN`) nu da
- potriviri de cod, doar mentiuni in `docs\` (progres.md, cercetare); `Grep` pe `ROAAUTO` in
- `D:\ROA\COMUNROA` a expirat (arbore prea mare) si nu a fost reincercat — **neverificat** daca
- `COMUNROA` (copia partajata separata de `COMUN` din ROAAUTO/ROAFACTURARE) are vreo referinta
- directa la ROAAUTO.
-
-## Concluzie pentru planul de unificare
-
-Premisa lui Marius se confirma pe cod: facturile ROAAUTO ajung, prin acelasi `PACK_FACTURARE`
-shared si acelasi `VANZARI_DETALII_TEMP` -> `VANZARI_DETALII`, in aceeasi tabela pe care o citeste
-ROAFACTURARE — deci un formular unificat **le poate vedea** fara cod special de recunoastere a
-sursei (dovada: editorul S4 le vede deja, testat pe date reale). Ce lipseste nu e recunoasterea, ci
-**capacitatea de scriere**: azi nimic, in niciun produs, nu poate adauga o linie pe o vanzare
-`tip=-12` — gridul nou din ROAFACTURARE e deliberat read-only, iar ROAAUTO isi blocheaza propriul
-formular dupa facturare. Particularitatea reala de gestionat e ca liniile existente nu sunt articole
-individuale, ci sume cumulate MATERIALE/MANOPERA pe pseudo-articole cu `id_articol` negativ — orice
-UI care adauga articole din lista de preturi "langa" ele trebuie sa decida cum coexista cu randuri
-care nu au `id_gestiune`/nu corespund unui articol real.
diff --git a/docs/cercetare/rute_scriere_antet.md b/docs/cercetare/rute_scriere_antet.md
deleted file mode 100644
index 7798250..0000000
--- a/docs/cercetare/rute_scriere_antet.md
+++ /dev/null
@@ -1,249 +0,0 @@
-# Rute de scriere pe antetul unui document DEJA EMIS (VANZARI/ACT/RUL) — Grupele A/B/C
-
-Cercetare read-only, fara nicio modificare de cod. Sfera: `pack_facturare.modifica_date_factura`
-(14 campuri, deja documentat in `modifica_date_factura_parametri.md`) e confirmata ca **singura**
-cale directa pentru serie/numar/data act/data scadenta + ruta/delegat/masina/agent/dataora_exp/
-id_facturare/listare_detaliata/text_aditional/tip_saft/efactura. Intrebarea de aici: exista alte
-cai, pentru campurile din grupele A/B/C, in afara drumului de emitere initiala.
-
-**Rezumat**
-
-| Camp | Verdict | Nota |
-|---|---|---|
-| A. ID_VENCHELT | NU (cu o rezerva) | vezi pct. 1.4 — posibil editabil direct in grid, neverificat pana la capat |
-| A. ID_SECTIE | **DA** (nou, activ) | prin editare directa a notei contabile, pct. 1.3-1.4 |
-| A. ID_RESPONSABIL | **DA** (nou, activ) | idem |
-| A. ID_LUCRARE | **DA** (nou, activ) | idem |
-| B. ID_FDOC (tip document) | NU | cautat, negasit — pct. 2 |
-| B. ID_VALUTA | NU | cautat, negasit |
-| B. Zi curs | NU | cautat, negasit |
-| B. ID_CLIENT | NU | cautat, negasit |
-| B. sursa/"altele" | NU | cautat, negasit |
-| B. gestiune sursa | NU | cautat, negasit |
-| B. politica de preturi | NU | cautat, negasit |
-| C. opt_incasat/casa/serie chit/nr chit/incasat/POS | NU direct, PARTIAL indirect | scrise doar la emitere (pct. 3.1); posibila cale indirecta prin editarea notei contabile daca incasarea e pe acelasi `cod` (pct. 3.2, neconfirmat pana la capat) |
-
----
-
-## 1. Grupul A — analiticele de antet (ID_VENCHELT, ID_SECTIE, ID_RESPONSABIL, ID_LUCRARE)
-
-### 1.1 Unde traiesc si cum se scriu la emitere
-
-Coloanele sunt pe `ACT` (`ACT.ID_VENCHELT%TYPE`, `ACT.ID_SECTIE%TYPE`, `ACT.ID_RESPONSABIL%TYPE`,
-declarate asa in pachetul Oracle), nu pe `VANZARI`. La emitere, `frm_date_factura`/`frm_date_aviz`
-(`COMUN\clase\ofacturare.vc2:9041-9706` / `:6900-7516`, controale `Ct_clb_venchelt`/`Ct_clb_sectie`/
-`Ct_clb_responsabil`/`Ct_clb_lucrare`) populeaza variabilele de sesiune Oracle
-`pack_facturare.nid_venchelt` / `nid_sectie_stoc` / `nid_responsabil` / `nid_lucrare`
-(`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:1884-1887`), care se scriu o singura data, uniform pe
-tot documentul, in `INSERT INTO ACT_TEMP` la contabilizare (comentariul explicit de la linia 1286
-din `PACK_CONTAFIN.pck`: *"Am completat ID_RESPONSABIL la instructiunile INSERT INTO ACT_TEMP"*).
-Nicaieri in cele doua fisiere Oracle centrale nu exista `UPDATE ACT SET ID_VENCHELT|ID_SECTIE|
-ID_RESPONSABIL|ID_LUCRARE = ...` (grep combinat `UPDATE ACT ... SET` + fiecare coloana, zero
-potriviri, atat in pachetul curent `ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql` cat si in
-`PACK_CONTAFIN.pck`, `PACK_UPDATE.pck`, `PACK_MIGRARE.pck` din `COMUN\docs`).
-
-`frm_date_factura`/`frm_date_aviz` sunt instantiate **doar** din interiorul `ofacturare.vc2`
-insusi (nu am gasit niciun `Createobject` catre ele in afara clasei) — sunt exclusiv wizard-ul de
-la emitere, nu apar pe niciun flux de editare ulterioara.
-
-**Concluzie partiala**: `modifica_date_factura` (calea documentata deja) NU atinge aceste 4
-campuri, si nu exista niciun `UPDATE` Oracle separat pe ele. **Pana aici, verdictul era NU.**
-
-### 1.2 Descoperire care schimba raspunsul: `frm_facturi.do_editare_factura` (functionalitate noua)
-
-Commit-ul cel mai recent din branch (`97d1613`, *"#6 editare factura emisa: omodificari.vcx intra
-in proiect"*) a adaugat exact ce lipsea. Exista deja o cercetare anterioara in acest depozit
-(`docs\cercetare\rec_modific2024.md`, scrisa inainte de acest commit) care documenteaza clasa
-`frm_modific2024` (`COMUN\clase\omodificari.vc2:6375+`, editor generic de nota contabila,
-partajat cu ROAGEST) si concluziona explicit: *"clasa exista deja, dar codul apelant din
-ROAFACTURARE NU exista inca — trebuie scris"*. **Acel gol a fost umplut** — am gasit apelantul,
-cablat si activ:
-
-`COMUN\clase\ofacturare_comun.vc2`, metoda `frm_facturi.do_editare_factura` (~linia 3690-3869):
-
-- Garda: blocheaza daca factura a fost trimisa in eFactura (`EsteInEFactura`, `:3764-3767`).
-- `IncarcaCursoareModificareNota(lnCod, pnAn, pnLuna, .F.)` (helper din `ofacturare_editare.prg`,
- citit dar nemodificat) incarca nota contabila completa (`vact_tot`/`vrul_tot`/`vrul_obinv_tot`
- filtrate pe `cod`) in cursoarele READWRITE `actactan`/`tact`/`rul_temp`/`trul`/
- `rul_temp_obinv`/`trul_obinv` (`:3769`).
-- `Omodif = Createobject([frm_modific2024], lnIdSet)` + `Omodif.Show()` (`:3796-3797`) — deschide
- editorul modal pe cursorul `tact` deja incarcat cu nota facturii curente.
-- Daca userul apasa Terminat (`buton = 1`, `:3799-3833`): deschide tranzactie manuala, sterge nota
- veche (`OSCRIE_IN_FISIERE(2,.T.,.T.)`), rescrie din cursoarele editate (`tact`->`actactan`,
- `trul`->`RUL_TEMP`, `trul_obinv`->`RUL_TEMP_OBINV`, cu `id_util`/`sters=0` noi),
- `OSCRIE_IN_FISIERE(0,.T.,.T.)` (scriere noua), apoi
- `pack_contafin.finalizeaza_modificare_nota(...)`, commit/rollback.
-
-Acest `finalizeaza_modificare_nota` (`PACK_CONTAFIN.pck:8601-8651`, citat deja in
-`rec_modific2024.md`) **resincronizeaza `vanzari`** dupa editare: `SELECT COUNT(*) FROM vanzari
-WHERE cod = tnCod; IF > 0 THEN pack_facturare.actualizeaza_vanzari(tnCod, lnCodNou); END IF;`.
-
-### 1.3 Ce e efectiv editabil in `tact`/`trul` — verificat prin `do_modifica`
-
-`frm_modific2024.do_modifica` (`omodificari.vc2:13836-13957`) e mecanismul generic prin care un
-camp din grid deschide un dialog de cautare (`cauta_alfa`) si apoi face `REPLACE` pe cursorul
-corespunzator. Pentru `trul`/`trul_obinv` (nivel LINIE de nota, nu antet unic), `CASE` explicit
-gestioneaza:
-
-```
-CASE m.lcControl = 'nrord' -> replace nrord with loCauta.nrord, id_lucrare with loCauta.id_lucrare
-CASE m.lcControl = 'sectie' -> replace sectie with loCauta.sectie, id_valuta with loCauta.id_sectie (!)
-CASE m.lcControl = 'nresp' -> replace nresp with loCauta.nume, id_responsabil with loCauta.id_responsabil
-```//omodificari.vc2:13934-13943
-
-Deci **ID_LUCRARE si ID_RESPONSABIL sunt editabile explicit**, pe cursorul `trul` (nivel de linie
-RUL), prin acest mecanism, azi, din UI, prin `do_editare_factura`. Linia `sectie` are ce pare a fi
-un bug preexistent (`replace ... id_valuta with loCauta.id_sectie` in loc de `id_sectie` — cod
-existent, nu l-am atins, doar il semnalez ca observatie relevanta pentru evaluarea "functioneaza
-sau nu in practica"): daca bug-ul e real, campul afisat `sectie` (text) se schimba, dar coloana
-`id_sectie` propriu-zisa risca sa NU se actualizeze corect (se suprascrie `id_valuta` in loc).
-Nu am testat comportamentul, doar am citit codul.
-
-**ID_VENCHELT**: NU exista un caz `CASE m.lcControl = 'venchelt'` (sau `dst_chlt`) in
-`do_modifica` pentru `trul`/`trul_obinv` — cautat explicit in tot procedeul (13836-13957), zero
-potriviri. Insa Grid1 al clasei (proprietatile de coloana, in afara metodelor) are o coloana cu
-`ControlSource = "dst_chlt"` (`omodificari.vc2:753, 2862, 7393` — a treia aparitie e in intervalul
-propriu al clasei `frm_modific2024`), deci explicatia venit/cheltuiala **e afisata** in grid. Daca
-acea coloana permite editare directa de text (nu prin popup de cautare) sau daca exista un alt
-handler (buton dedicat, dublu-click) care leaga `id_venchelt`, nu am verificat pana la capat — vezi
-"Necunoscute ramase". **Raspuns pentru ID_VENCHELT: NU confirmat ca ruta activa, dar cu o rezerva
-neinchisa** (grid-ul afiseaza coloana, mecanismul de editare exact al ei nu a fost trasat complet).
-
-### 1.4 Nivel LINIE vs. nivel ANTET
-
-O nuanta importanta: campurile din grupul A, la nivel Oracle, traiesc pe `ACT` (fiecare linie de
-nota isi are propriile `ID_VENCHELT`/`ID_SECTIE`/`ID_RESPONSABIL`/`ID_LUCRARE`), desi la EMITERE
-se scriu uniform (aceeasi valoare pe toate liniile unui document, din variabilele de sesiune).
-Editarea prin `frm_modific2024` e la nivel de LINIE (fiecare rand din `trul` se editeaza separat),
-nu o singura bifa de antet — deci userul poate, teoretic, sa lase valori diferite pe linii diferite
-ale aceleiasi facturi dupa editare, lucru care nu se putea intampla la emiterea initiala (uniforma).
-Asta conteaza pentru orice raportare care presupune "un singur ID_SECTIE per factura".
-
-**Verdict grup A**: **DA** pentru `ID_SECTIE`/`ID_RESPONSABIL`/`ID_LUCRARE` (cale noua, activa,
-`frm_facturi.do_editare_factura` -> `frm_modific2024` -> `OSCRIE_IN_FISIERE` ->
-`pack_contafin.finalizeaza_modificare_nota` -> Oracle `ACT`/`RUL`, cu resincronizare in `VANZARI`).
-**NU confirmat** pentru `ID_VENCHELT` prin acelasi mecanism generic (`do_modifica` nu are caz
-pentru el), dar cu rezerva de la 1.3 neinchisa complet.
-
----
-
-## 2. Grupul B — identitate/sursa (fdoc, valuta, zi curs, client, altele, gestiune sursa,
-politica preturi)
-
-Controalele (`Ct_clb_fdoc`, `Ct_clb_valuta`, `Clb_zi_curs`, `Ct_clb_nume_client`, `Ct_clb_altele`,
-`Ct_clb_gestiune_init`, `Ct_clb_politici_preturi`) au fost gasite **exclusiv** in metodele proprii
-ale `frm_date_aviz`/`frm_date_factura`/`frm_date_aviz_lucrare` din `ofacturare.vc2` — acelasi
-wizard de emitere de la grupul A (cautare `vfp_symbols.ps1 -Grep` pe toate cele 7 nume de
-control, in tot proiectul indexat: 316 fisiere, zero potriviri in afara `ofacturare.vc2`).
-
-Cautat in Oracle (pachetul curent + `PACK_CONTAFIN.pck` + `PACK_UPDATE.pck` + `PACK_MIGRARE.pck`):
-`UPDATE VANZARI ... SET (ID_FDOC|ID_VALUTA|ID_CLIENT|ID_PART|ID_GESTIN|ID_POL) = ...` si
-`UPDATE ACT ... SET` idem — zero potriviri (grep multiline, fereastra 400 caractere dupa
-`UPDATE`). Toate cele 13 aparitii ale `UPDATE VANZARI` din pachetul curent au fost inspectate
-individual (`sterge_factura`, `sterge_proforma`, `marcheaza_facturat`,
-`scrie_corespondente_vanzari`, plus `modifica_date_factura`) — niciuna nu atinge aceste coloane
-(ating `STERS`/`FACTURAT`/`ID_UTILFACT`/`DATA_FACTURAT`/`AVIZE`/`COD`/serie-numar-data-scadenta).
-
-`frm_modific2024`/`do_editare_factura` (descoperirea de la grupul A) nu ajuta aici: cursoarele pe
-care le editeaza (`tact`/`trul`/`trul_obinv`) sunt nota contabila (conturi, sume, gestiuni de
-STOC, TVA) — nu contin fdoc/valuta document/client/politica de preturi ale facturii; acestea sunt
-proprietati ale `VANZARI`, populate o singura data la `scrie_factura2`/`scrie_in_vanzari`, in afara
-oricarui flux gasit de editare ulterioara.
-
-**Verdict grup B: NU**, pentru toate cele 7 campuri — cautat si negasit, in ambele straturi
-(Oracle: pachetul de facturare curent + cele 3 pachete conexe; VFP: toate clasele indexate de
-`vfp_symbols.ps1`, 1128 clase / 9281 metode / 2461 proceduri).
-
----
-
-## 3. Grupul C — incasarea
-
-### 3.1 Unde se scrie la emitere
-
-Controalele din `frm_alte_date` (`COMUN\clase\ferestre_cere_date.vc2:2219+`) — `opt_incasat`,
-`Cb_casa`, `Clb_serie_chit`, `Clb_nrchit`, `Clb_incasat`, `chkPOS` — au `ControlSource` pe
-proprietati ale obiectului `poDate` (`poDate.nIncasatPos`, si prin cod pe `poDate.incasat`,
-`poDate.nr_incasare`, `poDate.ntip_incasare`, `poDate.id_casa`, `poDate.serie_chit`), NU pe un
-cursor legat direct de tabel. `frm_alte_date` e instantiat exclusiv din
-`frm_facturare_articole(2).inainte_de_do_termin` si din doua fluxuri de listare
-(`ofacturare.prg:listare_protocol`, `ofacturare_stoc.prg:oscrie_vanzare_din_stoc`,
-`oproceduri_listari.prg:listare_protocol`) — toate parti ale fluxului de EMITERE, niciuna de
-editare ulterioara.
-
-La `do_scrie_factura` (`ofacturare.vc2:14260-14389`, ambele forme `frm_facturare_articole` si
-`frm_facturare_articole2`), valorile din `poDate` sunt asamblate intr-un string
-`lcListaIncasare` (format `tip|suma|id_casa;...`) si trimise ca parametru la
-`pack_facturare.scrie_factura2` / `scrie_factura_avize` / `scrie_proforma` (apel RPC unic, la
-emitere). In Oracle, `scrie_factura2` cheama intern `pack_facturare.scrie_incasari` (linii 6204,
-7034 din pachetul curent), care parseaza lista si cheama `scrie_incasare2` per linie
-(`:13096-13168` -> `:13170+`) — aceasta insereaza o **nota contabila noua in `ACT_TEMP`**
-(coloane vazute: `ACT.SUMA`, `ACT.ID_PARTD` pentru casa/banca, `ACT.ASCC`/`SCD`/`ASCD`,
-`ACT_TEMP.PAYMENTCODE`), adica incasarea devine ea insasi o linie de jurnal (cont 5311/5121 etc.
-vs. 4111), scrisa prin acelasi flux `ACT_TEMP -> ACT` ca restul documentului, nu un camp separat
-pe `VANZARI`. `scrie_incasare2` nu are niciun apelant in afara lui `scrie_incasari` (cautat cu
-grep in tot pachetul de facturare — un singur call-site).
-
-### 3.2 Cale de schimbare DUPA emitere
-
-Nu exista nicio procedura Oracle de tip "modifica_incasare"/"corecteaza_incasare" (cautat
-`PROCEDURE ... (modifica|corecteaza|actualizeaza)...incasa...` in pachetul curent si
-`PACK_CONTAFIN.pck` — zero potriviri). `scrie_incasari`/`scrie_incasare2` nu au niciun apelant VFP
-direct (cautat in tot proiectul indexat — zero potriviri) — sunt folosite doar intern, o singura
-data, la emitere.
-
-**PARTIAL, neconfirmat pana la capat**: incasarea scrisa la emitere e o linie de nota contabila
-(`ACT`/`RUL`) ca oricare alta. Daca acea linie foloseste acelasi `cod` (acelasi document contabil)
-ca restul facturii, atunci mecanismul nou de la Grupul A (`frm_facturi.do_editare_factura` ->
-`frm_modific2024`) ar incarca-o si pe ea in grid — si, editand campurile generice de nota
-(cont/gestiune/suma, prin acelasi `do_modifica` sau direct in grid), un utilizator ar putea
-schimba indirect suma/contul incasarii, deci si `casa`/`suma incasata` efectiva. **Nu am confirmat
-daca incasarea primeste acelasi `cod` sau un `cod` separat** — ar necesita fie testare live
-(interzisa aici, doar cercetare pe cod), fie citirea completa a insertiei din `scrie_incasare2`
-(am citit doar semnatura si primele ~35 linii, nu INSERT-ul propriu-zis in `ACT_TEMP`). Marchez
-explicit ca necunoscuta ramasa, nu ca "DA" confirmat.
-
-`opt_incasat`/`chkPOS`/serie-numar chitanta/bon **ca atare** (proprietati `poDate` folosite doar
-pentru alocarea de numere de serie si generarea listei `lcListaIncasare`) nu au niciun camp
-persistent separat pe care sa-l poata atinge editarea ulterioara a notei — nu exista coloane
-`VANZARI.OPT_INCASAT`/`VANZARI.SERIE_CHIT` in tot ce am cautat.
-
-**Verdict grup C**: NU pentru o cale directa/documentata de schimbare dupa emitere; PARTIAL,
-neconfirmat, prin editarea generica a notei contabile (acelasi mecanism nou de la Grupul A),
-DACA incasarea partajeaza `cod`-ul cu restul documentului.
-
----
-
-## Ce am cautat (pentru un "NU" verificabil)
-
-- **Oracle**: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql`
- (17020 linii, pachetul curent) — grep pe `UPDATE VANZARI`, `UPDATE ACT`, `UPDATE DOCUMENTE` (toate
- aparitiile citite in context), plus grep combinat `UPDATE ... SET =` (fereastra
- multiline 300-400 caractere) pentru fiecare coloana din grupele A/B/C. Idem pe
- `D:\ROA\ROAFACTURARE\COMUN\docs\PACK_CONTAFIN.pck` (9041 linii), `PACK_UPDATE.pck` (2420 linii),
- `PACK_MIGRARE.pck` (407 linii).
-- **VFP**: `vfp_symbols.ps1 -Grep -CodeOnly` (index complet: 316 fisiere, 1128 clase, 9281 metode,
- 2461 proceduri) pentru fiecare nume de coloana Oracle si fiecare nume de control VFP din enunt
- (`Ct_clb_venchelt/sectie/responsabil/lucrare/fdoc/valuta/altele/gestiune_init/politici_preturi`,
- `Clb_zi_curs`, `opt_incasat`, `Cb_casa`, `Clb_serie_chit`, `Clb_nrchit`, `Clb_incasat`, `chkPOS`).
- Pentru fiecare formular gasit (`frm_date_factura`, `frm_date_aviz`, `frm_alte_date`), am cautat
- toti apelantii (`Createobject("...")`) in tot proiectul indexat, ca sa confirm ca sunt doar pe
- fluxul de emitere.
-- **Citire, fara scriere**: `ofacturare_comun.vc2` (metoda `do_editare_factura`, ~3690-3869) si
- `ofacturare_editare.prg` (integral, 457 linii) — apartin altui fir de lucru, doar citite.
-- `omodificari.vc2` (16464 linii) — clasa `frm_modific2024`: citite integral `do_modifica`
- (13836-13957) si `do_salvare` (13985-14042); NU am citit toate cele ~180 de metode ale clasei
- (Grid1.Column*, pgfArticole.*) — posibil sa existe alte cai de editare directa in grid,
- nedescoperite prin `do_modifica`.
-
-## Necunoscute ramase
-
-1. **ID_VENCHELT** (grup A): daca e editabil in grid-ul `frm_modific2024` prin alt mecanism decat
- `do_modifica` (coloana `dst_chlt` exista in grid) — neverificat pana la capat.
-2. **Incasarea pe acelasi `cod`** (grup C): daca linia de incasare scrisa de `scrie_incasare2`
- foloseste acelasi `cod` ca restul facturii (ceea ce ar face-o editabila prin
- `do_editare_factura`) — necesita citirea INSERT-ului efectiv in `ACT_TEMP` din
- `scrie_incasare2` (nu doar semnatura, citita aici doar partial) sau verificare pe date reale.
-3. **Bug-ul de la `sectie`** (`omodificari.vc2:13941`, `id_valuta with loCauta.id_sectie` in loc de
- `id_sectie`) — semnalat ca observatie, nu investigat mai departe (nu face parte din intrebare,
- dar afecteaza increderea in verdictul "DA" pentru `ID_SECTIE": campul e teoretic editabil, dar
- codul care il scrie pare sa aiba un bug care ar putea sa nu-l actualizeze corect in practica).
diff --git a/docs/cercetare/s10_pret_contract_reemitere.md b/docs/cercetare/s10_pret_contract_reemitere.md
deleted file mode 100644
index 7fb8183..0000000
--- a/docs/cercetare/s10_pret_contract_reemitere.md
+++ /dev/null
@@ -1,468 +0,0 @@
-# S10 (runda 3) — Proiectare: pretul re-derivat din contract la reemiterea #13
-
-Agent de proiectare (research), read-only. Nicio editare de cod, nicio scriere Oracle in afara de
-`SELECT`. Sursa SQL: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`
-(17217 linii — **de data asta liniile citate coincid exact cu cele din raportul vechi
-`s10_pret_rederivat.md`, fara offset**). Date verificate pe `MARIUSM_AUTO@ROA_CENTRAL`, doar
-`SELECT`, 11.08.2026 — baza de dezvoltare, esantion mic (vezi sectiunea 2), nu productie.
-
-## 0. Rezumat
-
-**Intrebare adaugata de team-lead, raspuns scurt: NU.** `cursor_retur_document` (procedura folosita
-la INCARCAREA liniilor unui document existent, apelata din VFP cu `V_COPIERE=1`) **citeste pretul
-ca atare din `VANZARI_DETALII.PRET`, nu il re-deriva** — nu exista niciun `JOIN` catre
-`CTR_ARTICOLE`/`CRM_POLITICI_PRET_ART` in toata procedura (`:3949-4062`). Presupunerea din S8b se
-confirma pe cod. Detaliu complet, cu dovezi, in sectiunea 1bis (nou adaugata, tratata ca prioritara
-fata de restul raportului, conform cererii).
-
-**Faptul portant (scrierea, nu citirea) se reconfirma integral** (`:5146-5185`) si se extinde cu
-doua descoperiri noi:
-
-1. **TVA-ul si identitatea valutei sunt re-derivate din exact acelasi `JOIN`/`SELECT` ca pretul**,
- pe aceeasi ramura de contract — nu doar pretul e in pericol la reemitere, ci pretul + cota de
- TVA + valuta articolului, impreuna, tot-sau-nimic (sectiunea 3).
-2. **Nu exista nicio a doua re-derivare mai departe in lant** — `PRET` trece neschimbat de la
- `VANZARI_DETALII_TEMP` in `VANZARI_DETALII` (`scrie_in_vanzari`, `:13705-13757`, coloana `PRET`
- copiata direct, fara `DECODE`/recalcul) si `contabilizeaza_articol` nu scrie niciodata pe
- `VANZARI_DETALII.PRET` (scrie doar `ACT_TEMP`, nota contabila). Singurul loc de re-derivare e
- `adauga_articol_factura:5146-5185` (sectiunea 1) — **la scriere, niciodata la citire** (sectiunea
- 1bis).
-
-Pe date reale (esantion mic, baza de dezvoltare): **3 din 11 linii deja facturate pe contract au
-azi un pret de contract diferit de pretul efectiv facturat** — divergenta nu e ipotetica, e deja
-prezenta (sectiunea 2).
-
-**Recomandare** (detaliata in sectiunea 4): varianta **(c) avertizare + confirmare explicita**,
-implementabila integral in VFP cu `goExecutor` (fara sa ating `pack_facturare`, conform deciziei
-27-bis), cu optiunea de a trece la **(b) blocare stricta** daca Marius prefera zero schimbari
-tacite vreodata. Varianta **(d) ocolire a ramurii** e posibila mecanic dar produce o regresie reala
-(pierderea legaturii `VANZARI_DETALII.ID_CTR`) — **nu o recomand**.
-
----
-
-## 1. Reverificarea faptului portant
-
-Cod citit direct din sursa (`:5039-5220`), nu preluat din raportul vechi.
-
-```sql
--- :5039-5050 — V_OPT_FACTURARE se calculeaza intern, din V_ID_CTR primit de la VFP
-IF pack_facturare.ntip IN (2, 6, 26, 52) THEN
- BEGIN
- SELECT NVL(OPT_FACTURARE, 3) INTO V_OPT_FACTURARE FROM CONTRACTE WHERE ID_CTR = V_ID_CTR;
- EXCEPTION
- WHEN NO_DATA_FOUND THEN
- V_OPT_FACTURARE := 4;
- END;
-END IF;
-```
-
-```sql
--- :5146-5185 — ramura de contract, in interiorul CASE-ului principal (:5052-5220)
-WHEN V_OPT_FACTURARE = 3 THEN
- BEGIN
- SELECT DECODE(A.PRET_UNITAR, 0, V_PRET_TEMP, A.PRET_UNITAR),
- B.PROC_TVAV,
- B.ID_VALUTA,
- A.PRET_CU_TVA,
- C.IN_STOC
- INTO V_PRET, V_PROC_TVAV, V_ID_VALUTA, V_PRETURI_CU_TVA, V_IN_STOC
- FROM CTR_ARTICOLE A
- LEFT JOIN CRM_POLITICI_PRET_ART B ON A.ID_POL_ART = B.ID_POL_ART
- LEFT JOIN NOM_ARTICOLE C ON B.ID_ARTICOL = C.ID_ARTICOL
- WHERE B.ID_ARTICOL = V_ID_ARTICOL AND A.ID_CTR = V_ID_CTR AND B.ID_POL = V_ID_POL;
- EXCEPTION
- WHEN NO_DATA_FOUND THEN
- ... V_PRET := V_PRET_TEMP; V_ID_VALUTA := V_ID_VALUTA_TEMP; V_PRETURI_CU_TVA := V_PRETURI_CU_TVA_TEMP; V_IN_STOC := V_IN_STOC_TEMP;
- END;
-```
-
-**Confirmat, cuvant cu cuvant fata de runda 9**: cu `OPT_FACTURARE = 3` (sau `NULL`, implicit 3),
-daca `CTR_ARTICOLE.PRET_UNITAR <> 0`, acea valoare **inlocuieste** `V_PRET_TEMP` (pretul trimis de
-VFP), necondiționat de faptul ca operatorul a atins sau nu linia. Procedura **nu are nicio notiune
-de reemitere** — parametrii sunt toti `IN` (`:4989-5059`, verificat), niciun canal care sa spuna
-"nu recalcula". `NO_DATA_FOUND` (politica/articol lipsa) e singurul caz care respecta pretul
-trimis.
-
-### Nu exista alt loc care suprascrie pretul
-
-- **`scrie_in_vanzari`** (`:13488+`), care muta liniile din `VANZARI_DETALII_TEMP` in
- `VANZARI_DETALII` (tabela finala) la finalizarea documentului: `PRET` e in lista de coloane
- copiate **neschimbat** (`:13705-13757`, `SELECT ... PRET ... FROM VANZARI_DETALII_TEMP` →
- `INSERT INTO VANZARI_DETALII (..., PRET, ...)`), fara `DECODE`/recalcul. Cautare exhaustiva pe
- fisier: **zero** `INSERT INTO VANZARI_DETALII` (tabela finala, nu `_TEMP`) in afara de acest
- punct.
-- **`contabilizeaza_articol`** (`:7173-7547`, reconfirmat structural fata de runda 9) citeste
- `detalii_articol.pret` (randul deja scris in `VANZARI_DETALII_TEMP`) doar ca sa calculeze suma
- notei contabile — nu scrie niciodata inapoi pe `VANZARI_DETALII.PRET`.
-- **`modificare_politica_stoc`** (`:2122-2135`) face un `UPDATE CRM_POLITICI_PRET_ART SET PRET=0,
- ...` — e singurul alt `SET PRET` gasit in tot fisierul, dar reseteaza **politica** la schimbarea
- monedei stocului, complet in afara lantului de facturare a unei linii; nu atinge vreo linie de
- document.
-
-**Concluzie sectiune**: raspunsul din runda 9 se confirma **integral**, fara nicio corectie, si se
-inchide explicit intrebarea "mai exista si alte locuri" — nu mai exista.
-
----
-
-## 1bis. Citirea la incarcare: `cursor_retur_document` re-deriva pretul?
-
-**Adaugat la cererea team-lead-ului — critic pentru S8b, tratat ca prioritar.**
-
-### Verdict: NU. Pretul se citeste ca atare din `VANZARI_DETALII.PRET`, fara nicio re-derivare.
-
-Corp complet, `PACK_FACTURARE:3949-4062`:
-
-```sql
-PROCEDURE cursor_retur_document(V_IN_VALUTA IN NUMBER,
- V_LISTAID IN VARCHAR2,
- V_COPIERE IN NUMBER,
- V_PROFORMA IN NUMBER,
- V_ID_UTIL IN NUMBER,
- V_CURSOR OUT cursor_facturare) IS
-...
-BEGIN
- pack_facturare.initializeaza_facturare(V_ID_UTIL);
-
- OPEN V_CURSOR FOR
- WITH CRS AS (SELECT X as ID_VANZARE FROM table(charn2collection(V_LISTAID, V_SEPARATOR)))
- SELECT ROWNUM AS ID_C, A.ID_ARTICOL, A.LOT, A.SERIE, A.ID_POL, A.ID_VALUTA,
- ... DISCOUNT_UNITAR (derivat din A.DISCOUNT_UNITAR) ...,
- B.CODMAT, B.CODBARE, B.DENUMIRE, NVL(B.UM,'') AS UM,
- ... GESTIONABIL ..., A.CANTITATE, A.PROC_TVAV, A.ID_JTVA_COLOANA,
- A.PRET_CU_TVA AS PRETURI_CU_TVA, A.CURS, A.MULTIPLICATOR,
- (CASE WHEN NVL(C.MONEDA_NATIONALA,1)<>1
- THEN ROUND(A.CURS * ROUND(A.PRET, pack_sesiune.nzecimale_pretvval) / NVL(A.MULTIPLICATOR,1), pack_sesiune.nzecimale_pretv)
- ELSE ROUND(A.PRET, pack_sesiune.nzecimale_pretv)
- END) + A.DIFERENTA AS PRET,
- ...
- FROM (SELECT A1.ID_ARTICOL, A1.LOT, A1.SERIE, A1.ID_POL, A1.DISCOUNT_UNITAR, A1.DIFERENTA,
- A1.CANTITATE, A1.PROC_TVAV, A1.ID_JTVA_COLOANA,
- NVL2(A1.ID_GESTIUNE,1,0) AS GESTIONABIL, A1.PRET_CU_TVA, A1.PRET, A1.ID_VALUTA,
- NVL(A2.CURS,0) AS CURS, NVL(A2.MULTIPLICATOR,1) AS MULTIPLICATOR,
- A1.EXPLICATIE, A1.ID_GESTIUNE, A1.PRET_ACHIZITIE, A1.PRETD, A1.ID_JTVA_COLOANA_EX
- FROM VANZARI_DETALII A1
- LEFT JOIN VANZARI_CURSURI A2 ON A1.ID_VANZARE = A2.ID_VANZARE AND A1.ID_VALUTA = A2.ID_VALUTA
- WHERE A1.STERS = 0 AND A1.ID_VANZARE IN (SELECT ID_VANZARE FROM CRS)) A
- LEFT JOIN NOM_ARTICOLE B ON A.ID_ARTICOL = B.ID_ARTICOL
- LEFT JOIN NOM_VALUTE C ON A.ID_VALUTA = C.ID_VALUTA
- ORDER BY B.DENUMIRE;
-END cursor_retur_document;
-```
-
-**Analiza surselor, coloana cu coloana:**
-
-- **`A.PRET`** (`:4009-4015`, alias final `PRET`) vine din subquery-ul `A` care e
- **`VANZARI_DETALII A1`** direct (`A1.PRET`, `:4041`) — **nicio referinta la
- `CTR_ARTICOLE`/`CRM_POLITICI_PRET_ART`/`CRM_POLITICI_PRETURI` in toata procedura** (cautare
- exhaustiva pe corpul de la `:3949-4062`: zero hit-uri pentru oricare din cele trei tabele).
- Singurele `JOIN`-uri sunt:
- - **`VANZARI_CURSURI A2`** (`:4051-4053`), pe `ID_VANZARE`+`ID_VALUTA` — aduce `CURS`/
- `MULTIPLICATOR` **stocate pe documentul insusi** (cursul valutar de la momentul cand a fost
- scris, nu un curs "de azi" recalculat — tabela `VANZARI_CURSURI`, nu `CURS`).
- - **`NOM_ARTICOLE B`** (`:4056-4057`) — doar campuri descriptive (`CODMAT`, `CODBARE`,
- `DENUMIRE`, `UM`), acelasi tipar confirmat deja in `rec_pret_lazy.md` A2 pentru alte cursoare
- din pachet — niciodata sursa de pret.
- - **`NOM_VALUTE C`** (`:4058-4059`) — doar `MONEDA_NATIONALA`/`NUME_VAL`, folosit in `CASE` ca sa
- decida **cum se formateaza** afisarea (lei vs. valuta), nu ca sa aduca un pret alternativ.
- - Expresia finala pe `PRET` e o **transformare de afisare** a lui `A.PRET` (rotunjire +
- conversie in valuta folosind `A.CURS`/`A.MULTIPLICATOR` **stocate pe document**) plus
- `A.DIFERENTA` (coloana proprie pe `VANZARI_DETALII`, un ajustaj deja persistat pe linie, nu o
- recalculare live) — nu o re-derivare dintr-o sursa externa.
-- **Acelasi tipar pe `DISCOUNT_UNITAR`, `PROC_TVAV`, `ID_VALUTA`, `PRET_CU_TVA`** — toate citite
- direct din `A1.*` (`VANZARI_DETALII`), fara vreun `JOIN` catre politica/contract.
-
-**Confirmare suplimentara pe partea VFP — `cursor_retur_document` cu `V_COPIERE=1` e chiar calea
-folosita la reincarcarea unui document existent, cu prioritate fata de ramura de contract**:
-
-```
-COMUN\programe\ofacturare.prg:266-283
-Do Case
- Case m.llCopiere
- lcSqlCursor = [{call pack_facturare.cursor_retur_document(?poDate.in_valuta,?poDate.listaid,1,?poDate.eProforma,?gnIdUtil)}]
- Case Inlist(tnTip, 48, 49)
- ...
- Case tnTip = 45
- ...
- Case Inlist(tnTip, 1, 22, 5, 29, 7, 10, 23) && lista de preturi
- ...
- Case Inlist(tnTip, 2, 26, 6, 52) && contract
- lcSqlCursor = [{call ]+gcS+[.pack_facturare.cursor_contract(...)}]
-```
-
-`Do Case` in VFP executa **doar prima ramura adevarata**. Cand `llCopiere` e activ (incarcarea unui
-document existent — exact scenariul "editare prin regenerare" descris de team-lead), procedura
-apelata e **intotdeauna** `cursor_retur_document`, **indiferent de `tnTip`** — ramura de contract
-(`cursor_contract`, `:283+`) nu se mai ajunge deloc, chiar daca documentul e de tip 2/6/26/52.
-`cursor_retur` (`:3934-3947`) e doar un wrapper subtire peste `cursor_retur_document` cu
-`V_COPIERE=0`/`V_PROFORMA=0`, pentru returul propriu-zis — nu schimba concluzia.
-
-### Consecinta pentru S8b
-
-**Presupunerea "re-derivarea e o proprietate a scrierii, nu a citirii" se confirma pe cod, fara
-rezerve.** Deschiderea formularului de editare (etapa II, incarcarea liniilor existente) **nu**
-declanseaza nicio re-derivare de pret/TVA/valuta — documentul apare "neschimbat" la simpla
-deschidere, exact cum a presupus S8b. Mecanismul de detectare a schimbarii (compara starea
-incarcata cu starea la confirmare) **poate functiona ca premisa** — riscul de suprascriere tacita
-descris in restul acestui raport (sectiunile 1-6) apare **doar la re-scriere** (regenerare efectiva
-prin `adauga_articol_factura`), nu la incarcare. Cele doua momente (citire la deschidere, scriere
-la regenerare) sunt guvernate de **cursoare Oracle complet diferite** (`cursor_retur_document` vs.
-`adauga_articol_factura`), fara cod comun — o modificare facuta doar pe unul din ele (de exemplu o
-garda adaugata la scriere, variantele (b)/(c) din sectiunea 4) **nu afecteaza** comportamentul
-celuilalt.
-
----
-
-## 2. Tipurile afectate si frecventa in date
-
-**Tipurile de document**: `pack_facturare.ntip IN (2, 6, 26, 52)` (`:5039`), confirmat identic cu
-tabelul din `rec_editare_factura.md:176` (contract = tip 2/6/26/52, ramura de scriere
-`scrie_factura2`, la fel ca lista de preturi — nu are RPC separat).
-
-**Frecventa in date** (schema `MARIUSM_AUTO`, doar `SELECT`, 11.08.2026):
-
-```sql
--- VANZARI_DETALII cu ID_CTR populat, active: 74
--- din care, articolul are un rand corespunzator in CTR_ARTICOLE (id_ctr+id_articol): 11
--- din acelea, CTR_ARTICOLE.PRET_UNITAR <> 0 SI diferit de VANZARI_DETALII.PRET: 3
--- din acelea, CTR_ARTICOLE.PRET_UNITAR <> 0 SI egal cu VANZARI_DETALII.PRET: 8
--- din acelea, CTR_ARTICOLE.PRET_UNITAR = 0 (nu suprascrie): 0
-```
-
-**Interpretare, cu grija la marimea esantionului**: baza e de dezvoltare, cu doar 27 randuri totale
-in `CTR_ARTICOLE` — nu extrapolez procentul (27%) la volumul de productie. Dar **3 cazuri reale,
-nu zero**, e dovada suficienta ca fenomenul **chiar se intampla**, nu doar teoretic: daca oricare
-din cele 3 facturi ar fi reemisa azi prin regenerare (#13 etapa II), suma ei s-ar schimba tacit,
-fara nicio actiune a operatorului legata de pret. Simetric, cele 8 cazuri "egal" arata ca in
-majoritatea situatiilor curente reemiterea ar fi azi inofensiva — ceea ce face problema mai
-insidioasa, nu mai putin reala: cand se produce, nimeni nu se astepta, pentru ca de obicei nu se
-intampla nimic vizibil.
-
-**Nu exista coloana de audit pe `CTR_ARTICOLE`** (confirmat din `user_tab_columns`: `ID_CTR_ART,
-ID_CTR, ID_POL_ART, PRET_UNITAR, CANT, COEF_DISCOUNT, VAL_DISCOUNT, ID_VALUTA, EXPLICATIE, UM,
-ID_ARTICOL, PRET_CU_TVA, ID_LOCATIA, PROC_TVAV, VALOARE` — nicio `DATA_MODIF`/`ID_UTIL_MODIF`) —
-nu exista cale de a masura *cat de des* se schimba `PRET_UNITAR` in timp, doar *cate cazuri
-divergente exista azi*. Raspunsul la "cat de des" ramane nedeterminabil din date; ce se poate
-spune e doar ca divergenta **exista deja**, azi, pe un esantion mic.
-
----
-
-## 3. Descoperire noua: TVA si valuta sunt re-derivate din **aceeasi** interogare ca pretul
-
-Din citatul de la sectiunea 1: `SELECT DECODE(A.PRET_UNITAR, ...), B.PROC_TVAV, B.ID_VALUTA, ...`
-— **un singur `SELECT`**, trei valori. Asta inseamna ca varianta de raspuns nu poate trata pretul
-izolat: daca politica de pret a contractului (`CRM_POLITICI_PRET_ART`, aceeasi `B`) si-a schimbat
-si cota de TVA sau valuta intre timp, reemiterea le suprascrie **pe amandoua**, prin acelasi
-mecanism, in aceeasi conditie (`NO_DATA_FOUND` → respecta ce a trimis VFP; altfel → suprascrie).
-
-Comparativ cu discountul si cursul (reconfirmare fata de runda 9, sectiunile 6-7 ale raportului
-vechi, verificate din nou pe sursa curenta):
-
-| Camp | Tratament pe ramura de contract | Risc la reemitere |
-|---|---|---|
-| **Pret** (`V_PRET`) | `DECODE(A.PRET_UNITAR, 0, V_PRET_TEMP, A.PRET_UNITAR)` — suprascris daca `PRET_UNITAR<>0` | **Da — faptul portant** |
-| **TVA** (`V_PROC_TVAV`) | `B.PROC_TVAV`, din acelasi `SELECT`, fara fallback conditionat separat | **Da — aceeasi conditie ca pretul** |
-| **Valuta articol** (`V_ID_VALUTA`) | `B.ID_VALUTA`, idem | **Da — aceeasi conditie** |
-| **Discount** (`V_DISCOUNT_UNITAR`) | Parametru trimis de VFP, scris direct in `INSERT` (`:5266`), nicio ramura din `CASE` il citeste | **Nu — mereu respectat, indiferent de ramura** |
-| **Curs** (`V_CURS`) | `DECODE(V_CURS, 0, 1, V_CURS)` la `INSERT` (`:5270`) — inlocuieste doar 0 cu 1 | **Nu direct — dar vezi mai jos** |
-
-**Consecinta combinata pret+valuta+curs**: daca `V_ID_VALUTA` re-derivat difera de valuta pentru
-care VFP a calculat `V_CURS` (de ex. politica a trecut de la EUR la USD intre emitere si
-reemitere), documentul reemis scrie **noua valuta cu vechiul curs trimis de VFP** — nicio
-validare incrucisata intre cele doua (reconfirmat, `:5270` nu verifica `V_ID_VALUTA`). Aceeasi
-observatie ca in runda 9, dar acum cu dovada ca sursa comuna (pret+TVA+valuta) inseamna ca **orice
-gardă construita pentru pret trebuie sa verifice si TVA si valuta in acelasi pas**, nu doar pretul
-— altfel o factura reemisa poate trece garda de pret nemodificata si totusi sa iasa cu alta cota
-de TVA sau alta valuta.
-
-**Discountul nu ridica aceeasi problema** — e mereu respectat ca atare, indiferent de ramura,
-deci nu are nevoie de nicio garda la reemitere.
-
----
-
-## 4. Variantele de raspuns
-
-Toate patru presupun ca infrastructura de "sterge + reemite" din #13 etapa II trimite, pentru
-liniile de pe un document-contract, acelasi `V_ID_CTR` care era pe linia originala (asta e
-premisa explicita a sarcinii: "acelasi drum ca la emitere" — daca `V_ID_CTR` nu s-ar retrimite,
-linia nici n-ar mai fi "de pe contract").
-
-### (a) Se accepta re-derivarea — nicio garda
-
-**Ce se face**: nimic — regenerarea apeleaza `adauga_articol_factura` exact ca la emitere, cu
-acelasi `V_ID_CTR`. Comportamentul existent (sectiunea 1) se aplica neschimbat.
-
-**Ce se strica**: criteriul din plan ("reemitere identica produce exact aceleasi sume" — vezi
-sectiunea 6) **esueaza silentios** pe orice linie de contract al carei pret/TVA/valuta a fost
-modificat intre timp. Dovedit sa se intample azi, pe date reale (sectiunea 2, 3 din 11). Utilizatorul
-care corecteaza o cantitate pe o factura veche poate vedea, fara sa i se spuna, totalul facturii
-schimbat pentru un articol la care nici nu s-a uitat.
-
-**Cod atins**: zero. **Regresie pe emiterea normala**: zero (comportamentul de azi ramane
-identic).
-
-### (b) Se blocheaza reemiterea cand pretul curent difera
-
-**Ce se face**: inainte de a porni stergerea+regenerarea, VFP ruleaza un `SELECT` (prin
-`goExecutor`, exact tiparul deja folosit in `ofacturare.prg` pentru alte verificari punctuale —
-`goExecutor.oSelecteaza2Value(...)`, `:2628`, `:2661`) care compara, pentru fiecare linie a
-documentului cu `ID_CTR` populat, pretul/TVA/valuta stocate pe linie
-(`VANZARI_DETALII.PRET`/`PROC_TVAV`/`ID_VALUTA`) fata de ce ar recalcula azi ramura de contract
-(`CTR_ARTICOLE.PRET_UNITAR`/`CRM_POLITICI_PRET_ART.PROC_TVAV`/`.ID_VALUTA`, acelasi `JOIN` ca in
-sectiunea 1, dar rulat direct din VFP, fara sa ating `pack_facturare`). Daca gaseste macar o
-divergenta, **blocheaza regenerarea** cu mesaj ("Pretul de pe contract s-a schimbat pentru
-articolul X: -> . Actualizati contractul sau anulati regenerarea.") si nu porneste
-deloc stergerea.
-
-**Ce se strica**: orice regenerare pe un document cu **cel putin o linie** de contract cu pret
-schimbat e blocata **integral**, chiar daca utilizatorul voia sa corecteze cu totul altceva
-(ruta, o cantitate pe alta linie). Nu exista cale de a "accepta noul pret si continua" fara o a
-doua interactiune — varianta (c) rezolva exact asta.
-
-**Cod atins**: doar VFP (o interogare noua, read-only, plus un dialog de blocare), inaintea
-apelului la infrastructura de stergere+regenerare din #13. **Zero atingere `pack_facturare`**
-(decizia 27-bis respectata). **Regresie pe emiterea normala**: zero — garda ruleaza doar pe
-calea de regenerare, nu la emiterea unui document nou.
-
-### (c) Se avertizeaza si se cere confirmare, cu diferenta afisata
-
-**Ce se face**: aceeasi interogare de detectie ca la (b), dar in loc sa blocheze, afiseaza un
-dialog cu lista liniilor divergente si delta (pret vechi vs. nou, si TVA/valuta daca difera —
-vezi sectiunea 3, toate trei trebuie aratate, nu doar pretul) si cere confirmare explicita
-("Continuati cu noile preturi de pe contract?" Da/Nu). La "Nu", regenerarea se opreste ca la (b).
-La "Da", regenerarea continua normal si ramura de contract face exact ce face azi (suprascrie).
-
-**Ce se strica**: nu opreste suprascrierea insasi — doar o face **vizibila si asumata** inainte
-sa se produca, exact criteriul cerut de plan ("un rezultat explicit decis, nu accidental"). Nu
-ofera o cale de a **pastra** vechiul pret in timp ce se accepta restul modificarii — pentru asta
-ar trebui combinata cu (d), cu costul ei (vezi mai jos). Risc de "warning fatigue": daca
-divergenta e frecventa in productie (nu se poate masura azi, sectiunea 2), utilizatorii pot invata
-sa dea click pe "Da" fara sa citeasca.
-
-**Cod atins**: identic cu (b) plus un dialog cu doua butoane in loc de unul singur. **Regresie pe
-emiterea normala**: zero.
-
-### (d) Se ocoleste ramura — reemiterea trimite pretul documentului pe o cale care nu trece prin `DECODE`
-
-**Posibil mecanic, cu un cost real.** Ramura de contract se selecteaza din doua conditii, ambele
-in afara controlului direct al apelantului per-linie:
-
-1. `pack_facturare.ntip IN (2,6,26,52)` — variabila **de sesiune** (`:1882`,
- `pack_facturare.ntip := V_TIP`), setata o singura data la initializarea documentului (tipul
- documentului insusi), nu per linie. A o schimba ar insemna sa reclasifici tot documentul
- (afecteaza si alte ramuri `CASE` care depind de `ntip` — `:1905`, `:5053`, `:6056-6124`,
- `:14820` — cu efecte necunoscute si necontrolate) — **contrazice premisa "acelasi drum ca la
- emitere"** data explicit in sarcina. Nu recomand aceasta sub-varianta.
-2. `V_ID_CTR` — parametru **per linie**, trimis explicit de VFP la fiecare apel
- `adauga_articol_factura`. Daca VFP trimite `V_ID_CTR = NULL` pentru o linie la reemitere,
- blocul de la `:5039-5050` gaseste `NO_DATA_FOUND` (cautarea `WHERE ID_CTR = NULL` nu potriveste
- nimic) → `V_OPT_FACTURARE := 4` → ramura `WHEN V_OPT_FACTURARE = 3` nu se mai potriveste →
- cade pe `ELSE` (`:5187-5203`) → `V_PRET := V_PRET_TEMP` (pretul documentului, respectat ca
- atare, la fel TVA prin `JTVA_COLOANE` dupa `V_ID_JTVA_COLOANA`).
-
- **Costul**: `V_ID_CTR` e si coloana scrisa in `VANZARI_DETALII_TEMP`/`VANZARI_DETALII.ID_CTR`
- (`:5280`, copiata neschimbat mai departe la `:13730`/`:13755`). Trimitand `NULL` la reemitere,
- linia **pierde definitiv legatura cu contractul** in tabela finala — orice raport care
- grupeaza/filtreaza pe `VANZARI_DETALII.ID_CTR` (regasire vanzari pe contract, situatii
- contractuale) nu va mai gasi acea linie dupa reemitere, desi articolul a fost, de fapt, livrat
- pe acel contract. E o regresie permanenta si greu de observat (nu da eroare, doar dispare
- tacit dintr-un raport), pe un camp folosit azi activ (`rec_pret_lazy.md`/`idpol_comanda_contract.md`
- confirma ca legatura cu contractul e cheie de raportare in tot lantul `PACK_FACTURARE`).
- In plus, o data pierduta legatura, **o a doua reemitere ulterioara nu ar mai putea re-deriva
- pretul din contract nici daca s-ar dori** — comutarea e ireversibila per linie, nu un flag
- comutabil.
-
-**Nu recomand varianta (d)** — costul (pierderea trasabilitatii contract-linie, permanenta) e mai
-mare decat problema pe care o rezolva, si nici macar nu rezolva complet criteriul "reemitere
-identica" (rezolva doar pretul/TVA/valuta acelei linii, cu pretul unei regresii pe alt camp).
-
----
-
-## 5. Discount, TVA, curs valutar — verificare fata de sectiunile 6-7 din raportul vechi
-
-Deja tratat integral in sectiunea 3 de mai sus (descoperirea principala a acestei runde). Rezumat
-scurt pentru trasabilitate fata de cererea explicita:
-
-- **Discountul** (sectiunea 6 raport vechi): reconfirmat — niciodata re-derivat, indiferent de
- ramura. **Nu ridica problema de reemitere.**
-- **TVA-ul** (sectiunea 6 raport vechi): reconfirmat ca "mereu recalculat, din surse diferite pe
- ramura" — dar cu precizarea noua ca pe ramura de contract, sursa **coincide exact** cu sursa
- pretului (acelasi `SELECT`, aceeasi conditie `NO_DATA_FOUND`). **Ridica aceeasi problema ca
- pretul, prin acelasi mecanism** — orice varianta (b)/(c) trebuie sa acopere si TVA, nu doar pret.
-- **Cursul valutar** (sectiunea 7 raport vechi): reconfirmat — `V_CURS` mereu respectat ca atare
- (`DECODE(V_CURS,0,1,V_CURS)`), nu se re-deriva direct. **Dar** identitatea valutei
- (`V_ID_VALUTA`) se re-deriva pe aceeasi ramura de contract, din acelasi `SELECT` — daca politica
- a schimbat valuta intre timp, reemiterea scrie noua valuta cu vechiul curs trimis de VFP, fara
- nicio validare incrucisata (reconfirmat, `:5270` nu verifica `V_ID_VALUTA`). **Ridica aceeasi
- problema, prin acelasi mecanism, si trebuie acoperita de aceeasi garda.**
-
----
-
-## 6. Cazul "reemitere identica"
-
-Criteriul din plan (S12) cere ca o reemitere fara nicio modificare intentionata sa produca
-**exact** aceleasi sume. Verificat pe fiecare ramura a `CASE`-ului de la `:5052-5220` (nu doar
-ramura de contract):
-
-| Ramura (`ntip`) | Garantat identic la reemitere? | De ce |
-|---|---|---|
-| `ELSE` (lista de preturi, fara contract) | **Da, cu o rezerva minora** | `V_PRET := V_PRET_TEMP` — passthrough direct (`:5200`). TVA vine din `JTVA_COLOANE` dupa `V_ID_JTVA_COLOANA` (`:5188-5198`) — identic **doar daca** acea coloana de TVA nu a fost ea insasi editata intre timp (posibil, dar alt tip de risc, nu cel cerut de aceasta sarcina). |
-| `45` (restaurant) | **Da, cu aceeasi rezerva** | `V_PRET := V_PRET_TEMP` setat **inainte** de orice `SELECT` (`:5109`) — respectat necondiționat. TVA vine tot din `JTVA_COLOANE` (`:5114-5139`), aceeasi rezerva ca mai sus. |
-| `3,21,28,42,47` (comenzi) | **Nu garantat, dar esueaza tare, nu tacit** | `SELECT ... WHERE A.PRET = V_PRET_TEMP` (`:5077`) — daca pretul din comanda-sursa nu mai coincide exact cu ce trimite VFP, **`NO_DATA_FOUND` netratat** → eroare Oracle bruta, regenerarea pica integral, nu produce o suma gresita silentios. Diferit structural de ramura de contract. |
-| `4` (aviz) | **Nu garantat, silentios** | `SELECT DISTINCT A.PRET ... FROM VANZARI_DETALII` (`:5082-5103`), **fara filtru pe pret** — re-citeste pretul curent al liniei din avizul-sursa necondiționat. Daca avizul insusi a fost modificat intre emiterea initiala si reemitere, sau daca exista mai multe randuri candidate (`DISTINCT` pe o potrivire ambigua), reemiterea poate lua alt pret, tacit — **acelasi tipar de risc ca la contract**, dar pe alt document-sursa. |
-| `V_OPT_FACTURARE=3` (contract) | **Nu garantat, silentios** | Sectiunea 1 — faptul portant. |
-
-**Observatie in afara perimetrului cerut, dar direct relevanta**: daca #13 etapa II ajunge sa
-regenereze si facturi emise initial din **aviz** (`ntip=4`), nu doar din contract, **acelasi tip
-de risc silentios exista si acolo**, prin alt mecanism (re-citire necondiționata din
-`VANZARI_DETALII` a avizului-sursa, fara filtru pe pret). Raportul vechi (`s10_pret_rederivat.md`,
-sectiunea 4) semnalase deja asta ca "neverificat, in afara bugetului" — de data asta o marchez
-explicit ca **decizie deschisa**: daca reemiterea din #13 se aplica si documentelor provenite din
-aviz, aceeasi discutie (a/b/c/d) trebuie purtata si pentru acea ramura, cu propriul cost (sursa
-de comparat e alt document, nu `CTR_ARTICOLE`). Nu am extins cercetarea de date pe aceasta ramura
-(in afara cererii explicite a sarcinii, care a cerut "cazul confirmat", adica cel de contract).
-
-**Concluzie sectiune**: criteriul "reemitere identica" e garantat azi doar pe ramurile
-`ELSE`/restaurant (fara contract, fara comanda, fara aviz). Pe comenzi, o divergenta produce
-eroare vizibila (rau, dar nu tacit). Pe contract **si** pe aviz, o divergenta produce o suma
-gresita fara nicio semnalare — acestea sunt cele doua ramuri care au nevoie de o decizie explicita
-de tipul (a)-(d) inainte ca #13 etapa II sa poata pretinde ca satisface criteriul S12.
-
----
-
-## 7. Ce ramane de decis de Marius
-
-1. **(b) blocare stricta vs. (c) avertizare+confirmare** — (c) satisface literal criteriul "decis
- explicit, nu accidental" cerut de plan si nu intrerupe fluxul quasi-niciodata (doar cand chiar
- exista divergenta); (b) e mai sigur (niciodata nu se schimba nimic fara interventie manuala pe
- contract) dar mai frustrant daca divergentele sunt frecvente in productie — lucru nemasurabil
- azi (sectiunea 2). **Recomand (c)** ca implicit, cu mesajul aratand explicit delta de
- pret/TVA/valuta (sectiunea 3) — nu doar pretul.
-2. **Garda trebuie sa acopere pret + TVA + valuta impreuna**, nu doar pretul — confirmat la
- sectiunea 3 ca vin din acelasi `SELECT`. O implementare care verifica doar pretul ar lasa
- trecerea tacuta a unei schimbari de TVA sau valuta.
-3. **Varianta (d) (ocolire) — nu o recomand**, din cauza pierderii permanente a legaturii
- `VANZARI_DETALII.ID_CTR`. Daca Marius considera totusi ca merita costul (de ex. daca
- trasabilitatea contract-linie pe documentele reemise nu conteaza in practica), e o decizie de
- produs explicita, nu tehnica — semnalez aici, nu decid.
-4. **Ramura de aviz (`ntip=4`) are acelasi tip de risc silentios** (sectiunea 6) — de decis daca
- intra in perimetrul #13 etapa II acum sau se trateaza separat, cu propriul studiu de fezabilitate
- pentru garda (sursa de comparat difera fata de contract).
-5. **Frecventa reala in productie a divergentei `CTR_ARTICOLE.PRET_UNITAR`** ramane nemasurabila
- din baza de dezvoltare (27 randuri total) — daca decizia (b) vs (c) depinde de cat de des s-ar
- declansa garda, ar trebui repetata interogarea din sectiunea 2 pe o baza cu volum de productie
- inainte de implementare.
-
----
-
-## STARE / CE RAMANE
-
-**Livrabil complet** — toate cele 6 puncte cerute in brief sunt acoperite (sectiunile 1-6), plus
-recomandare argumentata (sectiunea 4, cu tabel comparativ) si lista de decizii deschise
-(sectiunea 7).
-
-Nimic ramas in lucru; nicio verificare intrerupta. Singurele limitari explicite:
-- esantionul de date (27 randuri `CTR_ARTICOLE`, baza de dezvoltare) nu se extrapoleaza la
- productie (sectiunea 2);
-- ramura de aviz (`ntip=4`) e semnalata ca avand acelasi tip de risc, dar nu a primit acelasi nivel
- de cercetare (nu era in perimetrul cerut) — vezi sectiunea 6, ultimul paragraf inainte de
- concluzie.
diff --git a/docs/cercetare/s10_pret_rederivat.md b/docs/cercetare/s10_pret_rederivat.md
deleted file mode 100644
index 1afd654..0000000
--- a/docs/cercetare/s10_pret_rederivat.md
+++ /dev/null
@@ -1,342 +0,0 @@
-# S10 — Pretul re-derivat in `adauga_articol_factura`, ramura cu ramura
-
-## Nota pe sursa folosita
-
-`docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` **nu exista** (nici in `docs\`, nici urme in
-istoricul git — `docs\` e integral netracked). Fisierul cu **acelasi nume** exista insa la
-`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` si a fost folosit
-ca sursa. Continutul `adauga_articol_factura` coincide structural cu ce descrie planul (aceeasi
-ordine de ramuri, aceleasi coduri de eroare `FACT-012/013/018`, acelasi `DECODE(A.PRET_UNITAR, 0,
-V_PRET_TEMP, A.PRET_UNITAR)`), dar liniile sunt deplasate cu **+17** fata de citatele din plan
-(corp `4989-5284` aici vs. `4972-5268` in plan; ramura de contract `5146-5185` aici vs. `:5129-5168`
-in plan) — probabil diferente de comentarii de antet intre cele doua exporturi. Toate citatele de mai
-jos sunt pe fisierul din `SCRIPTURI_CLAR`, verificat direct.
-
-## Verdict (raspuns la intrebarea 4 — reemiterea)
-
-**Da, exista o ramura care suprascrie tacut pretul la orice apel, inclusiv la o eventuala
-reemitere: liniile provenite dintr-un contract cu `OPT_FACTURARE = 3` (sau `NULL`, care se
-implicit-eaza tot la 3).** Procedura nu are nicio notiune de "reemitere" — la fiecare apel cu acelasi
-`V_ID_CTR`, daca articolul are in `CTR_ARTICOLE.PRET_UNITAR` o valoare diferita de 0, acea valoare
-**inlocuieste** pretul trimis de VFP (`V_PRET_TEMP`), necontidionat de faptul ca linia a fost sau nu
-atinsa de utilizator pe ecran. Riscul se materializeaza doar daca pretul din contract s-a schimbat
-intre emiterea initiala si reemitere — daca n-a scazut, rezultatul e identic si nimeni nu observa
-diferenta pana cand se schimba. Pe toate celelalte ramuri (implicita, restaurant), pretul trimis de
-VFP e respectat ca atare. **Nu exista niciun parametru sau flag care sa opreasca re-derivarea** —
-raspunsul la intrebarea 5 e "nu exista".
-
-## 1. Semnatura completa (corp, nu spec)
-
-`PACK_FACTURARE:4989-5015` (spec identica la `:537-563`, verificat doar ca prezenta, nu citat):
-
-```
-PROCEDURE adauga_articol_factura(V_ID_TEMP IN NUMBER,
- V_ID_ARTICOL IN NUMBER,
- V_SERIE IN VARCHAR2,
- V_EXPLICATIE IN VARCHAR2,
- V_ID_POL IN NUMBER,
- V_ID_GESTIUNE IN NUMBER,
- V_PRET_ACHIZITIE_TEMP IN NUMBER,
- V_PRETD IN NUMBER,
- V_ID_VALUTAD IN NUMBER,
- V_PRET_TEMP IN NUMBER,
- V_ID_VALUTA_TEMP IN NUMBER,
- V_PRETURI_CU_TVA_TEMP IN NUMBER,
- V_IN_STOC_TEMP IN NUMBER,
- V_CANTITATE IN NUMBER,
- V_DISCOUNT_UNITAR IN NUMBER,
- V_CONT IN VARCHAR2,
- V_CURS IN NUMBER,
- V_MULTIPLICATOR IN NUMBER,
- V_ID_JTVA_COLOANA IN NUMBER,
- V_ID_PART_REZ IN NUMBER,
- V_ID_LUCRARE_REZ IN NUMBER,
- V_PRETV_ORIG IN NUMBER,
- V_ID_VANZARE_SET IN NUMBER,
- V_ID_CTR IN NUMBER,
- V_ID_UTIL IN NUMBER,
- V_TAXCODE IN NUMBER DEFAULT NULL,
- V_LOT IN VARCHAR2 DEFAULT NULL) IS
-```
-
-Toti parametrii sunt **IN**, niciunul OUT/IN OUT — nu exista un canal de intoarcere a pretului
-recalculat catre VFP la momentul apelului (linia se citeste ulterior, la re-interogarea grilei).
-
-**`V_OPT_FACTURARE` nu e parametru.** E o variabila locala (`:5029`), calculata **in interiorul
-procedurii** din `CONTRACTE.OPT_FACTURARE`, folosind parametrul `V_ID_CTR` primit de la VFP
-(`:5039-5050`):
-
-```sql
-IF pack_facturare.ntip IN (2, 6, 26, 52) THEN
- BEGIN
- SELECT NVL(OPT_FACTURARE, 3) INTO V_OPT_FACTURARE FROM CONTRACTE WHERE ID_CTR = V_ID_CTR;
- EXCEPTION
- WHEN NO_DATA_FOUND THEN
- V_OPT_FACTURARE := 4;
- END;
-END IF;
-```
-
-VFP nu trimite si nu poate influenta `V_OPT_FACTURARE` altfel decat prin `V_ID_CTR` (`poArt.id_ctr`,
-trimis `NULL` cand linia nu vine de pe contract). Pentru orice `pack_facturare.ntip` in afara lui
-`(2, 6, 26, 52)`, `V_OPT_FACTURARE` **ramane neinitializat** (blocul IF nu ruleaza deloc) — echivalent
-cu "nu conteaza", ramura de contract nu se poate nimeri.
-
-## 2. Ce inseamna `V_OPT_FACTURARE` si cum se coreleaza cu VFP
-
-Din `PACK_FACTURARE` (alte proceduri, aceeasi coloana `CONTRACTE.OPT_FACTURARE`) si din
-`COMUN\clase\ofacturare.vc2` / `COMUN\programe\oproceduri_facturare.prg` (proprietatea locala
-`poArt.opt_facturare`, populata la citirea contractului, in oglinda cu coloana Oracle):
-
-| Valoare | Tip facturare | Dovada |
-|---|---|---|
-| `0` (sau lipsa contract) | Articol normal, nelegat de contract | `ofacturare.vc2:13055` `If poArticol.opt_facturare = 0` |
-| `1`, `2` | **Rata** (scadentar contract, `CTR_SCADENTAR`) — linia nu trece prin `adauga_articol_factura`, ci prin `adauga_rata_factura` (`ofacturare.vc2:14041-14050`) | `ofacturare.vc2:14041` `If Inlist(poArt.opt_facturare,1,2)`; `PACK_FACTURARE:2898,2915` (`CTR_SCADENTAR`, doar pt. `OPT_FACTURARE IN (1,2)`) |
-| `3` | **Articol de pe contract**, pret din `CTR_ARTICOLE` | `PACK_FACTURARE:2699,2820` (`CTR_ARTICOLE` doar pt. `OPT_FACTURARE = 3`); `ofacturare.vc2:14750` (`poDate.tip = 2 And poArticol.opt_facturare = 3`) |
-| `4` | Fallback intern cand contractul nu (mai) exista (`NO_DATA_FOUND`) | `PACK_FACTURARE:5047-5048` |
-
-VFP nu trimite `V_OPT_FACTURARE` ca parametru al `adauga_articol_factura` — coreleaza doar indirect,
-prin faptul ca proprietatea locala `poArt.opt_facturare` (citita din acelasi `CONTRACTE.OPT_FACTURARE`
-cand grila s-a populat) decide **ce RPC se apeleaza** (`adauga_rata_factura` pentru 1/2,
-`adauga_articol_factura` pentru orice altceva, inclusiv 3), nu ce ramura Oracle se executa in interior
-— aceea o recalculeaza serverul singur, din `V_ID_CTR`.
-
-## 3. Ramura cu ramura pe `V_OPT_FACTURARE` (si pe `pack_facturare.ntip`, care are prioritate)
-
-`CASE` la `PACK_FACTURARE:5052-5220`. Ramurile 1-3 sunt selectate dupa `pack_facturare.ntip`, nu
-dupa `V_OPT_FACTURARE` — ramura 4 (contract) se testeaza **doar daca niciuna din primele trei nu s-a
-potrivit**.
-
-| Selector | Tip facturare | Pretul | Sursa re-derivarii | Citat |
-|---|---|---|---|---|
-| `ntip IN (3,21,28,42,47)` | Facturare/aviz din **comenzi** | **Re-derivat, dar constrans sa se potriveasca cu ce a trimis VFP** — `SELECT A.PRET ... WHERE A.PRET = V_PRET_TEMP` | `COMENZI_ELEMENTE` + `CRM_POLITICI_PRETURI`/`PRET_ART`, filtrat pe `A.PRET = V_PRET_TEMP`; daca nu exista rand cu exact acel pret, `NO_DATA_FOUND` **nu e tratat** — procedura pica cu eroare Oracle netratata | `:5053-5078` |
-| `ntip = 4` | Facturare din **avize** | **Re-derivat necondiționat, din documentul sursa** — `SELECT DISTINCT A.PRET ... INTO V_PRET` fara filtru pe pretul trimis | `VANZARI_DETALII` (linia din avizul sursa), filtrata pe articol/politica/gestiune/discount/cont, dar **nu** pe pret | `:5080-5103` |
-| `ntip = 45` | Facturare **restaurant** | **Respectat** — `V_PRET := V_PRET_TEMP` setat **inainte** de SELECT (`:5109`); SELECT-ul recalculeaza doar `V_PROC_TVAV` si `V_PRET_ACHIZITIE` (cost, nu pret de vanzare) | n/a pentru pret; TVA din `JTVA_COLOANE`, cost din `CRM_POLITICI_PRET_ART.PRETFTVA` | `:5104-5145` |
-| `V_OPT_FACTURARE = 3` (deci `ntip IN (2,6,26,52)` **si** contract cu `OPT_FACTURARE=3`/`NULL`) | Facturare/aviz **de pe contract** | **Re-derivat daca contractul are pret setat** — `DECODE(A.PRET_UNITAR, 0, V_PRET_TEMP, A.PRET_UNITAR)`; daca `PRET_UNITAR = 0` sau nu exista rand `CTR_ARTICOLE`/politica potrivita (`NO_DATA_FOUND`), cade pe `V_PRET_TEMP` | `CTR_ARTICOLE.PRET_UNITAR` (prin `CRM_POLITICI_PRET_ART`, `ID_POL_ART`) | `:5146-5185` (branch), `:5181-5184` (fallback `V_PRET_TEMP` in exceptie) |
-| `ELSE` (implicit — orice altceva, inclusiv linii normale fara contract) | Standard | **Respectat** — `V_PRET := V_PRET_TEMP` | n/a; TVA din `JTVA_COLOANE` dupa `V_ID_JTVA_COLOANA` trimis de VFP | `:5187-5203` |
-
-**Observatie de prioritate:** daca o linie e simultan "din comanda" (`ntip IN (3,21,28,42,47)`) si
-are si `V_ID_CTR` completat, ramura de comenzi castiga — `V_OPT_FACTURARE` nici nu se calculeaza
-(blocul de la `:5039` ruleaza doar pentru `ntip IN (2,6,26,52)`). Ramurile nu se pot suprapune in
-productie curenta, dar asta inseamna ca **orice extindere viitoare a lui `ntip`** (de ex. daca #13
-introduce un tip nou de document care refoloseste `adauga_articol_factura` pentru reemitere) trebuie
-verificata explicit fata de acest `CASE` — un `ntip` nou care nu intra in niciuna din listele
-`(3,21,28,42,47)` / `4` / `45` cade automat fie pe ramura de contract (daca are `V_ID_CTR`), fie pe
-`ELSE`.
-
-## 4. Reemiterea — detaliu (vezi si verdictul de mai sus)
-
-Procedura **nu primeste si nu poate primi** vreun semnal de tip "acesta e un apel de reemitere, nu
-recalcula". Comportamentul e identic la emiterea initiala si la orice apel ulterior cu aceiasi
-parametri. Riscul descris in plan (sectiunea H) se confirma integral pentru ramura de contract
-(`V_OPT_FACTURARE = 3`): daca `CTR_ARTICOLE.PRET_UNITAR` s-a modificat intre emiterea initiala si
-reemitere, factura reemisa va lua **pretul curent din contract**, nu pretul confirmat pe ecran de
-utilizator inainte de reemitere — chiar daca utilizatorul n-a atins linia.
-
-Pentru ramurile "avize" (`ntip = 4`) si "comenzi" (`ntip IN (3,21,28,42,47)`), acelasi risc structural
-exista (pretul se re-citeste din documentul sursa la fiecare apel), dar **nu sunt cazul confirmat de
-#13** — planul S10 spune explicit "se verifica pe factura din contract, care e cazul confirmat" — nu
-s-a cerut si nu s-a facut inventar suplimentar pentru daca fluxul de reemitere din #13 (etapa II,
-stergere+regenerare cu aceleasi linii) ar trece vreodata prin aceste doua ramuri. **De retinut daca
-#13 extinde reemiterea si la facturi/avize provenite din comanda sau din alt aviz** — pe ambele,
-re-derivarea e chiar mai stricta decat pe contract (ramura de comenzi cade cu eroare netratata daca
-pretul nu se potriveste exact; ramura de avize suprascrie necondiționat).
-
-## 5. Mecanism de "nu re-deriva"
-
-**Nu exista.** Niciun parametru boolean, nicio valoare santinela, nicio ramura in `CASE`
-(`:5052-5220`) care sa respecte pretul primit *pentru ca i s-a cerut explicit*. Ramurile "implicita"
-si "restaurant" respecta pretul doar pentru ca structural nu au de unde re-deriva altceva (nu exista
-document sursa de recitit), nu pentru ca ar exista o comutare intentionata. Orice solutie de tip
-"pretul vine din formular, nu se re-deriva" (cum sugereaza planul, sectiunea H) **ar trebui
-implementata in VFP inainte de apel** (de exemplu, nu retrimite `V_ID_CTR` la reemitere daca vrei sa
-eviti ramura de contract) — nu exista un parametru in pachet pe care VFP l-ar putea seta ca sa
-dezactiveze re-derivarea, iar pachetul **nu se modifica** (decizia 27-bis, respectata — aceasta e o
-constatare, nu o propunere).
-
-## 6. Discountul si TVA-ul
-
-- **Discountul (`V_DISCOUNT_UNITAR`) nu e niciodata re-derivat.** Parametrul intra direct in
- `INSERT INTO VANZARI_DETALII_TEMP (..., DISCOUNT_UNITAR, ...) VALUES (..., V_DISCOUNT_UNITAR, ...)`
- (`:5236`, `:5266`) — nicio ramura din `CASE` il citeste sau il modifica. Tratament **diferit** de
- pret: discountul e mereu respectat, indiferent de ramura.
-- **TVA-ul (`V_PROC_TVAV`) e mereu recalculat server-side, pe toate ramurile — dar din surse
- diferite, nu dintr-un parametru brut.** Nu exista parametru `V_PROC_TVAV_TEMP` in semnatura; VFP
- trimite doar `V_ID_JTVA_COLOANA` (un identificator de coloana de cota, nu cota insasi). Pe ramura
- implicita si pe cea de contract-fara-potrivire, cota se cauta in `JTVA_COLOANE` dupa acel ID
- (`:5188-5198`, `:5169-5179`); pe ramurile comenzi/avize/contract-cu-potrivire/restaurant, cota vine
- din documentul sursa sau din politica de pret (`:5058`, `:5083`, `:5150`, `:5114`). Deci TVA-ul are
- un tratament **mai strict** decat pretul: niciodata "pass-through" direct, intotdeauna o cautare,
- doar sursa cautarii difera pe ramura.
-
-## 7. Cursul valutar si pretul in valuta
-
-- **Cursul (`V_CURS`) e mereu respectat ca valoare, pe toate ramurile.** Singura procesare e
- `DECODE(V_CURS, 0, 1, V_CURS)` la `INSERT` (`:5270`) — inlocuieste 0 cu 1, altfel scrie exact ce a
- trimis VFP. Procedura **nu interogheaza niciodata tabela `CURS`** pentru un curs "de azi" — nu are
- de unde sa recalculeze cursul chiar daca ar vrea.
-- **Identitatea valutei (`V_ID_VALUTA`, variabila locala, nu parametrul `V_ID_VALUTAD`) urmeaza
- acelasi tipar ca pretul, ramura cu ramura:** re-derivata din sursa pe comenzi (`C.ID_VALUTA`,
- `:5059`) si avize (`A.ID_VALUTA`, `:5084`), re-derivata din contract pe ramura `V_OPT_FACTURARE=3`
- (`B.ID_VALUTA`, `:5151`, cu fallback `V_ID_VALUTA_TEMP` in exceptie, `:5182`), respectata pe
- implicita si restaurant (`V_ID_VALUTA := V_ID_VALUTA_TEMP`, `:5110`, `:5201`).
-- **Consecinta pentru reemiterea unui document in valuta pe contract:** daca politica de pret a
- contractului (`CRM_POLITICI_PRET_ART`, prin `CTR_ARTICOLE.ID_POL_ART`) a fost schimbata intre timp
- la o alta valuta, reemiterea ar scrie articolul in **noua** valuta a politicii, dar cu **cursul**
- trimis de VFP (posibil cursul valutei vechi, daca VFP nu a fost actualizat sa retrimita cursul
- corect pentru noua valuta) — o sursa suplimentara de neconcordanta, nesemnalata explicit in plan.
- Nu s-a gasit nicio validare in procedura care sa verifice ca `V_CURS` corespunde valutei
- re-derivate `V_ID_VALUTA`.
-
-## Completare: nota contabila a politicii
-
-Sursa: aceeasi, `contabilizeaza_articol` la `PACK_FACTURARE:7173-7547` (in fisierul din
-`SCRIPTURI_CLAR`; corpul relevant pentru articol simplu — nu compus — e la `:7391-7544`), plus
-`scrie_nota` la `:12329-12561`.
-
-### 1. Cum ajunge de la `id_pol` la nota contabila — ia toate randurile setului, fara distributie
-
-`cursor_articol` (`:7218-7271`):
-
-```sql
-FROM CRM_POLITICI_PRET_ART A
-LEFT JOIN CRM_POLITICI_PRETURI B ON A.ID_POL = B.ID_POL
-LEFT JOIN CRM_NOTE_VANZARI C ON B.ID_NOTA = C.ID_NOTA
-LEFT JOIN NOTE_CONTABILE D ON C.ID_SET = D.ID_SET
-WHERE A.ID_POL = detalii_articol.id_pol AND A.ID_ARTICOL = detalii_articol.id_articol
-```
-
-E un `JOIN` simplu pe `ID_SET`, **fara `ROWNUM`, fara agregare, fara filtru suplimentar pe
-`NOTE_CONTABILE`**. Daca setul are `N` randuri, cursorul intoarce `N` randuri pentru aceeasi
-combinatie `id_pol`/`id_articol`. Bucla care il consuma (`:7393-7542`,
-`OPEN cursor_articol; FETCH ...; WHILE cursor_articol%FOUND LOOP ... FETCH ...; END LOOP;`) executa
-**intregul corp — `scrie_nota`, `descarca_gestiune`, `scrie_discount` — o data pentru fiecare rand
-din set**, cu **aceeasi cantitate si acelasi pret intreg de fiecare data**, nu impartite intre
-randuri. Nu exista nicio coloana `ORDINE` in tot pachetul (cautare `ORDINE` in fisier: zero
-rezultate) si nicio logica de distributie procentuala intre randurile unui set.
-
-**Consecinta directa pentru reteta aprobata (J-quater):** daca politica tehnica pentru contul de
-venit ar ajunge sa foloseasca o nota al carei `ID_SET` are mai mult de un rand in
-`NOTE_CONTABILE` (cazul general — pana la 30 de randuri pe unele seturi din baza, per verificarea ta
-pe date vii), `contabilizeaza_articol` ar scrie **de N ori** aceeasi suma in contabilitate si ar
-apela `descarca_gestiune` de N ori pentru aceeasi linie de vanzare — dublare de venit si dublare de
-descarcare de gestiune, nu doar zgomot. Pasul 2 al retetei ("cauta o politica a carei nota are deja
-`SCC`-ul calculat") **trebuie sa garanteze un singur rand `NOTE_CONTABILE` per `ID_SET` ales**, nu
-doar un rand cu `SCC`-ul potrivit — verificarea facuta de tine pe cele 7 note active (exact un rand
-per set) e conditia care face reteta sigura azi, dar nu e impusa de cod, e o coincidenta a datelor
-curente.
-
-### 2. `NOTE_CONTABILE.PTVA` — nu e citit deloc de `contabilizeaza_articol`
-
-Lista de coloane a `cursor_articol` (`:7230-7260`) selecteaza explicit
-`ID_NOTA, PRETURI_CU_TVA, ID_VENCHELT, ID_SECTIE, ID_SET, EXPLICATIE, SCD, ASCD, SCC, ASCC, CU_TVA,
-IN_VALUTA` din lantul `CRM_POLITICI_PRET_ART -> CRM_POLITICI_PRETURI -> CRM_NOTE_VANZARI ->
-NOTE_CONTABILE` — **`D.PTVA` nu apare in acest `SELECT`**. Coloana exista pe tabel (confirmat de
-datele tale vii — `21`, `5`, `0`), dar `contabilizeaza_articol` n-o citeste niciodata.
-
-Cota de TVA folosita efectiv in scriere e alta — vine din apelul catre `scrie_nota` (`:7444-7467`),
-unde parametrul `V_PTVA` primeste `detalii_articol.proc_tvav * 100 - 100` (`:7464`), adica **cota
-calculata deja in `adauga_articol_factura`** (din `JTVA_COLOANE` sau din documentul sursa, vezi
-sectiunea 3 de mai sus), nu din nota. Deci **raspunsul direct la intrebarea ta: daca articolul are
-21% dar nota politicii are `PTVA=5`, nu se intampla nimic — `PTVA` de pe nota e complet ignorat,
-cota folosita e cea a articolului/documentului, nu a notei.** Coloana `NOTE_CONTABILE.PTVA` e moarta
-din perspectiva acestei proceduri (posibil folosita in alt modul, neverificat aici).
-
-### 3. `CU_TVA` si `IN_VALUTA` de pe nota
-
-Ambele se citesc din `NOTE_CONTABILE` (`crs_rand_articol.cu_tva`, `crs_rand_articol.in_valuta`,
-`:7253`, `:7254-7260`) si se transmit mai departe la `scrie_nota` ca parametri (`V_CU_TVA`,
-`V_IN_VALUTA`), unde controleaza mecanic, nu semantic tot ce e legat de pret:
-
-- **`V_CU_TVA`** (`scrie_nota:12416-12422`): daca `= 0`, suma acumulata in `V_INCASAT_CALCUL` e
- `V_SUMA_FARA_TVA`; daca `= 1`, e `V_SUMA_CU_TVA`. Separat, la `:12537-12558`, **doar cand
- `V_CU_TVA = 1` se scrie si o linie separata de TVA** (`pack_facturare.scrie_tva(...)`, cont
- `4427`/etc.). Deci `CU_TVA` decide daca acest rand din notă genereaza o inregistrare contabila
- separata pentru TVA sau nu — nu suprascrie si nu recalculeaza cota, doar comuta daca linia de TVA
- se scrie.
-- **`V_IN_VALUTA`** (`scrie_nota:12391-12404`, `:12492-12507`): daca `= 1`, se calculeaza si
- `V_SUMA_VAL`/`V_SUMA_FARA_TVA_VAL`/etc. (sumele in valuta straina) si randul `ACT_TEMP` scrie
- `ID_VALUTA = V_ID_VALUTA` (valuta reala a articolului) si `CURS = V_CURS`; daca `= 0`, randul
- scrie `ID_VALUTA = pack_facturare.nid_moneda_nationala` si `CURS = 0`, indiferent de valuta reala
- a articolului.
- **Raspuns la "ce se intampla daca `IN_VALUTA=1` pe nota dar documentul e in lei":** nu apare nicio
- eroare si nicio validare incrucisata intre `IN_VALUTA` de pe nota si valuta reala a documentului —
- procedura calculeaza pur si simplu `V_SUMA_VAL` folosind `V_ID_VALUTA` si `V_CURS` primite din
- `detalii_articol` (care, pe un document in lei, sunt deja moneda nationala si curs implicit 1).
- Rezultatul practic: `ACT_TEMP.SUMA_VAL` se populeaza redundant (cu aceeasi valoare ca `SUMA`,
- scalata la curs 1) in loc sa ramana `0`, iar `ID_VALUTA` de pe randul contabil ramane oricum
- moneda nationala (pentru ca asta e `detalii_articol.id_valuta` pe un document in lei) — o
- inconsistenta cosmetica in `ACT_TEMP` (rand cu `SUMA_VAL` populat desi `CURS` real e 1), nu o
- eroare de suma. Relevant pentru politicile `SERVICII VALUTA` / `COMISION INTERMEDIERE`
- (`SCC=704`, candidate la pasul 2 al retetei): daca oricare document in lei ar ajunge sa foloseasca
- una din ele, ar produce astfel de randuri cosmetic-inconsistente, fara sa strice suma facturata.
-
-### 4. `ASCD`/`ASCC` si `ID_PARTD`/`ID_PARTC`
-
-- **`ASCD`/`ASCC` nu sunt obligatorii — au fallback automat cand sunt nule**, exact pe ramura care
- se aplica pe facturi (`:7409-7428`):
- ```
- V_ASCD := NVL(crs_rand_articol.ascd,
- PACK_FACTURARE.GetAnaliticByGrupUtilizatori(pack_facturare.nid_util, V_SCD));
- ...
- V_ASCC := NVL(crs_rand_articol.ascc,
- PACK_FACTURARE.GetAnaliticByGrupUtilizatori(pack_facturare.nid_util, V_SCC));
- ```
- Cand nota nu are analitic explicit (cazul majoritatii notelor reale, per verificarea ta), se
- deriva unul din grupul de utilizatori al celui care factureaza, functie de contul `SCD`/`SCC`. Nu
- s-a verificat in aceasta sesiune ce intoarce `GetAnaliticByGrupUtilizatori` cand nici grupul de
- utilizatori nu are un analitic configurat (posibil `NULL` mai departe, netratat explicit aici).
-- **`ID_PARTD`/`ID_PARTC` nu sunt citite de la nota deloc.** `cursor_articol` nu le selecteaza (nu
- exista `D.ID_PARTD`/`D.ID_PARTC` nicaieri in fisier — verificat). Cele doua coloane de pe
- `ACT_TEMP` se calculeaza in `scrie_nota`/`scrie_tva` direct din **codul contului** (`V_SCD`,
- `V_SCC`) si din variabile de sesiune ale pachetului (`pack_facturare.nid_part`,
- `nid_part_rez`, `nid_partc`), nu din nota: `ID_PARTD` e un `CASE` pe prefixul lui `V_SCD`
- (`41%`/`46%`/`45%`/`357`) la `:12510-12515`; `ID_PARTC` e un `DECODE` pe `V_SCC`
- (`419`/`4111`/`357`) la `:12523-12530`. Daca `NOTE_CONTABILE` are coloane `ID_PARTD`/`ID_PARTC`,
- ele sunt irelevante pentru `contabilizeaza_articol` — partenerul contabil vine intotdeauna din
- contextul documentului (`pack_facturare.nid_part`), nu din configurarea notei.
-
-### 5. Politica fara `ID_NOTA` (`HOTEL TAXE`, `HOTEL CAZARE`)
-
-**Nu exista un cod `FACT-0xx` dedicat pentru acest caz — spre deosebire de articolul care lipseste
-din politica (`FACT-024`, `:7278-7302`), aici procedura nu detecteaza si nu semnaleaza explicit
-situatia.** Lantul de `LEFT JOIN` din `cursor_articol` (`:7261-7271`) e construit sa supravietuiasca
-oricarui inel lipsa: `A` (politica-articol, gasita — altfel s-ar fi luat deja `FACT-024` mai
-devreme) se pastreaza chiar daca `B.ID_NOTA` e `NULL` — `C` si `D` devin pur si simplu toate
-`NULL` pe acel rand, cursorul tot intoarce **un rand** (`cursor_articol%FOUND = TRUE`), nu zero.
-
-In bucla (`:7396-7541`), asta inseamna:
-- `crs_rand_articol.scd`, `.ascd`, `.scc`, `.ascc`, `.cu_tva`, `.in_valuta`, `.explicatie` — toate
- `NULL`.
-- Ramura de calcul `V_ASCD := NVL(NULL, GetAnaliticByGrupUtilizatori(nid_util, NULL))` — analitic
- calculat pe un cont `NULL`, deci probabil tot `NULL` (netestat aici ce intoarce functia pe
- argument `NULL`).
-- `scrie_nota` e apelata cu `V_SCD = NULL`, `V_SCC = NULL` — insereaza in `ACT_TEMP` un rand cu
- conturile de debit/credit **nule**.
-
-Daca `ACT_TEMP.SCD`/`ACT_TEMP.SCC` au constrangere `NOT NULL` pe schema, `INSERT`-ul ar pica cu o
-eroare Oracle generica (`ORA-01400`), nu cu un mesaj `FACT-0xx` prietenos ca la celelalte cazuri
-tratate explicit — **neverificat in aceasta sesiune** (DDL-ul `ACT_TEMP` nu e in exportul
-`PACK_FACTURARE`). In orice caz, **comportamentul e cel putin la fel de riscant ca lipsa unui
-articol din politica**, dar fara plasa de siguranta explicita din cod — de tratat cu atentie daca
-reteta aprobata ajunge sa produca vreodata o politica fara `id_nota` (nu pare sa fie cazul retetei
-J-quater, care cere explicit gasirea unei note existente, dar `HOTEL TAXE`/`HOTEL CAZARE` arata ca
-starea "politica fara nota" chiar exista azi in baza vie, pe alte fluxuri).
-
-## Ce nu s-a putut stabili si de ce
-
-- **Comportamentul exact al viitorului flux de reemitere din #13** (etapa II) fata de aceasta
- procedura — planul S10 cere verificarea "pe factura din contract", nu inventarul complet pentru
- comenzi/avize; nu s-a extins cercetarea acolo (in afara observatiei de la punctul 4, care ramane o
- constatare structurala, nu un verdict testat pe fluxul de reemitere, care **inca nu exista in
- cod** — decizia 30, nimic implementat).
-- **Ce se intampla la eroarea netratata din ramura de comenzi** (`NO_DATA_FOUND` cand
- `A.PRET = V_PRET_TEMP` nu gaseste rand, `:5057-5078`) — daca propaga ca eroare Oracle bruta pana la
- utilizator sau daca `goExecutor` o intercepteaza generic; n-a fost verificat (nu era in perimetrul
- celor 7 intrebari, dar e un risc adiacent gasit din citirea codului).
-- **Cate contracte reale au azi `CTR_ARTICOLE.PRET_UNITAR` diferit de pretul ultimei facturi emise**
- — verificare pe date vii, nefacuta (cercetare read-only, fara acces la interogari live in aceasta
- sesiune).
-- **Discrepanta de numerotare fata de `docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`** (fisierul
- cerut in prompt nu exista pe disc) — semnalata la inceputul raportului, nu blocheaza verdictul
- pentru ca fisierul gasit in `SCRIPTURI_CLAR` are acelasi nume/data si continut structural identic.
diff --git a/docs/cercetare/s10_rederivare_pe_calea_reemiterii.md b/docs/cercetare/s10_rederivare_pe_calea_reemiterii.md
deleted file mode 100644
index 43f8bce..0000000
--- a/docs/cercetare/s10_rederivare_pe_calea_reemiterii.md
+++ /dev/null
@@ -1,470 +0,0 @@
-# S10 — Se re-deriva valorile liniei pe calea de REEMITERE?
-
-Stare: **TERMINAT.**
-
-Surse:
-- `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (17217 linii;
- `versiune_db.txt` = `2026_08_09_02`) — prescurtat **`PF:`**;
-- corpul viu din `all_source` (`MARIUSM_AUTO.PACK_FACTURARE`, `PACKAGE BODY`, **VALID**,
- `last_ddl_time = 2026-08-09 20:03:50`) — prescurtat **`LIVE:`**;
-- `COMUN\clase\ofacturare.vc2`, `COMUN\programe\ofacturare_editare.prg`.
-
-**Exportul = ce ruleaza.** Verificat pe cinci ancore; in zona relevanta offsetul e constant,
-`LIVE + 1240 = PF`: `LIVE:3749`↔`PF:4989`, `LIVE:3840`↔`PF:5080`, `LIVE:3909`↔`PF:5149`,
-`LIVE:3982`↔`PF:5222`, `LIVE:4044`↔`PF:5284`, `LIVE:12466`↔`PF:13706`, `LIVE:13735`↔`PF:14975`.
-**Nu generalizez offsetul in afara zonei masurate** — il dau doar ca dovada de identitate.
-
----
-
-## 1. Unde sta `SELECT`-ul de la `PACK_FACTURARE:5149-5166` si cine il cheama
-
-**Numarul de linie e corect**, verificat direct pe fisier. `PF:5149-5166`:
-
-```
-5149 SELECT DECODE(A.PRET_UNITAR, 0, V_PRET_TEMP, A.PRET_UNITAR),
-5150 B.PROC_TVAV,
-5151 B.ID_VALUTA,
-5152 A.PRET_CU_TVA,
-5153 C.IN_STOC
-5154 INTO V_PRET, V_PROC_TVAV, V_ID_VALUTA, V_PRETURI_CU_TVA, V_IN_STOC
-5159 FROM CTR_ARTICOLE A
-5160 LEFT JOIN CRM_POLITICI_PRET_ART B ON A.ID_POL_ART = B.ID_POL_ART
-5162 LEFT JOIN NOM_ARTICOLE C ON B.ID_ARTICOL = C.ID_ARTICOL
-5164 WHERE B.ID_ARTICOL = V_ID_ARTICOL AND A.ID_CTR = V_ID_CTR AND B.ID_POL = V_ID_POL;
-```
-
-**Procedura**: `adauga_articol_factura` — spec `PF:537`, corp **`PF:4989`**,
-`END adauga_articol_factura;` **`PF:5284`**. **Deci DA, e `adauga_articol_factura`.**
-
-**CORECTIE fata de raportul rundei 9**: procedura **nu scrie in `VANZARI_DETALII`**. Se termina cu un
-singur `INSERT`, `PF:5222`, in **`VANZARI_DETALII_TEMP`**:
-
-```
-5222 INSERT INTO VANZARI_DETALII_TEMP (... PRET, PRET_CU_TVA, PROC_TVAV, ... ID_VALUTA, ... IN_STOC ...)
-5252 VALUES (... V_PRET, V_PRETURI_CU_TVA, V_PROC_TVAV, ... V_ID_VALUTA, ... V_IN_STOC ...)
-```
-
-Re-derivarea se produce deci **pe drumul catre temp**, nu dupa el. Afirmatia „`scrie_in_vanzari`
-copiaza `PRET` neschimbat din temp" e adevarata (vezi 3) si totusi **irelevanta ca protectie**:
-valoarea din formular e inlocuita **inainte** sa intre in temp.
-
-**Cine cheama procedura**: numai VFP-ul, din metoda de **salvare** a formularului:
-
-- `COMUN\clase\ofacturare.vc2:14069` — `frm_facturare_articole.do_scrie_articole`
-- `COMUN\clase\ofacturare.vc2:18104` — `frm_facturare_articole2.do_scrie_articole`
-
-(`:14054` si `:18089` sunt variante comentate, cu bind `?`, ale aceluiasi apel.)
-In pachet **nu exista apelant intern**: `grep 'adauga_articol_factura\b'` da doar `PF:537` (spec),
-`PF:4989` (corp), `PF:5284` (`END`) si doua comentarii de antet (`PF:22`, `PF:1497`).
-
-**Traseul complet pe calea de scriere** (`frm_facturare_articole`):
-
-1. `ofacturare.vc2:13981` — `pack_facturare.initializeaza_date_factura(...)`, care primeste
- `Alltrim(Str(poDate.Tip))` (`ofacturare.vc2:13994`) si il pune in variabila de pachet:
- `PF:1882 pack_facturare.ntip := V_TIP;` (corp `PF:1808`, `END` la `PF:1917`).
- **`ntip` = tipul documentului din formular** — acelasi care ajunge in `VANZARI.TIP` (`PF:13670`).
- Tot aici, `PF:1835 DELETE FROM VANZARI_DETALII_TEMP;` si `PF:1836 nid_act := 0;`.
-2. `ofacturare.vc2:14036-14115` — `SCAN` pe cursorul de grid `crsfactura`, cate un
- `pack_facturare.adauga_articol_factura(...)` per linie (`:14069`), executat prin
- `goExecutor.oExecute` (`:14105`).
-3. `frm_facturare_articole.do_scrie_factura` — `scrie_factura2` (`ofacturare.vc2:14345`, `:14373`),
- `scrie_factura_avize` (`:14318`) sau `scrie_factura_avize_retur` (`:14434`, `:14497`), care ajung
- la `pack_facturare.scrie_in_vanzari` (`PF:13488`).
-
-**Raspuns Q1**: e `adauga_articol_factura`, si e pe calea de **scriere** a documentului (nu pe cea de
-creare/incarcare din sursa) — dar tinta insertului e `VANZARI_DETALII_TEMP`, iar re-derivarea se
-aplica **inainte** de insert, deci nimic de dupa temp nu o mai poate repara.
-
-### Poarta care decide re-derivarea
-
-`adauga_articol_factura` are un singur `CASE` (`PF:5052-5220`), pe **`pack_facturare.ntip`**:
-
-| `WHEN` | linii | conditie |
-|---|---|---|
-| comenzi | `PF:5053-5078` | `ntip IN (3, 21, 28, 42, 47)` |
-| avize | `PF:5080-5103` | `ntip = 4` |
-| restaurant | `PF:5104-5145` | `ntip = 45` |
-| **contract** | `PF:5146-5185` | `V_OPT_FACTURARE = 3` |
-| `ELSE` | `PF:5187-5218` | restul |
-
-`V_OPT_FACTURARE` se seteaza **numai** daca `ntip IN (2, 6, 26, 52)` (`PF:5039-5050`):
-`SELECT NVL(OPT_FACTURARE, 3) INTO V_OPT_FACTURARE FROM CONTRACTE WHERE ID_CTR = V_ID_CTR;`, cu
-`NO_DATA_FOUND -> V_OPT_FACTURARE := 4`. Pentru orice alt `ntip` ramane **NULL**, iar `WHEN NULL = 3`
-e NULL -> fals -> se merge pe `ELSE`. **Implicitul e ramura care re-deriva**: `NVL(OPT_FACTURARE, 3)`.
-
-Tipurile (`COMUN\docs\tipuri_documente_facturare.md`): 2 = factura pe contract, 6 = contract in
-valuta, 26 = aviz pe contract, 52 = contract factura valuta; 4 = factura din avize;
-3/21/28/42/47 = din comenzi; 45 = restaurant.
-
-## 2. Cele cinci valori, una cate una
-
-Intai maparea parametrilor — ce **trimite** formularul (apel `ofacturare.vc2:14069-14091` confruntat
-cu semnatura `PF:4989-5015`; 27 de parametri, pozitional, potrivire completa):
-
-| formular (`crsfactura` -> `poArt`) | parametru |
-|---|---|
-| `poArt.pretftva`/`pretctva`/`vpretftva`/`vpretctva` | `V_PRET_TEMP` |
-| `poArt.id_valuta` | `V_ID_VALUTA_TEMP` |
-| `poArt.cu_tva` | `V_PRETURI_CU_TVA_TEMP` |
-| `poArt.gestionabil` | `V_IN_STOC_TEMP` |
-| `poArt.id_jtva_coloana` | `V_ID_JTVA_COLOANA` |
-| `poArt.id_pol` | `V_ID_POL` |
-| `poArt.id_ctr` | `V_ID_CTR` |
-
-**`PROC_TVAV` nu e parametru.** Nu exista `V_PROC_TVAV_TEMP` in semnatura — cota de TVA a liniei se
-calculeaza **intotdeauna** pe server, in **toate** ramurile. Formularul trimite `ID_JTVA_COLOANA`, din
-care ramura `ELSE` deriva `PROC_TVAV`. Pentru `PROC_TVAV` intrebarea „vine din temp?" **nu are raspuns
-„da" pe nicio ramura**; intrebarea reala e *din ce* se deriva.
-
-### Ramura contract (`V_OPT_FACTURARE = 3`, `PF:5146-5185`)
-
-- **`PRET`** — `DECODE(A.PRET_UNITAR, 0, V_PRET_TEMP, A.PRET_UNITAR)` (`PF:5149`).
- **Se re-deriva** din `CTR_ARTICOLE.PRET_UNITAR` ori de cate ori aceasta e `<> 0`, indiferent daca
- linia a fost atinsa pe ecran. Numai cand contractul are `PRET_UNITAR = 0` trece valoarea din
- formular. **Capcana NULL**: `CTR_ARTICOLE.PRET_UNITAR` e `nullable=Y` (verificat pe DB); un NULL
- **nu** potriveste literalul `0` in `DECODE`, deci rezultatul e **NULL**, nu `V_PRET_TEMP` — pretul
- din formular se pierde si linia intra in temp cu `PRET` NULL. *(dedus din semantica `DECODE`, nu
- rulat.)*
-- **`PROC_TVAV`** — `B.PROC_TVAV` din `CRM_POLITICI_PRET_ART` (`PF:5150`). **Se re-deriva** din
- politica de preturi, **nu** din `ID_JTVA_COLOANA` trimis de formular. Diferit de `ELSE`.
-- **`ID_VALUTA`** — `B.ID_VALUTA` din `CRM_POLITICI_PRET_ART` (`PF:5151`). **Se re-deriva**;
- `V_ID_VALUTA_TEMP` e ignorat.
-- **`PRET_CU_TVA`** — `A.PRET_CU_TVA` din `CTR_ARTICOLE` (`PF:5152`). **Se re-deriva**;
- `V_PRETURI_CU_TVA_TEMP` (`poArt.cu_tva`) e ignorat.
-- **`IN_STOC`** — `C.IN_STOC` din `NOM_ARTICOLE` (`PF:5153`). **Se re-deriva din nomenclatorul
- curent**; `V_IN_STOC_TEMP` (`poArt.gestionabil`) e ignorat.
-
-Cele cinci **nu merg impreuna** nici macar aici: `PRET` are un `DECODE` care uneori lasa valoarea din
-formular sa treaca, celelalte patru sunt inlocuite **neconditionat**, din **trei tabele diferite**
-(`CTR_ARTICOLE`, `CRM_POLITICI_PRET_ART`, `NOM_ARTICOLE`).
-
-**Iesirea de siguranta**: `EXCEPTION WHEN NO_DATA_FOUND` (`PF:5167-5185`) deriva `PROC_TVAV` din
-`JTVA_COLOANE` si pune **toate** celelalte patru pe valorile din formular (`PF:5181-5184`):
-`V_PRET := V_PRET_TEMP; V_ID_VALUTA := V_ID_VALUTA_TEMP; V_PRETURI_CU_TVA := V_PRETURI_CU_TVA_TEMP;
-V_IN_STOC := V_IN_STOC_TEMP;`. Adica **daca linia nu mai are corespondent in contract, formularul
-castiga** — exact comportamentul cerut de decizia 54, existent deja in cod, dar numai pe calea de
-exceptie.
-
-### Ramura `ELSE` (`PF:5187-5218`) — cazul „bun"
-
-`PROC_TVAV` din `JTVA_COLOANE` pe `ID_JTVA_COLOANA` trimis de formular (`PF:5189-5192`), iar
-`PF:5200-5203` pune explicit `V_PRET := V_PRET_TEMP`, `V_ID_VALUTA := V_ID_VALUTA_TEMP`,
-`V_PRETURI_CU_TVA := V_PRETURI_CU_TVA_TEMP`, `V_IN_STOC := V_IN_STOC_TEMP`.
-**Patru din cinci vin din formular; `PROC_TVAV` se deriva, dar din date trimise de formular.**
-
-### Ramura comenzi (`ntip IN (3,21,28,42,47)`, `PF:5053-5078`)
-
-```
-5057 SELECT A.PRET,
-5058 NVL2(A.PTVA, ROUND((A.PTVA + 100) / 100, 2), C.PROC_TVAV),
-5059 C.ID_VALUTA, B.PRETURI_CU_TVA, D.IN_STOC
-5075 WHERE A.ID_COMANDA = V_ID_COMANDA AND A.ID_ARTICOL = V_ID_ARTICOL
-5077 AND A.PRET = V_PRET_TEMP AND A.STERS = 0;
-```
-
-- **`PRET`** — formal `A.PRET` din `COMENZI_ELEMENTE`, dar `WHERE ... A.PRET = V_PRET_TEMP`
- (`PF:5077`) **fixeaza** rezultatul pe pretul din formular. Practic **nu se schimba**.
-- **`PROC_TVAV`, `ID_VALUTA`, `PRET_CU_TVA`, `IN_STOC`** — **se re-deriva** din
- `COMENZI_ELEMENTE.PTVA` / `CRM_POLITICI_PRET_ART` / `CRM_POLITICI_PRETURI` / `NOM_ARTICOLE`.
-- **Ramura nu are bloc `EXCEPTION`.** Un `SELECT INTO` gol da `NO_DATA_FOUND` (ORA-01403)
- **netratat**, care urca prin `goExecutor` in VFP. Deci daca la reemitere pretul liniei a fost
- modificat pe ecran (sau linia nu mai e in comanda), scrierea **cade cu eroare** — nu se re-deriva
- tacit. Este o **a doua ramura de re-derivare**, pe care raportul rundei 9 nu o numara.
-
-### Ramura restaurant (`ntip = 45`, `PF:5104-5145`)
-
-`PF:5109-5112` pune explicit `V_PRET := V_PRET_TEMP`, `V_ID_VALUTA := V_ID_VALUTA_TEMP`,
-`V_PRETURI_CU_TVA := V_PRETURI_CU_TVA_TEMP`, `V_IN_STOC := V_IN_STOC_TEMP`; `SELECT`-ul de la
-`PF:5114-5139` deriva **doar** `V_PROC_TVAV` (din `JTVA_COLOANE`) si `V_PRET_ACHIZITIE`.
-Patru din cinci vin din formular.
-
-### Ramura avize (`ntip = 4`) — la punctul 5
-
-## 3. `UPDATE` / recalcul care suprascrie valorile DUPA insertul din temp
-
-**Nu exista, pentru cele cinci valori.**
-
-Scrierea temp -> definitiv, in `scrie_in_vanzari` (`PF:13488-13953`), e o copiere 1:1:
-
-```
-13705 INSERT /*+ APPEND */
-13706 INTO VANZARI_DETALII (... PRET, PROC_TVAV, ... ID_VALUTA, ... PRET_CU_TVA, DIFERENTA, ...)
-13732 SELECT V_ID_VANZARE as ID_VANZARE, ... PRET, PROC_TVAV, ... ID_VALUTA, ... PRET_CU_TVA, DIFERENTA, ...
-13757 FROM VANZARI_DETALII_TEMP;
-```
-
-> Capcana de cautare platita aici: `grep 'INSERT INTO VANZARI_DETALII'` da **zero** potriviri —
-> hint-ul `/*+ APPEND */` rupe cuvintele pe doua randuri. Cautarea corecta e `INTO VANZARI_DETALII`.
-
-`IN_STOC` **nu apare** in lista de coloane (`PF:13707-13731`), si `VANZARI_DETALII` **nu are coloana
-`IN_STOC`** (verificat pe DB: `all_tab_columns` -> 0 randuri). Traieste doar in
-`VANZARI_DETALII_TEMP`, unde decide descarcarea de gestiune. Re-derivarea lui nu murdareste
-documentul salvat, dar **schimba comportamentul de stoc** al reemiterii.
-
-Toate scrierile pe `VANZARI_DETALII` din pachet:
-
-| linie | procedura | ce face |
-|---|---|---|
-| `PF:13705` | `scrie_in_vanzari` (`PF:13488`) | `INSERT` 1:1 din temp |
-| `PF:14974` | `finalizeaza_avize_lucrare` (`PF:14854`) | `INSERT` 1:1 din temp (cale avize de lucrare) |
-| `PF:5560` | `sterge_factura` (`PF:5432`) | `SET STERS, ID_UTILS, DATAORAS` |
-| `PF:5630` | `sterge_proforma` (`PF:5610`) | `SET STERS, ID_UTILS, DATAORAS` |
-| `PF:14516` | `modifica_explicatie_articol` (`PF:14511`) | `SET EXPLICATIE, TAXCODE` |
-| `PF:16017` | `actualizeaza_vanzari` (`PF:16012`) | `SET STERS = 0` |
-
-**Niciun `UPDATE` nu atinge `PRET`, `PROC_TVAV`, `ID_VALUTA`, `PRET_CU_TVA`.**
-Confirmat si pe DB: `all_source` are exact doua `INTO VANZARI_DETALII` (`LIVE:12466`, `LIVE:13735`).
-
-Mutatiile pe `VANZARI_DETALII_TEMP` **intre** `adauga_articol_factura` si `scrie_in_vanzari`:
-
-| linie | procedura | ce schimba |
-|---|---|---|
-| `PF:5297` | `adauga_diferente_pret` | numai `DIFERENTA` (`PF:5344`: `UPDATE SET DIFERENTA = B.DIFERENTA`) |
-| `PF:6860`, `PF:6864` | `scrie_factura_avize` | numai `CANTITATE` (split pe custodie); in `MERGE`, `PRET`, `PRET_CU_TVA`, `PROC_TVAV`, `ID_VALUTA`, `IN_STOC` sunt in clauza `ON`, nu in `UPDATE SET` |
-| `PF:14020` | `scrie_seturi` | numai `ID_VANZARE_SET` |
-| `PF:14057` | `scrie_seturi_proforma` | numai `ID_VANZARE_SET` (cale proforma) |
-| `PF:12266` | `transfera_articol` | cale de transfer, in afara scrierii de factura |
-
-**`pack_auto.actualizeaza_deviz`** (`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_31_02_AUTO_PACK_AUTO.sql:692-733`)
-atinge **`DEV_ORDL.PROC_TVAV`, `RUL.ID_FACT`, `NOM_LUCRARI.ID_FACT`** — **nu atinge `VANZARI_DETALII`**.
-
-Recalculele de totaluri (`PF:13760+`, `recalculeaza_totaluri_vanzari` `PF:16021`) si rotunjirile
-lucreaza pe **`VANZARI`**, agregat — nu rescriu linia.
-
-**Raspuns Q3**: nu. Dupa insertul in temp, cele cinci valori nu mai sunt suprascrise nicaieri.
-`DIFERENTA` si `CANTITATE` da, restul nu.
-
-## 4. Verdict: ajung valorile din formular neatinse in `VANZARI_DETALII`?
-
-**NU, pentru trei familii de tipuri. DA, pentru restul.**
-
-Se pierd **intr-un singur loc**: `PACK_FACTURARE.adauga_articol_factura`, in `CASE`-ul de la
-**`PF:5052-5220`**, adica **inainte** de `INSERT INTO VANZARI_DETALII_TEMP` (`PF:5222`). Precis:
-
-- **contract** (`ntip IN (2,6,26,52)` cu `CONTRACTE.OPT_FACTURARE` NULL sau 3) — `PF:5149-5153`:
- se pierd `PRET` (cand `CTR_ARTICOLE.PRET_UNITAR <> 0`), `PROC_TVAV`, `ID_VALUTA`, `PRET_CU_TVA`,
- `IN_STOC`;
-- **aviz** (`ntip = 4`) — `PF:5082-5086`: se pierd toate cinci, **inclusiv `PRET`, neconditionat**;
-- **comenzi** (`ntip IN (3,21,28,42,47)`) — `PF:5057-5061`: se pierd patru; `PRET` e fixat de
- `WHERE`, dar la nepotrivire scrierea **cade cu ORA-01403** in loc sa treaca.
-
-Pentru toate celelalte tipuri (1, 5, 10, 22, 45, ...) valorile din formular **ajung neatinse**:
-ramurile `ELSE` (`PF:5200-5203`) si restaurant (`PF:5109-5112`) le copiaza explicit, iar traseul de
-dupa (`PF:13705-13757`) e copiere 1:1.
-
-**Exceptie transversala, valabila pe TOATE tipurile**: `PROC_TVAV` **nu vine niciodata din formular** —
-nu e parametru al procedurii. Pe calea „buna" se deriva din `JTVA_COLOANE` pe `ID_JTVA_COLOANA`-ul
-trimis de formular, deci reproduce documentul **atat timp cat cota din `JTVA_COLOANE` nu s-a
-schimbat**. La o modificare legala de cota, reemiterea schimba TVA-ul chiar si pe ramura `ELSE`.
-
-## 5. Sursa AVIZ (`ntip = 4`) — calea difera, si e mai grava
-
-Verbatim, `PF:5080-5103` (confirmat identic pe DB, `LIVE:3840-3863`):
-
-```
-5080 WHEN pack_facturare.ntip = 4 THEN
-5081 -- facturare din avize
-5082 SELECT DISTINCT A.PRET,
-5083 A.PROC_TVAV,
-5084 A.ID_VALUTA,
-5085 A.PRET_CU_TVA,
-5086 B.IN_STOC
-5087 INTO V_PRET, V_PROC_TVAV, V_ID_VALUTA, V_PRETURI_CU_TVA, V_IN_STOC
-5092 FROM VANZARI_DETALII A
-5093 LEFT JOIN NOM_ARTICOLE B ON A.ID_ARTICOL = B.ID_ARTICOL
-5095 WHERE A.ID_ARTICOL = V_ID_ARTICOL
-5096 AND A.ID_POL = V_ID_POL
-5097 AND NVL(A.ID_GESTIUNE, -1000) = V_ID_GESTIUNE
-5098 AND A.DISCOUNT_UNITAR = V_DISCOUNT_UNITAR
-5099 AND NVL(A.CONT, 'XXXX') = V_CONT
-5100 AND A.ID_VANZARE IN
-5101 (SELECT X AS ID_VANZARE
-5102 FROM table(cast(CHARN2COLLECTION(pack_facturare.clistaid, ',') AS num_tab)));
-```
-
-Diferentele fata de contract, toate in defavoarea deciziei 54:
-
-1. **`PRET` se re-deriva neconditionat**, direct din `VANZARI_DETALII` al **avizului sursa**. Nu exista
- `DECODE(..., 0, V_PRET_TEMP, ...)` si **nu exista `AND A.PRET = V_PRET_TEMP`** in `WHERE` (spre
- deosebire de ramura comenzi, `PF:5077`). Un pret modificat pe ecran la reemitere e **inlocuit
- tacit** cu pretul din aviz. **Aceasta e ramura cea mai agresiva din tot `CASE`-ul.**
-2. **Nu are bloc `EXCEPTION`.** Ramura contract are `NO_DATA_FOUND` care cade inapoi pe formular
- (`PF:5167-5185`); aici, orice modificare pe ecran a `DISCOUNT_UNITAR`, `CONT`, `ID_GESTIUNE` sau
- `ID_POL` scoate randul din `WHERE` -> **ORA-01403** urcata in VFP. `SELECT DISTINCT` peste mai
- multe avize cu preturi diferite pe acelasi articol poate da si **ORA-01422** (`TOO_MANY_ROWS`).
-3. **Nu filtreaza `A.STERS = 0`**, desi `VANZARI_DETALII` are coloana `STERS` (verificat pe DB) si
- `sterge_factura` o foloseste (`PF:5560`). Linii sterse ale avizului sursa pot fi citite.
-4. Depinde de `pack_facturare.clistaid` — lista de avize sursa, trimisa de VFP prin
- `initializeaza_date_factura` (`poDate.listaid`, `ofacturare.vc2:13992`). La reemitere, `clistaid`
- trebuie repopulata cu aceleasi avize, altfel `WHERE` nu potriveste nimic -> ORA-01403.
-
-**Ce nu difera**: dupa `CASE` traseul e identic (`INSERT` in temp `PF:5222`, apoi copiere 1:1
-`PF:13705`), iar `scrie_factura_avize` (`PF:6692`) modifica in temp **numai `CANTITATE`**
-(`PF:6860`, `PF:6864`) — nu re-deriva nimic in plus.
-
-**Raspuns Q5**: calea difera, si e **mai stricta**. Pe contract exista o portita (`PRET_UNITAR = 0`
-si `NO_DATA_FOUND`) prin care valorile din formular trec; pe aviz **nu exista niciuna** — ori se
-re-deriva tot, ori pica cu eroare.
-
-## 6. Consecinta pentru decizia 54, la nivel de contract
-
-### 6.1 Se poate curat VFP? **Nu.**
-
-Confirm afirmatia rundei 9 — dar acum cu dovada, nu prin absenta:
-
-- **Semnatura nu are flag.** `PF:4989-5015`: 27 de parametri, toti date de linie; ultimii doi
- (`V_TAXCODE`, `V_LOT`) sunt `DEFAULT NULL`, niciunul nu e comutator.
-- **Globalele pachetului nu au flag.** `PF:126-212` — stare de sesiune (`ntip`, `clistaid`,
- `nid_part`, ...), niciun comutator de comportament pe re-derivare.
-- **Poarta nu e influentabila legitim din VFP.** `ntip` ajunge in `VANZARI.TIP` (`PF:13670`) — a-l
- falsifica inseamna a schimba tipul documentului. `CONTRACTE.OPT_FACTURARE` e date de contract, nu
- parametru de apel.
-- **Singurele parghii VFP care ar devia pe calea `NO_DATA_FOUND` sunt, ambele, de aceeasi natura ca
- varianta (d) deja respinsa:**
- - `V_ID_CTR = NULL` — respinsa; `PF:5280` duce `V_ID_CTR` in `temp.ID_CTR`, iar `PF:13755` in
- `VANZARI_DETALII.ID_CTR`, deci legatura se pierde permanent;
- - `V_ID_POL = NULL` — **acelasi defect, alta coloana**: `PF:5258` duce `V_ID_POL` in `temp.ID_POL`,
- `PF:13737` in `VANZARI_DETALII.ID_POL`; in plus ar rupe ramura aviz, care potriveste pe
- `A.ID_POL = V_ID_POL` (`PF:5096`). **Nu o propun** — o mentionez ca sa nu fie redescoperita ca
- „solutie" intr-o runda urmatoare.
-
-**Concluzie: decizia 54 cere obligatoriu modificare in `pack_facturare`.**
-
-### 6.2 Ce forma trebuie sa aiba semnalul
-
-Doua forme sunt inerte pentru apelantii de azi:
-
-- **(i) variabila noua de pachet** („regenerare in curs"), implicit `0` = comportamentul actual, scrisa
- de VFP **dupa** `initializeaza_date_factura` si inainte de bucla de `adauga_articol_factura`;
-- **(ii) parametru `DEFAULT 0`** adaugat **dupa** `V_LOT` in semnatura — apelantii de azi trimit 27 de
- argumente pozitional si raman valizi.
-
-**Recomand (i)**, din trei motive concrete: se potriveste cu stilul existent al pachetului (care e deja
-o punga de stare de sesiune); se scrie o data pe document, nu o data pe linie, in toate produsele; si
-**punctul de resetare exista deja** — `initializeaza_date_factura` (`PF:1808-1917`) reinitializeaza
-~40 de globale si face `DELETE FROM VANZARI_DETALII_TEMP` (`PF:1835`), deci flag-ul nu poate scapa in
-documentul urmator din aceeasi sesiune. Atentie la ordine: VFP il seteaza **dupa** apelul de la
-`ofacturare.vc2:13981`, nu inainte. Ambele variante modifica spec-ul, deci ambele forteaza
-recompilarea dependentilor — nu e un criteriu de departajare.
-
-### 6.3 Ce face semnalul, cand e pornit
-
-**Nimic nou** — forteaza ramura care exista deja. Cea mai mica forma: un `WHEN` nou, **primul** in
-`CASE`-ul de la `PF:5052`, cu **acelasi corp ca `ELSE`-ul de azi** (`PF:5189-5203`): `PROC_TVAV` din
-`JTVA_COLOANE` pe `V_ID_JTVA_COLOANA`, si `V_PRET`/`V_ID_VALUTA`/`V_PRETURI_CU_TVA`/`V_IN_STOC` din
-parametrii `*_TEMP`. `INSERT`-ul de la `PF:5222` ramane neatins. Acopera dintr-o data **toate trei**
-ramurile problematice (contract, aviz, comenzi), pentru ca toate sunt in acelasi `CASE`.
-
-### 6.4 Trei consecinte de acceptat explicit, nu ocolite
-
-1. **`IN_STOC` ar veni din formular** (`poArt.gestionabil`) in loc de `NOM_ARTICOLE`. Nu e o problema
- de fidelitate a documentului — `VANZARI_DETALII` **nu are coloana `IN_STOC`** (verificat pe DB) —
- ci de **comportament de stoc** la reemitere. Ca reemiterea sa fie identica, incarcarea (S8) trebuie
- sa dea valoarea cu care s-a scris documentul initial. **Azi nu o da**: loader-ul lui #6 o citeste
- din nomenclatorul curent — `ofacturare_editare.prg:302-303`,
- `left join nom_articole na on na.id_articol = v.id_articol`, cu comentariul care spune ca view-ul
- n-o expune. **Flag-ul singur nu rezolva asta.**
-2. **Se pierde o validare pe ramura comenzi.** `A.PRET = V_PRET_TEMP` (`PF:5077`) plus lipsa lui
- `EXCEPTION` fac azi 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 exact asta, dar e o schimbare de comportament care trebuie spusa, nu
- descoperita la S12.
-3. **`PROC_TVAV` ramane derivat**, nu preluat. Reproducerea exacta a documentului cere ca S8 sa
- pastreze `ID_JTVA_COLOANA` **si** ca `JTVA_COLOANE.COTA_TVA` sa nu se fi schimbat intre timp. Daca
- se cere reproducere exacta si peste o modificare de cota, `PROC_TVAV` trebuie sa devina
- **parametru** — schimbare mai mare decat flag-ul, de decis separat.
-
-### 6.5 Un obstacol de incarcare, gasit in treacat (pentru S8, nu pentru S10)
-
-View-ul pe care se sprijina incarcarea de azi, **`VVANZARI_ARTICOLE`**, expune (interogat pe DB):
-`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,
-ID_VANZARE_SET, PRET_ACHIZITIE, DENUMIRE, CODMAT, NUME_GESTIUNE, NUME_VAL`.
-
-**Nu expune `ID_POL` si nu expune `ID_CTR`** — exact cei doi pe care `adauga_articol_factura` ii cere
-(`V_ID_POL`, `V_ID_CTR`) si pe care `VANZARI_DETALII` ii pastreaza. Reemiterea S9 **nu poate folosi
-acest view ca atare**; ori se completeaza view-ul, ori loader-ul citeste direct din
-`VANZARI_DETALII`. Nu e in perimetrul S10, dar blocheaza S9 daca nu e prins din timp.
-
----
-
-## Tabel sintetic — cele cinci valori pe ramura
-
-„temp" = valoarea trimisa de formular; „re-derivat" = citita din alta sursa si suprascrisa.
-
-| valoare | **contract** (2/6/26/52, `OPT_FACTURARE` NULL sau 3) | **aviz** (`ntip = 4`) | comenzi (3/21/28/42/47) | restaurant (45) | `ELSE` |
-|---|---|---|---|---|---|
-| `PRET_UNITAR` (`PRET`) | **re-derivat** din `CTR_ARTICOLE.PRET_UNITAR` daca `<> 0`; **temp** daca `= 0`; **NULL** daca e NULL (`PF:5149`) | **re-derivat** din `VANZARI_DETALII` al avizului, **neconditionat** (`PF:5082`) | **temp** de facto — `WHERE A.PRET = V_PRET_TEMP` (`PF:5077`); nepotrivire = ORA-01403 | **temp** (`PF:5109`) | **temp** (`PF:5200`) |
-| `PROC_TVAV` | **re-derivat** din `CRM_POLITICI_PRET_ART` (`PF:5150`) | **re-derivat** din avizul sursa (`PF:5083`) | **re-derivat** din `COMENZI_ELEMENTE.PTVA` / politica (`PF:5058`) | **re-derivat** din `JTVA_COLOANE` (`PF:5114`) | **derivat** din `JTVA_COLOANE` pe `ID_JTVA_COLOANA` din formular (`PF:5189`) |
-| `ID_VALUTA` | **re-derivat** din `CRM_POLITICI_PRET_ART` (`PF:5151`) | **re-derivat** din avizul sursa (`PF:5084`) | **re-derivat** din politica (`PF:5059`) | **temp** (`PF:5110`) | **temp** (`PF:5201`) |
-| `PRET_CU_TVA` | **re-derivat** din `CTR_ARTICOLE` (`PF:5152`) | **re-derivat** din avizul sursa (`PF:5085`) | **re-derivat** din `CRM_POLITICI_PRETURI` (`PF:5060`) | **temp** (`PF:5111`) | **temp** (`PF:5202`) |
-| `IN_STOC` | **re-derivat** din `NOM_ARTICOLE` (`PF:5153`) | **re-derivat** din `NOM_ARTICOLE` (`PF:5086`) | **re-derivat** din `NOM_ARTICOLE` (`PF:5061`) | **temp** (`PF:5112`) | **temp** (`PF:5203`) |
-
-`PROC_TVAV` **nu vine din temp pe nicio ramura** — nu e parametru al procedurii.
-`IN_STOC` **nu ajunge in `VANZARI_DETALII`** (coloana nu exista) — traieste doar in temp, unde decide
-descarcarea de gestiune.
-Pe ramura contract, `EXCEPTION WHEN NO_DATA_FOUND` (`PF:5167-5185`) muta **toate cele cinci** pe
-coloana „temp"; ramurile aviz si comenzi **nu au** un asemenea bloc.
-
-## Verificat direct vs. dedus
-
-**Verificat direct pe fisier SI confirmat pe DB** (`all_source`, `MARIUSM_AUTO.PACK_FACTURARE`,
-`PACKAGE BODY`, VALID, `last_ddl_time = 2026-08-09 20:03:50`):
-granitele lui `adauga_articol_factura`; toate cele cinci ramuri ale `CASE`-ului, ramura cu ramura;
-textul integral al ramurii aviz; faptul ca insertul procedurii merge in `VANZARI_DETALII_TEMP`; ca
-exista exact doua `INTO VANZARI_DETALII` in tot pachetul.
-
-**Verificat direct pe fisier** (nereconfirmat separat pe DB, dar in aceeasi zona cu offset masurat):
-copierea 1:1 temp -> `VANZARI_DETALII` (`PF:13705-13757`); cele patru `UPDATE VANZARI_DETALII` si ce
-coloane ating; mutatiile pe temp intre `adauga_articol_factura` si `scrie_in_vanzari`; corpul lui
-`pack_auto.actualizeaza_deviz`.
-
-**Verificat pe metadatele DB**: `VANZARI_DETALII` nu are `IN_STOC`, are `STERS`;
-`CTR_ARTICOLE.PRET_UNITAR` e `nullable=Y`; lista de coloane a lui `VVANZARI_ARTICOLE`.
-
-**Verificat direct in VFP**: apelantii lui `adauga_articol_factura`; maparea celor 27 de parametri;
-`ntip := poDate.Tip`; loader-ul `IncarcaArticoleFactura` (`ofacturare_editare.prg:292-327`).
-
-**Dedus, nerulat**: comportamentul `DECODE` cu `PRET_UNITAR` NULL (semantica Oracle, nu test);
-ORA-01403 / ORA-01422 pe ramurile fara `EXCEPTION` (din absenta blocului, nu din reproducere).
-
-**Din date de dev — NU e dovada, nu extrapolati**: `CTR_ARTICOLE` are **27** de randuri
-(0 NULL, 10 cu `PRET_UNITAR = 0`, 17 cu `<> 0`) — deci **cazul NULL nu apare in dev**, ceea ce nu
-spune nimic despre productie. `CONTRACTE.OPT_FACTURARE`: 176 NULL, 53 = 0, 9 = 1, 3 = 3, 1 = 4 —
-adica pentru **176 + 3 din 242** de contracte `NVL(OPT_FACTURARE, 3)` da 3 si ramura re-deriva.
-
-**Neacoperit**: n-am rulat niciun flux real (nici VFP, nici o reemitere efectiva) — totul e analiza
-statica plus interogari `SELECT` pe metadate. N-am citit corpurile `scrie_factura2` si
-`finalizeaza_factura` integral, doar punctele in care ating `VANZARI_DETALII` / temp.
-
-## Corectii la rapoartele anterioare
-
-### `docs\cercetare\s10_pret_rederivat.md` (runda 9)
-
-1. **„exista exact o ramura care suprascrie pretul — contractul" — FALS.** Ramura **aviz**
- (`ntip = 4`, `PF:5080-5103`) suprascrie `PRET` **neconditionat**, fara `DECODE` si fara filtru pe
- pretul din formular — **mai agresiv decat contractul**. Ramura **comenzi** (`PF:5053-5078`) nu
- suprascrie `PRET`, dar suprascrie celelalte patru si **arunca ORA-01403** la nepotrivire.
- Ramurile care re-deriva sunt **trei**, nu una.
-2. **„pe calea de scriere" — corect ca moment, gresit ca destinatie.** Se intampla la salvare, dar
- insertul e in **`VANZARI_DETALII_TEMP`** (`PF:5222`), nu in `VANZARI_DETALII`. Diferenta conteaza:
- explica de ce copierea „neschimbata" de mai tarziu nu protejeaza nimic.
-3. **„nu exista niciun parametru sau flag care sa opreasca re-derivarea" — CONFIRMAT**, acum cu dovada
- pozitiva (semnatura `PF:4989-5015`, globalele `PF:126-212`), nu prin absenta.
-
-### `docs\cercetare\s10_pret_contract_reemitere.md` (runda 13)
-
-1. **„acelasi `SELECT` alimenteaza cinci valori" — corect** (`PF:5149-5166`), dar de completat:
- **nu merg impreuna** — `PRET` are `DECODE`, celelalte patru sunt neconditionate, si vin din trei
- tabele diferite.
-2. **„`IN_STOC` din nomenclatorul curent" — corect**, de completat cu faptul decisiv:
- **`VANZARI_DETALII` nu are coloana `IN_STOC`** (verificat pe DB). Nu ajunge in document; efectul e
- pe descarcarea de gestiune.
-3. **„`scrie_in_vanzari` copiaza `PRET` neschimbat din temp" — corect** (`PF:13705-13757`), de marcat
- insa ca **nu e o protectie**: dauna e amonte de temp.
-4. Varianta **„avertizare + confirmare" ramane respinsa** (decizia 54) — nu am reargumentat-o.
-
-### `docs\plan_13_unificare_formular_facturare.md`
-
-- Trimiterea „`initializeaza_date_factura` (`PACK_FACTURARE:1808-1846`)" — corpul incepe la `PF:1808`
- dar se termina la **`PF:1917`**. Citarile `:1835` / `:1836` din plan sunt corecte.
diff --git a/docs/cercetare/s11_legaturi_id_vanzare.md b/docs/cercetare/s11_legaturi_id_vanzare.md
deleted file mode 100644
index 8035429..0000000
--- a/docs/cercetare/s11_legaturi_id_vanzare.md
+++ /dev/null
@@ -1,379 +0,0 @@
-# S11 — Legaturile care raman pe `ID_VANZARE` la editarea prin regenerare
-
-Stare: **in lucru**. Vezi sectiunea STARE / CE RAMANE la final pentru progres curent.
-
-## Context (dat, nu se rediscuta)
-
-#13 etapa II: editarea unei facturi = regenerare. Documentul vechi e soft-sters (`STERS=1`) si
-reemis in aceeasi tranzactie. `ID_FACT`, seria, numarul si data se pastreaza. **`ID_VANZARE` se
-schimba** — documentul reemis primeste un `id_vanzare` nou din secventa.
-
-Sarcina: inventarul complet al legaturilor pe `VANZARI.ID_VANZARE` care se rup la aceasta
-schimbare, clasificate (A) trebuie remigrat / (B) trebuie sters-refacut / (C) nu conteaza.
-
-## 0. Puncte de plecare (de verificat, nu de preluat pe incredere)
-
-- `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`
-- `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`
-- `docs\cercetare\s5c_factura_din_proforma.md` (sectiunea `VANZARI_CORESP`)
-- PL/SQL: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`
-
-## 0-bis. Constatare centrala care schimba premisa din plan
-
-**Mecanismul S9 (planificat) NU e acelasi cu mecanismul deja existent de editare (#6).** Astea sunt
-doua cai distincte, si asta conteaza pentru fiecare consumator de mai jos:
-
-- **#6, "editare directa"** (`frm_modific2024`/`omodificari.vc2`, `afisjurcom.do_modifica`,
- `pack_contafin.finalizeaza_modificare_nota`): documentul vechi (identificat prin `cod`) primeste
- `STERS=1` in `ACT`/`RUL`, se scrie un document nou cu `cod` nou, apoi
- **`pack_facturare.actualizeaza_vanzari(V_COD_VECHI, V_COD_NOU)`**
- (`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16012-16022`) face
- `UPDATE VANZARI SET COD = V_COD_NOU, STERS = 0 WHERE COD = V_COD_VECHI` —
- **randul `VANZARI` e REFOLOSIT, `ID_VANZARE` NU SE SCHIMBA**, doar `COD`. In continuare,
- `finalizeaza_modificare_nota` face si `UPDATE atasamente_vanzari SET cod = lnCodNou WHERE cod =
- tnCod` (`rec_modific2024.md:126`, confirmat `fisier:linie`). Acesta e mecanismul deja **livrat in
- productie** (git log: `#6 editare factura emisa`, changelog 2.11.15/2.11.16).
-- **#13 S9 (planificat, subiectul acestei cercetari)**: reemiterea merge **pe drumul normal de
- emitere**, `scrie_factura2` -> `finalizeaza_factura` -> `scrie_in_vanzari`, care face
- `INSERT INTO VANZARI (...) VALUES (...) RETURNING ID_VANZARE INTO pack_facturare.nid_vanzare`
- (`rec_cale_vanzari_detalii.md:99`, confirmat separat in planul S9: „reemiterea scrie prin
- `pack_facturare`, pe acelasi drum ca emiterea", `plan_13...md:2936-2937`). Acesta e un rand **nou**,
- cu **`ID_VANZARE` nou din secventa** — exact premisa data de team-lead. `oscrie_in_fisiere`
- intervine in S9 **doar la stergerea** documentului vechi (`plan_13...md:2938`), nu si la scriere,
- deci **`actualizeaza_vanzari`/sincronizarea prin `finalizeaza_modificare_nota` NU se declanseaza
- pentru S9** — acel mecanism ramane specific caii #6, nu se mosteneste automat de S9.
-
-**Consecinta directa**: orice legatura tinuta azi prin `cod` (realiniata gratis de mecanismul #6) e
-**expusa** la regenerarea din #13, pentru ca S9 nu trece prin `actualizeaza_vanzari`. Fiecare sectiune
-de mai jos noteaza explicit daca protectia #6 s-ar fi aplicat sau nu.
-
-## 1. Inventarul exhaustiv al consumatorilor de ID_VANZARE
-
-| # | Tabela/mecanism | Cheie folosita | Scriitor(i) | Cititor(i) | Clasificare |
-|---|---|---|---|---|---|
-| 1 | `ATASAMENTE_VANZARI` | `ID_VANZARE` (FK real `FK_AT_VANZ001` -> `VANZARI.ID_VANZARE`) + coloana `COD` (legacy, vezi §2) | `ofacturare_comun.prg:466` (VFP INSERT direct), `pack_facturare.scrie_atasamente_factura` (PL/SQL, `ff_...:13955-13988`) | `VATASAMENTE_VANZARI` (view, JOIN pe `id_vanzare`), `ROAGEST`/`ROAIMOB` `oproceduri_atasamente.prg` (`citeste_atasament_vanzari`, `arata_meniu_at_vanz` — cauta pe `cod` via view) | **(A) trebuie remigrat** — vezi §2 |
-| 2 | `marcheaza_facturat` -> `VANZARI.FACTURAT`/`ID_UTILFACT` | `VANZARI_CORESP.ID_VANZARE_FACT` (documentul nou) leaga la sursa | `pack_facturare.marcheaza_facturat`, apelata din `finalizeaza_factura` (`ff_...:14827,14831`) | citit la filtrarea avizelor/comenzilor facturabile | **(C) nu conteaza pentru discontinuitatea ID_VANZARE-ului documentului editat** — vezi §3 (releaga sursa, nu documentul editat insusi) |
-| 3 | `VANZARI_CORESP` | `ID_VANZARE_FACT`/`ID_VANZARE_AVIZ`, ambele pe `VANZARI.ID_VANZARE` | `pack_facturare.scrie_corespondente_vanzari`, singurul writer (`s5c_factura_din_proforma.md:92-96`) | `sterge_factura` (garda la stergere), afisare "provine din X" | **(A) trebuie remigrat daca documentul editat e parte a unui lant retur/aviz->factura** — vezi §3 |
-| 4 | `VANZARI_CANTITATI` | `ID_VANZARE` (a avizului sursa, nu a facturii editate) | `scrie_cantitati_vanzari_avize`, apelata doar `ntip=4` | `marcheaza_facturat(V_VERIFICARE=1)` | **(C) nu conteaza** — vezi §3, tine de sursa, neatinsa de editarea facturii |
-| 5 | `DOCUMENTE` | `ID_DOC` = `ID_FACT` (nu `ID_VANZARE`) | `SET_IDFACT`/INSERT in `SCRIE_IN_ACT` | `SET_IDFACT` cautare veche (inactiva) | **(C) confirmat fara legatura cu ID_VANZARE** — vezi §4, acoperit deja de `idfact_refolosire_si_documente.md`, nu se reface |
-| 6 | eFactura (`ANAF_EFACTURA`, `EsteInEFactura`) | `VANZARI.ID_FACT` (nu `ID_VANZARE`) | — | `ofacturare_editare.prg`/`omodificari.vc2` | **(C) nu conteaza** — cheia e `ID_FACT`, care se pastreaza — vezi §5 |
-| 7 | Listari/rapoarte facturi (`FACT_VFACTURI*`, grid cautare) | `ID_VANZARE` + `ID_FACT`/serie+numar, cautari mixte | — | multiple | **de verificat, vezi §5** — cele care cauta dupa serie+numar/ID_FACT raman corecte; cele care tin un `ID_VANZARE` stocat undeva (ex. favorite, ultima factura deschisa) s-ar rupe |
-| 8 | Incasari/plati (`INCASARI`, `PLATI`, `IREG_PARTENERI`) | **de verificat** | — | — | **in lucru, vezi §6** |
-
-## 2. ATASAMENTE_VANZARI
-
-**Nu sunt documente incarcate de utilizator — sunt exporturi PDF AUTO-GENERATE ale documentului
-tiparit** (factura/aviz/recapitulatie/invoice), salvate automat dupa listare. Dovada, pas cu pas:
-
-- Scrierea porneste din `frm_facturi.do_listeaza_formular`/fluxul de listare, la
- `COMUN\programe\ofacturare.prg:2102-2105`:
- ```
- If poDate.nRelistare = 0 And poDate.eProforma = 0 AND poDate.nEFactura = 0 And poDate.nSalveazaAtasamente = 1
- poDate.scrieAtasamente()
- Endif
- ```
- imediat dupa exportul PDF al recapitulatiei (`:2068`, `goExport.export2pdf('crsrecapitulatie',
- 'recapitulatie', .F., poDate.cDocAtasate)`) — `poDate.cDocAtasate` **e** numele cursorului
- `crsoDateDocAtasate`, populat de motorul de export PDF, nu de un dialog de upload.
-- `crsoDateDocAtasate` se creeaza gol la `ofacturare.prg:233`: `Create Cursor crsoDateDocAtasate
- (nume_frx c(50), fisier w)` — nicio referinta la `GETFILE()`/`GETPICT()`/dialog de fisier in tot
- `ROAFACTURARE`/`COMUN` legata de acest cursor (cautat explicit, zero potriviri).
-- `scrieAtasamente` (`ofacturare_comun.prg:429-475`) clasifica `TIP` dupa numele raportului
- (`FACTURA_VAL*`->2, `FACTURA*`->1, `INVOICE*`->3, `RECAPITULATIE`->4, `AVIZ*`->5) si scrie:
- `INSERT INTO ATASAMENTE_VANZARI(ID_VANZARE, TIP, FORMAT, DOCUMENT, ID_UTIL) VALUES (?pnId, ...)`
- (`:466`) — `pnId = poDate.nid_vanzare` (sau `nid_vanzare_retur` pentru cazul aviz->factura). Deci
- scriitorul **foloseste exclusiv `ID_VANZARE`**, niciodata `COD`.
-- Cititorii confirmati: `ROAGEST\COMUN\programe\oproceduri_atasamente.prg` (identic in `ROAIMOB`) —
- `citeste_atasament_vanzari` (`SELECT document FROM atasamente_vanzari WHERE id_at_vanz=...`) si
- `arata_meniu_at_vanz(tnCod,...)` (`SELECT ... FROM vatasamente_vanzari a WHERE a.cod = ...`,
- `:56`) — ambele read-only, mecanism de "vezi documentele salvate pentru aceasta factura",
- disponibil din ROAGEST/ROAIMOB (alte produse ale suitei, confirmand ca S11 trebuia sa caute in
- toata suita, nu doar ROAFACTURARE).
-
-**Structura reala (interogata pe schema vie `MARIUSM_AUTO`)**: `ATASAMENTE_VANZARI(ID_AT_VANZ PK
-NOT NULL din secventa, ID_VANZARE NUMBER NULL, DOCUMENT BLOB, TIP, FORMAT, STERS NOT NULL, ID_UTIL,
-DATAORA NOT NULL, ID_UTILS, DATAORAS, COD NUMBER NULL)`. FK real: `FK_AT_VANZ001` pe `ID_VANZARE ->
-VANZARI.ID_VANZARE` (`PK_VANZARI`). Coloana `COD` **nu e scrisa de niciun cod curent** (scriitorii
-gasiti folosesc doar `ID_VANZARE`) — e populata azi doar de mecanismul legacy #6
-(`finalizeaza_modificare_nota`'s `UPDATE atasamente_vanzari SET cod = lnCodNou WHERE cod = tnCod`,
-care **nu poate seta `cod` pe un rand care nu-l are deja** — e un realiniere, nu o initializare).
-Pe schema de test `MARIUSM_AUTO`, toate cele 20 de randuri existente au `COD` populat si
-`ID_VANZARE` NULL (probabil date vechi, dinainte ca `ID_VANZARE` sa fie coloana activa) — cf.
-memoriei de proiect, **zero cazuri in date nu e dovada**, dar dovada de cod (scriitorii folosesc
-doar `ID_VANZARE`) e independenta de date si sta singura.
-
-**Cheia reala de legatura azi e `ID_VANZARE`, prin view**: `VATASAMENTE_VANZARI` (definitie
-interogata direct din `ALL_VIEWS`):
-```sql
-select a.id_at_vanz, a.tip, decode(a.tip,1,'Factura',2,'Factura in valuta',3,'Invoice',
- 4,'Recapitulatie',5,'Aviz','Alt document') as tip_doc, b.cod
- from atasamente_vanzari a
- left join vanzari b on a.id_vanzare = b.id_vanzare
- where a.sters = 0 and b.sters = 0
-```
-`cod` in view **nu e coloana stocata pe `atasamente_vanzari`** — e `VANZARI.COD` curent, calculat
-live prin JOIN pe `ID_VANZARE`. Consumatorii din alta suita (`ROACONT\Programe\orap_terti.prg:1854`,
-`ROACONTRACTE\Programe\oparteneri_contracte.prg:190,229` — `LEFT JOIN vatasamente_vanzari ... ON
-a.cod = b.cod`, pentru afisarea unui numar de atasamente pe rand de factura) folosesc de fapt tot
-`ID_VANZARE`, indirect prin acest JOIN.
-
-**Ce se rupe la regenerare (S9, calea B din §0-bis)**: `atasamente_vanzari.id_vanzare` al randurilor
-vechi ramane neschimbat, aratand spre `VANZARI` cu `STERS=1` dupa stergerea documentului vechi.
-`WHERE b.sters = 0` din view **filtreaza acele randuri afara** — atasamentele **dispar tacit** din
-orice interogare prin `VATASAMENTE_VANZARI` (inclusiv `arata_meniu_at_vanz` din ROAGEST/ROAIMOB),
-desi BLOB-ul ramane fizic in tabel. Documentul nou (`ID_VANZARE` nou) nu are niciun atasament legat.
-**Clasificare: (A) trebuie remigrat** — `UPDATE atasamente_vanzari SET id_vanzare = :id_nou WHERE
-id_vanzare = :id_vechi AND sters = 0`, in aceeasi tranzactie ca restul regenerarii (acelasi tipar ca
-`actualizeaza_vanzari` de la #6, dar pe `id_vanzare` in loc de `cod`, si trebuie scris nou — #6 nu
-acopera acest caz, cf. §0-bis).
-
-**Corectie fata de premisa din briefing**: nu e "pierdere de date reala" in sensul de date
-introduse de utilizator si irecuperabile — snapshot-ul se poate regenera prin relistare (acelasi
-mecanism care l-a creat prima data). Ce s-ar pierde real e **istoricul exact al PDF-ului trimis
-clientului la momentul emiterii initiale** (relevant daca factura a fost deja trimisa/tiparita
-inainte de editare) — merita remigrare oricum, ca sa nu se piarda urma, dar motivatia corecta e
-"pastrarea unui audit trail", nu "date introduse de utilizator".
-
-## 3. marcheaza_facturat / VANZARI.FACTURAT / VANZARI_CANTITATI / VANZARI_CORESP
-
-**Inventarul FK declarat pe `VANZARI.ID_VANZARE`** (interogare directa pe schema `ACN`, cea reala —
-`ALL_CONS_COLUMNS`/`ALL_CONSTRAINTS`, `r_constraint_name = PK_VANZARI`), confirma si extinde lista
-din briefing:
-
-| Tabela | Coloana | Constraint |
-|---|---|---|
-| `ATASAMENTE_VANZARI` | `ID_VANZARE` | `FK_AT_VANZ001` |
-| `VANZARI_CORESP` | `ID_VANZARE_FACT` | `FK_VANZARI_CORESP_001` |
-| `VANZARI_CORESP` | `ID_VANZARE_AVIZ` | `FK_VANZARI_CORESP_002` |
-| `VANZARI_CURSURI` | `ID_VANZARE` | `FK_VANZARE_CURS_002` |
-| `VANZARI_DETALII` | `ID_VANZARE` | `FK_VANZARE_DET001` |
-| `REST_NOTE_PLATA` | `ID_VANZARE` | `FK_REST_NOTE_PLATA_004` |
-| `IPS_VOYAGES_VANZARI` | `VZ_ID` | `FK_VOYAGES_VANZARI_2` |
-
-Primele cinci erau asteptate (vezi §1-2 si mai jos). **Ultimele doua nu erau in lista din plan** —
-descoperite prin FK, nu prin cautare de text, exact motivul pentru care inventarul trebuia facut pe
-schema, nu doar pe cod. Ambele sunt module de business **specifice unui singur tip de document**
-(`pack_facturare.ntip`), nu cai generale:
-
-- **`REST_NOTE_PLATA`** — modul restaurant (`PACK_RESTAURANT`, `nTipFacturaRestaurant`). La
- stergerea unei vanzari de tip restaurant, `sterge_factura` cheama deja
- `pack_restaurant.sterge_vanzare(V_ID_VANZARE, V_ID_UTIL)` (`ff_...:5593`, in `CASE`-ul de la
- finalul procedurii) — un hook dedicat, separat de logica generala. **Nu s-a gasit un hook simetric
- „re-leaga la reemitere"** in codul citit (nu era in scop sa se citeasca tot `PACK_RESTAURANT` —
- pachet separat, mii de linii). Clasificare: **(A) suspecta, needs follow-up dedicat** — afecteaza
- doar documentele cu `ntip = nTipFacturaRestaurant`, deci doar daca #13 include si acest tip in
- „regenerabile" (de confirmat in `COMUN\docs\tipuri_documente_facturare.md`, cf. S13).
-- **`IPS_VOYAGES_VANZARI`** — modul specific schemei `ACN` (`PACK_ACN`, `nTipFacturaACN`), legat de
- un tabel `IPS_VOYAGES_VANZARI`/`IPS_VOYAGE_MEMBERS_VANZARI`/`IPS_VVOYAGE_MEMBERS` (confirmat in
- `ris_2024_04_09_01_ACN.sql:258-266`, JOIN pe `vz.id_vanzare = vv.vz_id`) — pare o extensie de
- business pentru un client specific (calatorii/voiaje), nu parte din suita generica ROA. Acelasi
- tipar: `sterge_factura` cheama `pack_acn.sterge_vanzare(...)` la stergere (`ff_...:5596-5600`,
- `execute immediate` conditionat de `pack_migrare.ObjectExist('PACK_ACN')` — pachetul exista doar
- pe schema ACN). Clasificare: **(A) suspecta, needs follow-up dedicat** — probabil in afara
- perimetrului #13 (client unic, tip de factura special), dar trebuie confirmat, nu presupus.
-
-**`VANZARI_CURSURI`** — cursul valutar al documentului. Scris de `pack_facturare.scrie_cursuri(nid_vanzare)`
-(`rec_cale_vanzari_detalii.md:102`), apelat **in interiorul aceluiasi `scrie_in_vanzari`** care
-genereaza noul `ID_VANZARE` la reemitere (S9 foloseste exact acest drum, cf. §0-bis). Deci un rand
-nou `VANZARI_CURSURI` se scrie automat pentru noul `ID_VANZARE`, fara nicio interventie separata.
-**Clasificare: (B)** — se reface singur, ca parte a drumului normal de emitere, nimic de adaugat.
-
-**`VANZARI_DETALII`** — liniile facturii. E miezul a ceea ce regenerarea insasi scrie (INSERT direct
-pe noul `ID_VANZARE`, cf. `rec_cale_vanzari_detalii.md:105-113`) — nu e un consumator "extern" care
-sa se rupa, e obiectul regenerarii. **Clasificare: (B)**, deja acoperit de proiectarea S9/S10, nu se
-reface aici.
-
-### VANZARI_CORESP — cazul netratat inca de plan: documentul editat e EL INSUSI parte a unui lant
-
-Planul (S11, `plan_13...md:3024-3027`) trateaza `VANZARI_CORESP` ca pe o lista simpla, dar
-`sterge_factura` (apelata de S9 la pasul de stergere) arata ca situatia are **doua fete diferite**,
-niciuna simpla:
-
-**(i) Garda de blocare — editarea unui document care e SURSA pentru altul e azi IMPOSIBILA, nu
-riscanta.** `sterge_factura` (`ff_...:5450-5494`) verifica, INAINTE de orice stergere:
-```sql
-SELECT COUNT(*) INTO V_NR_FACT_RETUR FROM VANZARI_CORESP
- WHERE STERS=0 AND ID_VANZARE_AVIZ = V_ID_VANZARE AND TIP = 3;
-IF V_NR_FACT_RETUR > 0 THEN RAISE_APPLICATION_ERROR(-20000, 'Pentru acesta factura s-au emis facturi
- de retur. Trebuie sa stergeti mai intai factura de retur!'); END IF;
-```
-si analog pentru `TIP IN (1,2)` (aviz cu factura/aviz de retur emise pe el) si pentru avizele-sursa
-ale unei „facturi din aviz" (subquery imbricat, `:5478-5494`). **Consecinta pentru S9**: daca
-utilizatorul incearca sa editeze (regenereze) o factura care are deja o factura de retur emisa
-pe ea, sau un aviz care are deja o factura/aviz de retur emis pe el, **pasul de stergere din
-tranzactia S9 arunca `ORA-20000`, tranzactia face rollback, documentul vechi ramane intact** — nu
-e coruptie silentioasa, e un esec curat, dar e o **limitare functionala reala**: aceste documente
-nu pot fi editate prin regenerare deloc, cat timp garda ramane activa (si nu exista niciun motiv
-funcțional sa fie dezactivata — ar contrazice exact protectia pe care garda o ofera azi). *De
-verificat de S12*: ca mesajul de eroare Oracle ajunge inteligibil la utilizator prin formularul de
-editare, nu ca o eroare tehnica generica.
-
-**(ii) Legaturile in care documentul editat e chiar `ID_VANZARE_FACT`/`ID_VANZARE_AVIZ` — marcate
-`STERS=1` la stergere, NU remigrate automat, dar potential rescrise de reemitere daca parametrii
-sunt refurnizati corect.** La stergerea documentului vechi, `sterge_factura` executa neconditionat
-(`:5582-5585`):
-```sql
-UPDATE VANZARI_CORESP SET STERS = V_STERS
- WHERE ID_VANZARE_FACT = V_ID_VANZARE OR ID_VANZARE_AVIZ = V_ID_VANZARE;
-```
-— orice legatura in care documentul vechi apare pe oricare parte devine `STERS=1`. **Nu exista cod
-care sa recreeze automat legatura pentru noul `ID_VANZARE`.** Dar exista o cale prin care se
-recreeaza **corect, de la sine**, daca S9 e proiectat sa refoloseasca drumul normal: `finalizeaza_factura`
-(chemata de reemiterea normala) are un `CASE` pe `pack_facturare.ntip` care scrie din nou
-corespondenta (`WHEN ntip=4: scrie_corespondente_vanzari(1)`; `WHEN ntip=24:
-scrie_corespondente_vanzari(2)`; `WHEN ntip IN (8,9): scrie_corespondente_vanzari(3)`,
-`ff_...:14823-14836`) — **daca** S9 seteaza `pack_facturare.ntip` la aceeasi valoare ca documentul
-original SI re-populeaza `pack_facturare.clistaid`/`clistaid_avize` cu lista de `id_vanzare` sursa
-originala **inainte** de reemitere, corespondenta se scrie natural, cu noul `ID_VANZARE_FACT`.
-**Sursa lista originala e recuperabila** din randurile `VANZARI_CORESP` (acum `STERS=1`) ale
-documentului vechi, citite INAINTE de stergere in aceeasi tranzactie — un pas suplimentar pe care
-proiectarea S9 trebuie sa-l includa explicit, nu e „gratis". **Clasificare: (A) trebuie remigrat
-— dar prin re-derivare + refolosirea mecanismului existent, nu prin UPDATE direct pe `VANZARI_CORESP`**
-(un UPDATE direct ar trebui sa distinga cu grija cele doua roluri — FACT vs AVIZ — si ar risca sa
-resusciteze legaturi catre documente inca sterse din alte motive; re-emiterea naturala prin `ntip`+
-`clistaid` e mai sigura, pentru ca refoloseste exact logica deja validata de emiterea normala).
-
-### marcheaza_facturat — pentru sursa documentului editat, nu pentru documentul insusi
-
-`marcheaza_facturat` (`ff_...:15381-15418`) actioneaza pe **sursa** (avizul din care s-a facturat,
-sau avizul-parinte al unui aviz de retur), nu pe documentul care se editeaza. La stergerea
-documentului vechi (S9, pasul de stergere), pentru `V_TIP=4`/`V_TIP=24`, `sterge_factura` reseteaza
-deja `FACTURAT=0`/`ID_UTILFACT=NULL` pe sursa (`:5504-5510`, `:5525-5533`) si marcheaza
-`VANZARI_CANTITATI.STERS=1` pentru cantitatile consumate (`:5517-5523`, `:5535-5540`) — sursa e deci
-**eliberata** corect de mecanismul EXISTENT, neschimbat. La reemitere, daca `ntip`/`clistaid_avize`
-sunt refurnizate corect (acelasi argument ca la VANZARI_CORESP mai sus), `finalizeaza_factura`
-cheama din nou `scrie_cantitati_vanzari_avize` + `marcheaza_facturat` (`:14825-14827`,`:14831`),
-**reconsumand** sursa sub noul `ID_VANZARE_FACT`. **Clasificare: (C) — mecanismul deja exista si
-functioneaza simetric (elibereaza la stergere, reconsuma la scriere), CONDITIONAT de aceeasi
-cerinta ca la VANZARI_CORESP: S9 trebuie sa refurnizeze `ntip` si `clistaid`/`clistaid_avize`
-originale la reemitere.** Aceasta e exact conditia pe care S12 o testeaza explicit („sursa eliberata
-si reconsumata", `plan_13...md:3037`) — S11 confirma DE CE mecanismul poate functiona (nu e nevoie
-de cod nou pentru asta), dar nu inlocuieste testul S12.
-
-## 4. DOCUMENTE / ID_DOC — legatura cu ID_VANZARE
-
-**Confirmat: fara legatura.** `DOCUMENTE(ID_DOC, ID_UTIL, DATAORA, TVA_INCASARE, SERIE_ACT, NRACT,
-DATAACT, DATAIREG, ID_CTR, ID_SET, STERS, ...)` — INSERT-ul complet citat in
-`idfact_refolosire_si_documente.md:143-148` (`PACK_CONTAFIN.pck:788-817`, cod activ) nu are nicio
-coloana `ID_VANZARE`. Cheia `ID_DOC = ID_FACT`, care se PASTREAZA la regenerare (decizie E/F, deja
-data). Acest raport nu reface analiza — deja acoperita exhaustiv de
-`docs\cercetare\idfact_refolosire_si_documente.md` (S9, punctele A-C), care stabileste separat
-conditiile pentru pastrarea `ID_FACT` (variabila noua de sesiune in `SET_IDFACT` + upsert real in
-`DOCUMENTE`). **Clasificare: (C) — confirmat, fara actiune ceruta de S11.**
-
-## 5. Borderou eFactura si listari
-
-**eFactura: cheia e `ID_FACT`, nu `ID_VANZARE` — confirmat cu dovada proprie, independenta.**
-`EsteInEFactura` (`COMUN\programe\ofacturare_editare.prg`, apelata din `ofacturare_comun.vc2:3764`
-cu `lnIdFact = crsfacturi.id_fact`) verifica prezenta documentului in `ANAF_EFACTURA` **pe
-`VANZARI.ID_FACT`**, nu pe `id_vanzare` — confirmat explicit ca eroare corectata in
-`rec_d42_efactura.md:81-109` (implementarea initiala folosea gresit `id_vanzare`, corectata dupa
-verificare pe date: `id_fact` si `id_vanzare` sunt spatii de ID complet diferite, 0 coincidente pe
-142 facturi testate). **Cum `ID_FACT` se pastreaza la regenerare (decizie deja luata), `EsteInEFactura`
-continua sa functioneze corect pe documentul reemis, fara nicio schimbare.** Aceeasi concluzie se
-aplica probabil borderoului eFactura insusi (cautarea documentelor de trimis/trimise), dar
-**construirea borderoului nu a fost citita in acest raport** (in afara scopului — cheia `ID_FACT`
-fiind deja confirmata stabila, riscul e mic, dar afirmatia stricta „borderoul il gaseste corect"
-ramane de verificat direct pe cod la implementare, nu doar dedusa). **Clasificare: (C), cu rezerva
-de verificare directa a borderoului la implementare.**
-
-**Listari/grid cautare facturi**: cursoarele de grid (`crsFacturi`, `crsFacturiOrd`,
-`ofacturare_comun.vc2:3982,4134-4145,4983`) se reconstruiesc live din Oracle la fiecare deschidere
-a formularului de listare, filtrate pe `sters=0` — nu tin niciun `id_vanzare` persistat intre
-sesiuni. Documentul reemis (nou `id_vanzare`, acelasi `id_fact`/serie/numar) apare normal la
-urmatoarea reincarcare a gridului. **Singurul risc identificat, nu confirmat ca problema reala**:
-daca undeva in cod exista un `id_vanzare` **retinut pe termen lung** in afara sesiunii curente a
-formularului (ex. „ultima factura deschisa", favorite, shortcut) — nu s-a gasit niciun asemenea
-mecanism in codul citit (`ofacturare_comun.vc2`, `ofacturare.prg`), dar nici nu a fost cautat
-exhaustiv in tot `ROAFACTURARE` (in afara bugetului acestei cercetari). **Clasificare: (C),
-neconfirmat ca risc real — verificare suplimentara recomandata daca timpul permite.**
-
-## 6. Incasari/plati si riscuri finale
-
-**Cautare directa (negativa, dar utila): niciun tabel de incasari/plati nu are FK declarat pe
-`VANZARI.ID_VANZARE`.** Interogarea exhaustiva `ALL_CONS_COLUMNS`/`ALL_CONSTRAINTS` pe schema `ACN`
-(tabelul din §3) e completa pentru FK-uri declarate — `INCASARI`, `PLATI`, `IREG_PARTENERI` nu apar
-in acea lista. Cautare text suplimentara (`grep -rn "ID_VANZARE"` filtrat pe fisiere cu
-"incasari"/"plati"/"chitant" in nume, in tot `D:\ROA\DATABASE\SCRIPTURI_CLAR`) — **zero rezultate**.
-Coerent cu arhitectura deja cunoscuta: incasarile/platile se leaga de facturi prin **`ID_FACT`**
-(coloana pe `ACT`/`IREG_PARTENERI`, cf. `idfact_refolosire_si_documente.md`), nu prin `ID_VANZARE`
-— `ID_FACT` se pastreaza la regenerare, deci **incasarile/platile nu sunt afectate structural**.
-**Clasificare: (C), cu dovada dubla (schema + text), coerenta cu memoria de proiect „zero cazuri in
-date nu e dovada" — aici insa e absenta de FK + absenta de text, nu absenta de date, deci e o
-dovada structurala, nu doar un data point.**
-
-## Rezumat clasificari
-
-| Consumator | Clasificare | Actiune ceruta |
-|---|---|---|
-| `ATASAMENTE_VANZARI.ID_VANZARE` | **(A)** | `UPDATE ... SET id_vanzare=:nou WHERE id_vanzare=:vechi AND sters=0`, in tranzactia S9 |
-| `VANZARI_CORESP` (documentul editat ca FACT/AVIZ al altui lant) | **(A)**, prin re-emitere naturala | S9 trebuie sa citeasca `ntip`+lista sursa originala INAINTE de stergere si sa le refurnizeze la reemitere |
-| `marcheaza_facturat`/`VANZARI_CANTITATI` (sursa documentului editat) | **(C)**, conditionat | functioneaza automat DACA `ntip`/`clistaid` sunt refurnizate (acelasi mecanism ca mai sus) |
-| `VANZARI_CURSURI` | **(B)** | se rescrie automat de `scrie_in_vanzari`, nimic de facut |
-| `VANZARI_DETALII` | **(B)** | e obiectul regenerarii, acoperit de S9/S10 |
-| `DOCUMENTE`/`ID_DOC` | **(C)** | confirmat fara legatura, acoperit de `idfact_refolosire_si_documente.md` |
-| eFactura (`EsteInEFactura`, `ANAF_EFACTURA`) | **(C)** | cheie `ID_FACT`, pastrat — verificare directa a borderoului recomandata la implementare |
-| Listari/grid facturi | **(C)** | cursoare live, fara stare persistata gasita |
-| Incasari/plati | **(C)** | fara FK, fara referinta text — cheie e `ID_FACT` |
-| `REST_NOTE_PLATA` (modul restaurant) | **(A)** suspecta | needs follow-up dedicat, `PACK_RESTAURANT` necitit integral |
-| `IPS_VOYAGES_VANZARI` (modul ACN specific client) | **(A)** suspecta | needs follow-up dedicat, `PACK_ACN` necitit integral, posibil in afara perimetrului #13 |
-
-## Riscuri si ce ramane de decis de Marius
-
-1. **Editarea documentelor care sunt sursa unui lant retur/aviz e azi BLOCATA, nu doar riscanta.**
- `sterge_factura` arunca `ORA-20000` daca documentul editat are deja facturi/avize de retur emise
- pe el (§3.i). Nu e o eroare de proiectare — garda protejeaza integritatea lantului — dar
- inseamna ca „editare prin regenerare" **nu va functiona deloc** pentru aceste documente, cat timp
- utilizatorul nu sterge intai documentele-copil. **De decis**: acceptat ca limitare (cu mesaj
- clar in UI, tradus din eroarea Oracle), sau se doreste alt comportament?
-2. **Recuperarea `VANZARI_CORESP`/`marcheaza_facturat` la reemitere depinde de un pas pe care planul
- nu-l mentioneaza explicit**: citirea listei sursa originale (`ID_VANZARE_AVIZ`/`ID_VANZARE_FACT`
- din randurile `VANZARI_CORESP` ale documentului vechi) **inainte** de stergere, si refurnizarea
- ei ca `pack_facturare.clistaid`/`clistaid_avize` la reemitere. Fara acest pas, corespondenta si
- `marcheaza_facturat` **nu se scriu deloc** pentru documentul reemis (nu eroare, ci scriere lipsa
- silentioasa) — de adaugat explicit in proiectarea S9, nu presupus „vine gratis" din drumul normal.
-3. **`ATASAMENTE_VANZARI` nu e „date de utilizator pierdute"**, cf. §2 — e un audit trail de
- PDF-uri auto-generate la listare. Remigrarea (`UPDATE ... SET id_vanzare`) e simpla si ieftina,
- dar motivatia corecta pentru Marius e „pastrarea istoricului tiparit", nu „pierdere de date
- introduse manual" — poate schimba prioritatea relativa fata de alte itemi din S11/S12.
-4. **`REST_NOTE_PLATA` si `IPS_VOYAGES_VANZARI`** raman needs-investigation — descoperite prin FK,
- nu prin text, deci nu erau in raza cautarilor anterioare (nici in planul S11 original). Daca
- tipurile de document asociate (`nTipFacturaRestaurant`, `nTipFacturaACN`) nu sunt in domeniul
- „regenerabile" al #13 (de confirmat in `tipuri_documente_facturare.md`, S13), riscul dispare de
- la sine — dar asta trebuie confirmat, nu presupus.
-5. **Borderoul eFactura insusi** (nu doar `EsteInEFactura`) nu a fost citit direct — cheia `ID_FACT`
- fiind stabila, riscul e mic, dar afirmatia din *Gata cand* a S11 („documentul reemis se regaseste
- corect in borderoul eFactura") merita o verificare punctuala pe cod la implementare, nu doar
- dedusa din `EsteInEFactura`.
-
-## STARE / CE RAMANE
-
-**Cercetare incheiata pentru toate cele 7 puncte cerute de briefing**, cu dovada `fisier:linie` pe
-fiecare afirmatie portanta: inventar exhaustiv (via FK Oracle + cod), `ATASAMENTE_VANZARI` (sectiune
-proprie, cu corectia premisei „date de utilizator"), `marcheaza_facturat`/`VANZARI.FACTURAT`/
-`VANZARI_CANTITATI`, `DOCUMENTE`/`ID_DOC` (confirmat, fara redeschidere), borderou eFactura si
-listari, riscuri finale.
-
-**Constatare centrala**: mecanismul S9 planificat (regenerare cu `ID_VANZARE` nou, pe drumul normal
-de emitere) e **diferit** de mecanismul #6 deja livrat (`actualizeaza_vanzari`, reutilizeaza acelasi
-`ID_VANZARE`, doar `COD` se schimba) — deci nicio protectie construita pentru #6 nu se mosteneste
-automat de S9. Singurul consumator care chiar are nevoie de un `UPDATE` explicit nou este
-`ATASAMENTE_VANZARI` (clasificare A simpla). `VANZARI_CORESP`/`marcheaza_facturat` se pot rezolva
-**fara cod PL/SQL nou**, refolosind mecanismul existent (`finalizeaza_factura`'s `CASE` pe `ntip`),
-**daca** S9 e proiectat sa citeasca si sa refurnizeze parametrii sursei originale — asta e o cerinta
-de design care trebuie scrisa explicit in S9, nu deductibila implicit.
-
-**Neverificat, ramas pentru follow-up** (declarat, nu ascuns): corpul complet al `PACK_RESTAURANT`/
-`PACK_ACN` (pentru `REST_NOTE_PLATA`/`IPS_VOYAGES_VANZARI`), borderoul eFactura citit direct (nu doar
-`EsteInEFactura`), o cautare exhaustiva de „id_vanzare retinut pe termen lung" in tot codul VFP
-(favorite/shortcut-uri), si confirmarea in `tipuri_documente_facturare.md` a caror tipuri intra
-efectiv in perimetrul „regenerabile" al #13 (ar elimina sau confirma riscurile 1 si 4).
-
-Zero modificari de cod, zero write-back, zero `git_sync.ps1`/`txt2vcx.ps1`, zero commit. Pe Oracle
-doar `SELECT` (schema `MARIUSM_AUTO`, interogari pe `ALL_TAB_COLUMNS`/`ALL_CONSTRAINTS`/`ALL_VIEWS`/
-`ALL_SOURCE`, plus `SELECT` de numarare pe date de test — niciuna cu efect de scriere).
diff --git a/docs/cercetare/s2_factureaza_unificare.md b/docs/cercetare/s2_factureaza_unificare.md
deleted file mode 100644
index 67c7099..0000000
--- a/docs/cercetare/s2_factureaza_unificare.md
+++ /dev/null
@@ -1,318 +0,0 @@
-# S2 — Proiectare: o singura procedura `factureaza`
-
-Cercetare read-only pentru povestea **S2** din `docs\plan_13_unificare_formular_facturare.md`.
-Niciun fisier de cod atins, `git_sync.ps1` nerulat, niciun write-back, niciun commit.
-
-## Verdict
-
-**Se poate unifica, si e mai simplu decat pare.** `factureaza2` nu e o a doua implementare
-funcţională care trebuie fuzionata cu grija — e un fork din 08.06.2017 la care s-a **dezactivat
-execuţia interogarii de articole** (`lnSucces = 1` hardcodat, `goExecutor.oExecute` niciodata
-apelat) si mai multe blocuri intregi sunt inchise cu `If .F.`. Are **exact un singur apelant** in
-tot codul (`ofacturare.prg:90`, din interiorul lui `factureaza` insusi, in spatele unui
-`AMESSAGEBOX` de confirmare) si **zero utilizatori reali** dincolo de acel switch de test. Riscul de
-regresie e mic pentru ca nu exista nimic funcţional de pierdut in `factureaza2` — obstacolul
-principal nu e tehnic, e ca formularul spre care duce (`frm_facturare_articole2`) e tot un prototip
-neterminat (`Init` de 92 de linii, nu completeaza antetul), deci unificarea proceduri lor **nu**
-face formularul nou utilizabil — doar elimina duplicarea de cod. Asta ramane treaba lui S3.
-
----
-
-## 1. Inventarul celor doua proceduri
-
-Ambele sunt proceduri globale (nu metode de clasa) in **`COMUN\programe\ofacturare.prg`**, incarcat
-via `SET PROCEDURE ... ADDITIVE` din `Programe\roafacturare.prg`. Nu exista omonime — verificat cu
-`Get-ChildItem -Recurse *.prg | Select-String '^\s*(PROCEDURE|FUNCTION)\s+factureaza2?\b'` pe tot
-`ROAFACTURARE` si cu Grep pe `.vc2` din `COMUN`: un singur rezultat pentru fiecare nume.
-
-| | `factureaza` | `factureaza2` |
-|---|---|---|
-| Locatie | `COMUN\programe\ofacturare.prg:81-577` (497 linii) | `COMUN\programe\ofacturare.prg:583-1081` (499 linii) |
-| Parametri | `LPARAMETERS tnTip, toFactura` (`:82`) — `toFactura` = obiect, pentru copiere/modificare | `LPARAMETERS tnTip` (`:584`) — **fara** al doilea parametru |
-| Apelanti | ~20+ puncte de intrare reale (sectiunea 3) | **unul singur**: `ofacturare.prg:90`, din `factureaza` |
-
-`ofacturare.prg` in sine e cod comun al **intregii suite**: exista o copie identica-la-origine in
-`COMUN\programe\ofacturare.prg` a fiecarui produs ROA verificat (ROACONT, ROAGEST, ROACONTRACTE,
-ROAAUTO, ROAACNPRO, ROAIMOB, plus alte ~30 produse) — fiecare cu propriile `factureaza`/`factureaza2`
-la linii apropiate (de regula `:76-77` sau `:87-88` pentru comutatorul `gnFacturareNou`, dupa
-versiune). Nu exista in `COMUNROA` (biblioteca partajata separata) — e sincronizat manual intre
-produse ca fisier COMUN, nu ca livrabil COMUNROA.
-
-## 2. Diff-ul semantic
-
-Comparatie linie-cu-linie, cu citate `ofacturare.prg:linie`. **Sase din cele noua diferente listate
-in sectiunea A a planului se confirma exact; una e imprecisa; una lipseste din plan.**
-
-### Ce face `factureaza` si nu face `factureaza2`
-
-| Ce | `factureaza` | `factureaza2` |
-|---|---|---|
-| Tipurile 51 (ROAACNPRO), 52 (contract factura fiscala valuta) rutate la FACTURA | `Inlist(tnTip,45,48,49,**51,52**)` la `:192` si `:222` | `Inlist(tnTip,45,48,49)` la `:674` si `:700` — **51/52 lipsesc**, ar cadea in `Otherwise` -> AVIZ |
-| Ramura `llCopiere`/`toFactura` (copiere/modificare factura) | declarata `:102`, populata `:111`, folosita la completarea datelor (`:200-206`), la construirea interogarii (`Case m.llCopiere` -> `cursor_retur_document`, `:267-268`), si la adaugarea articolelor din lista de preturi peste cele copiate (`:454-474`) | **absenta complet** — nicio declarare a `llCopiere`, niciun tratament al lui `toFactura` |
-| Deschiderea `frm_date_factura`/`frm_date_aviz` | activa, cu `toFactura` transmis constructorului (`:229-235`) | inchisa cu `If .F.` (`:707-711`) |
-| Filtrul `RORTC` pe `jtva_coloane` | `AND !'RORTC'$UPPER(coloana_jv)` la ambele ramuri (`:243`, `:245`) | absent (`:715`, `:717`) |
-| Executia interogarii de articole | `lnSucces = goExecutor.oExecute(lcSqlCursor, lcCursor)` (`:311`) | **inchisa cu `If .F.`** (`:823-826`); imediat dupa, `lnSucces = 1` hardcodat (`:827`) — cursorul SQL construit la `:748-822` nu ruleaza niciodata |
-| Verificarea "nu exista articole" | activa (`:324-328`) | **inchisa cu `If .F.`** (`:838`) — combinata cu `lnSucces=1` de mai sus, ramura merge mereu pe calea "am articole", indiferent de continut |
-| Zeroizarea `gestionabil` pe proforma | `IF poDate.eProforma = 1 ... UPDATE (lcCursor) SET gestionabil = 0` (`:333-336`) | **absenta** — `eProforma` nu apare nicaieri in `factureaza2` (verificat cu grep pe tot fisierul) |
-| `crspolitici` / `crscontracte` (populare combo-uri) | necondiţionate (`:420-440`) | **ambele inchise cu `If .F.`** (`:956-968`, `:969-980`) |
-| `GetInstitutiePublica` | `poDate.institutie_publica = GetInstitutiePublica(...)` (`:509`) | **absenta** |
-| `codnc8`/`codcpv` pe fiecare linie | `Replace codnc8 WITH ..., codcpv WITH ...` in `Scan` (`:516-517`), pe langa `codmatc` | **doar `codmatc`** (`:1027`) — `codnc8`/`codcpv` lipsesc |
-| `GetSoldClient` + `poDate.sold_lei`/`sold_valuta` inainte de listare | prezent, in ramura non-bon-fiscal (`:530-533`) | **absent** — ramura echivalenta (`:1040-1041`) sare direct la `listeaza_ofacturare()` |
-| Formularul de articole | `frm_facturare_articole` (`:395`) | `frm_facturare_articole2` (`:929`) — **singura diferenta functionala reala** care justifica existenta lui `factureaza2` |
-
-### Corectii fata de sectiunea A a planului
-
-- **"`verifica_numar(16, ...)` pentru chitanta" — planul GRESESTE.** E prezent **identic** in ambele:
- `factureaza:502-504` si `factureaza2:1018-1020` (`If poDate.incasat <> 0 ...
- poGeneratorNumere.verifica_numar(16, poDate.nr_incasare) Endif`). Nu lipseste din `factureaza2`.
-- **"`cursor_avize` cu tip 23" — planul e imprecis.** Nu exista nicio asociere `cursor_avize`/tip 23
- in niciuna din cele doua proceduri (`cursor_avize` trateaza doar `tnTip = 4`, identic in ambele,
- `:294-295` / `:774-775`). Ce difera real pentru tipul 23: in `factureaza`, tipul 23 e prins in
- `Case Inlist(tnTip,1,22,5,29,7,10,**23**)` -> `cursor_preturi` (`:279-282`); in `factureaza2`, 23
- **nu** e in acea lista (`:758`, doar `1,22,5,29,7,10`) si cade in schimb in
- `Case Inlist(tnTip,**23**,41)` -> `cursor_gestiune` (`:776-778`). E o rutare complet diferita
- pentru acelasi tip de document, nu o simpla lipsa — **de adaugat explicit la lista din sectiunea A**.
-- **Nementionat in plan — tipul 52 lipseste si din `Do Case` de contract**: `factureaza`
- `Case Inlist(tnTip,2,26,6,**52**)` (`:283`) vs `factureaza2` `Case Inlist(tnTip,2,26,6)` (`:762`) —
- aceeasi lipsa a tipului 52 ca la nIdTipDoc, dar intr-un loc separat din cod; **tipul 24** (aviz de
- retur) lipseste similar din `Case Inlist(tnTip,8,9,**24**)` (`:306`) vs `Case Inlist(tnTip,8,9)`
- (`:819`).
-
-### Ce fac amandoua identic (verificat, nu presupus)
-
-Structura comentariilor `lnIdSet`/`pnTipFacturare`, bucla `Do While lnRaspuns = 6`, apelul
-`actualizeaza_optiuni_program()`, crearea `poDate`/`poGeneratorNumere`, alegerea `frm_date_factura` /
-`frm_date_aviz_lucrare` / `frm_date_aviz` pentru antet (desi in `factureaza2` deschiderea propriu-zisa
-e dezactivata), tratarea `tnTip=30` (aviz din NIR, inclusiv bucla `Scatter`/`Insert Into crsfactura`
-identica caracter-cu-caracter), `verifica_numar(16,...)`, dezalocarea celor trei numere
-(`nIdTipDoc`, 16, 3/26) la abandon, si intreaga bucla finala de `AMESSAGEBOX`
-"Doriti sa continuati" + `CloneObj`/`poDate.Reset()`.
-
-### Ce face `factureaza2` si nu face `factureaza`
-
-Un singur lucru: verificari defensive suplimentare de tip la iesirea timpurie (`pnButon = 2`):
-```
-IF TYPE('poDate.nr_incasare') = 'N'
- poDate.nr_incasare = 0
-ENDIF
-IF TYPE('poDate.incasat') = 'N'
- poDate.incasat = 0
-ENDIF
-```
-(`factureaza2:727-732`) — `factureaza` face resetarea echivalenta necondiţionat, dar mai tarziu, in
-ramura de succes (`:546-547`), nu pe calea de abandon. Diferenta e cosmetica, nu comportamentala pe
-fluxul normal.
-
-## 3. Toti apelantii
-
-**Cautare in tot arborele `D:\ROA`** (fiecare produs + `COMUN`-ul lui + `COMUNROA`), cu capcana
-"Grep nu vede COMUN" tratata explicit (path dat direct pe fiecare `COMUN`, nu doar pe radacina
-produsului — altfel cautarea sare tacut peste el, per gitignore-ul fiecarui produs).
-
-**Niciun produs verificat (ROACONT, ROAGEST, ROAAUTO, ROAACNPRO, ROAIMOB) nu apeleaza `factureaza`
-direct din cod propriu — nici in `COMUN`, nici in partea specifica produsului.** Singura urma in
-`COMUN`-urile lor e propria copie a `ofacturare.prg`/`oproceduri_facturare.prg` (definitia, nu un
-apel). Confirma independent observatia din `coresp_cont_venchelt.md` ca ROAACNPRO nu trece prin acest
-flux (foloseste `pack_acn.salveaza_regdoc`, nu `contabilizeaza_articol`). **Exceptia: ROACONTRACTE**,
-care are un apel real, specific produsului, la wrapper-ul `facturare_contracte`.
-
-### Apelanti directi ai `factureaza(N)`
-
-| Apelant | Produs | Parametri | Tip document |
-|---|---|---|---|
-| `Meniuri\politica.mn2:12` | ROAFACTURARE | `factureaza(1)` | lista de preturi, lei |
-| `Meniuri\politica.mn2:15` | ROAFACTURARE | `factureaza(8)` | retur factura lei |
-| `Meniuri\politica.mn2:18` | ROAFACTURARE | `factureaza(45)` | restaurant |
-| `Meniuri\politica.mn2:26` | ROAFACTURARE | `factureaza(49)` | marfa custodie fara descarcare K |
-| `Meniuri\politica.mn2:29` | ROAFACTURARE | `factureaza(48)` | marfa custodie cu descarcare K |
-| `Meniuri\politica.mn2:37` | ROAFACTURARE | `factureaza(5)` | lista de preturi, valuta (invoice) |
-| `Meniuri\politica.mn2:40` | ROAFACTURARE | `factureaza(7)` | credit note |
-| `Meniuri\politica.mn2:43` | ROAFACTURARE | `factureaza(10)` | factura fiscala valuta |
-| `Meniuri\politica.mn2:46` | ROAFACTURARE | `factureaza(9)` | retur factura valuta |
-| `Meniuri\contracte.mn2:12` | ROAFACTURARE | `factureaza(2)` | contract, lei |
-| `Meniuri\contracte.mn2:15` | ROAFACTURARE | `factureaza(6)` | contract, valuta |
-| `Meniuri\contracte.mn2:18` | ROAFACTURARE | `factureaza(52)` | contract, factura fiscala valuta |
-
-### Apelanti prin `COMUN\programe\oproceduri_facturare.prg` (dispecer comun, un wrapper per grup de tipuri)
-
-| Wrapper (`oproceduri_facturare.prg`) | -> `factureaza(N)` | Apelat din |
-|---|---|---|
-| `facturare_contracte(tcTip)` (`:119-136`) | `factureaza(2)`/`factureaza(6)`/`factureaza(52)` dupa `tcTip` | `ROAFACTURARE\Clase\ofundal_facturare.vc2:890-894`, `ROAFACTURARE\Ferestre\fundal.sc2:924`, **`ROACONTRACTE\Clase\ferestre_contracte.vc2:1542-1546`** (produs diferit, apel real) |
-| `facturare_comenzi()` (`:139-141`) | `factureaza(3)` | `COMUN\clase\ocomenzi.vc2:1580-1596`, metoda `do_factura` — `SCATTER NAME goComanda MEMO` inainte de apel |
-| `facturare_avize()` (`:144-146`) | `factureaza(4)` | `ROAFACTURARE\Clase\ofundal_facturare.vc2:905`, `ROAFACTURARE\Ferestre\fundal.sc2:932` |
-| `copiere_factura(toFactura)` (`:150-153`) | `factureaza(toFactura.Tip, toFactura)` | `COMUN\clase\ofacturare_comun.vc2:3710` — fisierul de perimetrul #6, doar citit, neatins |
-| `facturare_lista_de_preturi()` (`:114-116`) | `Do politica.mpr` -> popup-ul din `politica.mn2` (vezi tabelul de mai sus) | `ROAFACTURARE\Clase\ofundal_facturare.vc2:883`, `ROAFACTURARE\Ferestre\fundal.sc2:920` |
-| `emitere_aviz_clienti(tnTip)` (`:198-228`) | `factureaza(21/22/26/24)` dupa `tnTip=1/2/3/7`; `tnTip=4,5,6` -> `initializeaza_vanzare_din_stoc`, nu `factureaza` | `ROAFACTURARE\Meniuri\aviz_clienti.mn2:21,47,51,55,59,63,67` |
-| `emitere_aviz_clienti_debitori(tnTip)` (`:230-243`) | `factureaza(28/29)` dupa `tnTip=1/2` | `ROAFACTURARE\Meniuri\aviz_clienti_debitori.mn2:22,26` |
-| `emitere_aviz_clienti_custodie(tnTip)` (`:244-259`) | `factureaza(42/47)` dupa `tnTip=1/2`; `tnTip=3` -> `initializeaza_vanzare_din_stoc` | `ROAFACTURARE\Meniuri\aviz_clienti_custodie.mn2:30,34,38` |
-| `emitere_aviz_transfer(tnTip)` (`:261-280`) | `factureaza(25/23/27/30/41)` dupa `tnTip=1..5` | `ROAFACTURARE\Meniuri\aviz_subunitati.mn2:36,40,44,48,52` |
-
-**Total: ~33 puncte de intrare reale in cod pentru `factureaza`, doar unul pentru `factureaza2`**
-(`ofacturare.prg:90`, in interiorul lui `factureaza`, gatit de `gnFacturareNou=1` + confirmare DA la
-`AMESSAGEBOX`).
-
-## 4. Rolul lui `gnFacturareNou`
-
-**Nu e un comutator de productie — e un switch de dezvoltator, fara nicio persistenta.**
-
-- **Declarat:** nicaieri. Cautare exhaustiva (`gnFacturareNou`, tot `D:\ROA`, extensii
- `.prg/.vc2/.sc2/.mn2`) — singura aparitie e exact linia care il citeste (`ofacturare.prg:88`, sau
- liniile echivalente in fiecare copie de produs). Nu exista intr-un ecran de optiuni, nu e coloana
- intr-un tabel de configurare (spre deosebire de `gnScadereStoc`, `gl406` etc., citite din
- `oinit_optiuni.prg`).
-- **Citit:** o singura data, `ofacturare.prg:88` — `If Type('gnFacturareNou') = 'N' And
- m.gnFacturareNou = 1`.
-- **Valoare implicita:** inexistenta ca variabila -> `Type()` intoarce `'U'` (Undefined), deci
- conditia e falsa implicit. Devine `.T.` doar daca cineva a facut manual, in sesiunea VFP curenta
- (de regula din fereastra de comenzi a IDE-ului), `gnFacturareNou = 1`.
-- **Cine il seteaza:** nimeni, in cod. E gandit sa fie setat manual de un dezvoltator care vrea sa
- testeze prototipul.
-- **Confirma sau infirma ca e comutator intre proceduri, nu intre formulare?** Azi, chiar intre
- **proceduri** — `factureaza:88-93` face `Return factureaza2(m.tnTip)` dupa raspunsul DA la dialog,
- adica sare complet in cealalta procedura, cu tot ce lipseste din ea (sectiunea 2). Planul (S2,
- linia 1423) vrea sa-l transforme in comutator **intre formulare**, in interiorul unei singure
- proceduri — schimbare corecta, pentru ca azi dubleaza cod, nu doar UI.
-
-## 5. Proiectarea unificarii
-
-### Semnatura
-
-**Neschimbata la aceasta poveste:** `factureaza(tnTip, toFactura)`. Parametrul de sursa explicit
-(comanda/contract) e treaba lui **S3c**, care depinde de S2 si il trateaza separat — nu se amesteca
-aici (planul insusi spune "Atinge cod comun intregii suite — nu se face impreuna cu alta
-modificare").
-
-### Ramificarea interna
-
-Nu e nevoie de o rescriere — `factureaza` de azi e deja versiunea completa si functionala. Interventia
-e chirurgicala:
-
-1. **Muta verificarea `gnFacturareNou`** de la inceputul procedurii (azi `:88-93`, unde face
- `Return factureaza2(...)`) la **punctul unde se alege `lcObject`** pentru formularul de articole
- (azi `:395` in `factureaza`, ramura corespunzatoare celei din `factureaza2:929`):
- ```
- Case tnTip = 27
- lcObject = [frm_avizare_lucrare]
- Otherwise
- lcObject = IIF(m.llFacturareNoua, [frm_facturare_articole2], [frm_facturare_articole])
- Endcase
- ```
- unde `llFacturareNoua` e calculat **o singura data**, la fel ca azi (`Type('gnFacturareNou')='N'
- And gnFacturareNou=1`, urmat de acelasi `AMESSAGEBOX` DA/NU), dar **fara** `Return` in alta
- procedura — doar seteaza flagul si continua executia normala.
-2. **Tot restul ramane identic** — cursorul de articole, `eProforma`, `codmatc`/`codnc8`/`codcpv`,
- `GetInstitutiePublica`, `GetSoldClient`, filtrul `RORTC`, rutarea tipurilor 51/52/23/24, ramura
- `llCopiere`/`toFactura` — pentru ca acestea nu au nicio legatura cu care formular de articole se
- deschide. `factureaza2` nu avea o varianta "corecta, dar diferita" a acestor blocuri — pur si
- simplu nu le avea, pentru ca fusesera dezactivate in graba la prototipare (`If .F.` peste tot),
- nu pentru ca noul formular ar avea nevoie de alt comportament acolo.
-3. **Sterge `factureaza2`** in intregime (`:583-1082`, inclusiv bannerul `INCEPUT`/`SFARSIT`).
-
-### Ordinea, ca suita sa nu fie stricata niciun moment
-
-Riscul de "moment in care suita e stricata" e mic aici, spre deosebire de S3c — pentru ca
-`factureaza2` **nu are alt apelant decat el insusi prin `factureaza`**. Ordinea propusa:
-
-1. Muta logica de selectie a lui `lcObject` (pasul 1 de mai sus) **inainte** de a sterge
- `factureaza2` — la acest punct, codul are temporar ambele cai active (comutatorul nou +
- `factureaza2` inca existent, dar orfan). Se poate testa manual ca `gnFacturareNou=1` deschide
- `frm_facturare_articole2` din interiorul lui `factureaza`, cu restul comportamentului corect
- (spre deosebire de azi, unde deschiderea prin `factureaza2` sare peste `eProforma`, `codnc8` etc.)
-2. Abia dupa verificare, **sterge `factureaza2`** — pasul e sigur pentru ca nu mai are niciun apelant
- (linia 90, singurul, a fost deja inlocuita la pasul 1).
-3. **Un singur fisier se schimba**: `COMUN\programe\ofacturare.prg`. Niciun apelant din tabelul de
- la punctul 3 nu are nevoie de nicio modificare — toti cheama `factureaza(N)` cu aceeasi semnatura,
- niciunul nu cheama `factureaza2` direct.
-4. **ROACONTRACTE nu necesita nicio schimbare** la aceasta poveste — apelul lui la
- `facturare_contracte` -> `factureaza(2/6/52)` nu atinge `factureaza2` deloc.
-
-## 6. Riscurile de regresie
-
-- **Cel mai probabil sa se rupa:** ramura `llCopiere`/`toFactura`, pentru ca e cea mai complexa
- bucata de logica prezenta doar in `factureaza` (`cursor_retur_document`, apoi suprapunerea cu
- `cursor_preturi` pentru a permite adaugarea de articole noi peste cele copiate, `:454-474`). Nu
- are nicio acoperire azi in `factureaza2` de comparat — deci orice greseala de copy-paste la mutarea
- liniei `lcObject` risca sa rupa exact aceasta ramura, nu partea "noua". **Testat manual din
- `copiere_factura` (`ofacturare_comun.vc2:3710`) inainte si dupa.**
-- **Al doilea cel mai probabil:** rutarea tipurilor 23/24/51/52, pentru ca azi cad in `Do Case`-uri
- diferite intre cele doua proceduri (sectiunea 2) — o gresala de aliniere la stergerea lui
- `factureaza2` nu ar afecta functional (pentru ca acele Do Case-uri raman neatinse, doar duplicate
- disparute), dar merita o trecere vizuala pe fiecare tip listat la punctul 3 dupa modificare.
-- **ROACONTRACTE** — singurul apelant real din alt produs. **Nu poate fi testat din arborele de lucru
- ROAFACTURARE** — cere un build/rulare separata a ROACONTRACTE, cu propriul `ofacturare.prg`
- sincronizat manual (nu e acelasi fisier fizic, e o copie). Verificarea "gata" trebuie sa includa
- explicit macar un test manual pe ROACONTRACTE, tip contract-factura, nu doar pe ROAFACTURARE.
-- **`frm_facturare_articole2` insusi ramane netestabil functional** la aceasta poveste — `Init`-ul
- lui nu completeaza antetul (S1), deci deschiderea cu `gnFacturareNou=1` va arata un formular cu
- campuri goale la fel ca azi. Nu e o regresie introdusa de S2, dar e o asteptare de gestionat: S2
- **nu** face `frm_facturare_articole2` utilizabil, doar elimina procedura duplicata din spatele lui.
-- **Nimic din asta e testabil headless** — toate cele ~33 puncte de intrare sunt declansate din
- meniuri/formulare UI (`ON SELECTION BAR`, `DO ... IN ...` din metode de clic), iar rezultatul se
- verifica prin `ACT`/`VANZARI`/`RUL` in Oracle sau vizual pe formular. Testarea de dupa modificare
- trebuie sa fie manuala, minim pe: o factura lista de preturi lei (tip 1), un aviz din comanda (tip
- 21), o factura din contract lei (tip 2, din `ROACONTRACTE` daca fezabil), o copiere de factura
- (`toFactura` populat), si — cu `gnFacturareNou=1` setat manual — confirmarea ca
- `frm_facturare_articole2` se deschide fara eroare (nu neaparat ca arata corect, asta e S3).
-
-## 7. Criteriul de "gata", rescris si verificabil
-
-Planul spune azi: *"`factureaza2` nu mai exista, iar comutatorul alege formularul, nu procedura."*
-Rescris, verificabil fara ambiguitate:
-
-1. **Structural** (verificabil cu o comanda, fara sa citesti codul):
- ```
- Get-ChildItem -Recurse 'D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare.prg' |
- Select-String -Pattern '^\s*(PROCEDURE|FUNCTION)\s+factureaza2\b'
- ```
- trebuie sa intoarca **zero rezultate**.
- ```
- Select-String -Path 'D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare.prg' -Pattern 'gnFacturareNou'
- ```
- trebuie sa intoarca **exact o aparitie**, situata in interiorul lui `factureaza`, la punctul unde
- se alege `lcObject` (nu inainte de constructia lui `poDate`, ca azi).
-2. **Comportamental**, testat manual, fara `gnFacturareNou` setat (calea implicita, majoritatea
- utilizatorilor): cele patru documente listate la sectiunea 6 (factura lista de preturi, aviz din
- comanda, factura din contract, copiere factura) produc aceleasi randuri in `ACT`/`VANZARI`/`RUL`
- ca inainte de modificare.
-3. **Comportamental**, cu `gnFacturareNou = 1` setat manual si DA la dialog: se deschide
- `frm_facturare_articole2` (nu `frm_facturare_articole`), fara eroare la deschidere, cu
- `eProforma`/`codnc8`/`codcpv`/`GetInstitutiePublica`/`GetSoldClient`/filtrul RORTC/rutarea
- 51-52-23-24 toate active identic cu calea implicita (spre deosebire de azi, cand
- `gnFacturareNou=1` le sarea pe toate).
-4. **ROACONTRACTE**: minim un test manual de facturare din contract, dupa sincronizarea
- `ofacturare.prg` in acel produs, confirma acelasi rezultat ca inainte.
-
-## Ce nu s-a putut stabili si de ce
-
-- **Cine activeaza popup-urile `politica.mn2`/`contracte.mn2`** (nivelul chiar deasupra apelurilor
- directe la `factureaza(N)`) nu a fost trasat pana la butonul/grid-ul exact — nu era necesar pentru
- diff-ul procedurilor sau pentru tabelul de apelanti (punctul de interes e apelul la `factureaza`,
- nu inca un nivel de indirectare deasupra), dar daca implementarea muta si aceste meniuri, merita
- o trecere separata.
-- **Daca alte produse (ROAGEST, ROAAUTO, ROAACNPRO, ROAIMOB, ROACONT) au propriul lor
- `oproceduri_facturare.prg`/`ocomenzi.vc2` invocat din cod specific produsului, dincolo de ce am
- cautat** — cautarea a acoperit exact numele `factureaza`/`factureaza2` si cei noua wrapperi din
- `oproceduri_facturare.prg`; nu a acoperit eventuale cai complet diferite catre acelasi fisier
- (de exemplu un meniu `.mn2` specific unui alt produs care ar chema un wrapper cu alt nume). Pentru
- aceste cinci produse, cautarea directa (`factureaza(`, cei noua wrapperi) a dat zero rezultate in
- codul specific produsului — suficient pentru concluzia "nu apeleaza azi", dar nu e o dovada
- negativa absoluta de "nu ar putea apela niciodata prin alt canal".
-- **Testarea reala pe ROACONTRACTE** nu a fost efectuata (read-only, fara rulare de cod) — doar
- confirmata existenta apelului in sursa (`ferestre_contracte.vc2:1542-1546`).
-- **Diferenta minora de text** intre mesajele "Luna inchisa" ale celor doua proceduri
- (`factureaza:105` vs `factureaza2:594`, un caracter diacritic afisat diferit la citire) nu a fost
- investigata mai departe — pare artefact de encoding la citire (cp1250 in fisier), nu o diferenta
- de continut intentionata; oricum dispare odata cu stergerea lui `factureaza2`.
-
-## Bug-uri semnalate, nereparate
-
-- **`factureaza2` e, in forma actuala, non-functional dincolo de deschiderea formularului de
- antet dezactivata** — chiar daca cineva ar apela azi acest cod pe o cale ipotetica ocolind
- `factureaza`, executia interogarii SQL e dezactivata (`lnSucces = 1` hardcodat la `:827`, fara
- `goExecutor.oExecute`) si verificarea "nu exista articole" e dezactivata (`:838`) — codul ar merge
- mereu pe ramura de succes cu un cursor `crsarticole` nepopulat de aceasta rulare (posibil ramas
- dintr-un apel anterior, cu alt `tnTip`). Nu se repara aici — S2 il sterge oricum, deci bug-ul
- dispare odata cu procedura, nu prin fix separat.
-- Niciun bug nou gasit in `COMUN\clase\ofacturare_comun.vc2` sau `COMUN\programe\ofacturare_editare.prg`
- (perimetrul #6) — singura atingere a acestor fisiere in aceasta cercetare a fost citirea liniei
- `copiere_factura` din `ofacturare_comun.vc2:3710`, care nu are nimic suspect.
diff --git a/docs/cercetare/s3_portare_antet.md b/docs/cercetare/s3_portare_antet.md
deleted file mode 100644
index 4c5560a..0000000
--- a/docs/cercetare/s3_portare_antet.md
+++ /dev/null
@@ -1,478 +0,0 @@
-# Cercetare — proiectare S3: portarea logicii de antet in formularul unificat
-
-Investigatie READ-ONLY pentru povestea **S3** din `docs\plan_13_unificare_formular_facturare.md:1428-1439`.
-Fara editari de cod, fara `git_sync.ps1`/`txt2vcx.ps1`, fara commit. Constrangerile din briefing —
-`COMUN\clase\ofacturare_comun.vc2` si `COMUN\programe\ofacturare_editare.prg` doar citite (perimetrul
-#6), `pack_facturare` si `pack_facturare_comun`-ul intern neatinse, analiticele read-only — respectate.
-
-## Verdict (5-10 randuri)
-
-S3 e **mai mare decat inventarul din plan sugereaza pe numar de metode** (29 `do_cauta_*` reale, nu
-30 — vezi punctul 1), dar **mult mai mare decat sugereaza pe complexitate reala**, pentru doua motive
-descoperite aici, nu presupuse: (a) `Init`, `inainte_de_do_termin` si — partial — `do_cauta_fdoc` sunt
-**omonime cu semantica total diferita pe toate cele patru formulare-sursa** (antet vs. articole vs.
-alte-date), deci portarea "o singura data" cere de fapt patru fuziuni de metoda, nu una singura cu
-ramificare; (b) bug-ul **#16 e real, reprodus pe cod pana la linia exacta**, si **nu e un bug de focus**
-— e o consecinta a faptului ca bucla de reincercare din `factureaza`/`factureaza2`
-(`ofacturare.prg:174-571`) trateaza **orice esec SQL** (nu doar cursul lipsa) ca pe un "DA, continui cu
-alt document", redeschizand din senin formularul de antet de la zero. Unificarea **nu-l reproduce
-automat** — poate chiar sa-l elimine ca efect secundar, daca antetul nu se mai reconstruieste de la
-Init dupa un esec Oracle in pasul urmator. Obstacolul principal pentru implementare nu e portarea
-codului de validare (majoritatea e `Do Case`/`amessagebox` mecanic), ci **reconcilierea a patru cicluri
-de viata `Init`/`inainte_de_do_termin` independente intr-unul singur**, cu ordinea de dependente de la
-punctul 5.
-
----
-
-## 1. Inventarul metodelor de portat — numere corectate
-
-Sursa: `vfp_symbols.ps1 -Class frm_date_factura` / `-Class frm_date_aviz`, confirmat pe fisierul real
-`COMUN\clase\ofacturare.vc2` (nu `.bak`).
-
-**`frm_date_factura`** (`ofacturare.vc2:8482-9869`) — **16** metode `do_cauta_*`, nu 17:
-
-| Metoda | Linii | Ce face | Echivalent in `frm_facturare_articole2` |
-|---|---|---|---|
-| `do_cauta_altele` | `8940-8961` (21) | cautare pe campul cu eticheta dinamica ("Altele"/contract/comanda/etc.) | nu |
-| `do_cauta_avize` | `8963-8999` (36) | cautare aviz-sursa (tip=4) | nu |
-| `do_cauta_client` | `9001-9060` (59) | cautare client, populeaza sold/cod fiscal | nu |
-| `do_cauta_comanda` | `9062-9090` (28) | cautare comanda-sursa | nu |
-| `do_cauta_contract` | `9092-9153` (61) | cautare contract-sursa | nu |
-| `do_cauta_factura` | `9155-9171` (16) | cautare factura-sursa (credit note, tip 7) | nu |
-| `do_cauta_facturi` | `9173-9212` (39) | cautare multi-factura (retur, tip 8/9) | nu |
-| `do_cauta_fdoc` | `9214-9225` (11) | cautare generica fel-document, `caut_fdoc()` — **identica byte-cu-byte cu varianta din `frm_date_aviz`**, vezi punctul 4 | nu |
-| `do_cauta_gestiune_init` | `9227-9242` (15) | cautare gestiune sursa | nu |
-| `do_cauta_locatii` | `9244-9253` (9) | cautare locatie (tip 45) | nu |
-| `do_cauta_lucrare` | `9255-9279` (24) | cautare lucrare | nu |
-| `do_cauta_responsabil` | `9281-9301` (20) | cautare responsabil | nu |
-| `do_cauta_sectie` | `9303-9342` (39) | cautare sectie | nu |
-| `do_cauta_valuta` | `9344-9359` (15) | cautare valuta, muta focus pe `clb_zi_curs` daca exista, altfel pe serie (`:9351-9356`, deja conditionat `Type(...)<>'U'`) | nu |
-| `do_cauta_venchelt` | `9361-9391` (30) | cautare venit/cheltuiala | nu |
-| `do_cauta_venit` | `9393-9394` (1) | stub/alias, o linie — de verificat ce mai apeleaza | nu |
-| `do_schimba_tipdoc` | `9396-9438` (42) | vezi punctul 6 — schimba `poDate.nIdTipDoc` si reinitializeaza serie+numar | **nu** — apelat orfan din prototip, vezi punctul 3 |
-| `do_verifica` | `9440-9453` (13) | verificare ANAF pe cod fiscal client | nu (dar exista pe `frm_facturi`, aceeasi semantica) |
-| `inainte_de_do_termin` | `9455-9561` (106) | validare completa antet inainte de trecerea la articole | **omonim cu semantica diferita** pe toate 4 formulare, vezi mai jos |
-| `Init` | `9563-9796` (234) | vezi punctul 5 | **omonim cu semantica diferita**, vezi mai jos |
-| `Clb_dataact...LostFocus` | `9798-9813` (15) | sincronizeaza `zi_curs=dataact` daca `clb_zi_curs` exista | nu |
-| `Clb_dataireg...LostFocus` | `9815-9831` (16) | idem, pe `dataireg` | nu |
-| `Clb_nract...LostFocus` | `9833-9835` (2) | — | nu |
-| `Clb_serie_act...LostFocus` | `9837-9844` (7) | — | nu |
-| `Ct_clb_fdoc._combobox1.Init` | `9846-9855` (9) | populeaza combo-ul FACTURA/PROFORMA/BON FISCAL | nu |
-| `Ct_clb_fdoc._combobox1.LostFocus` | `9857-9859` (2) | `thisform.do_schimba_tipdoc()` — vezi punctul 6 | nu (frm_facturare_articole2 are un apel similar, dar **orfan**, vezi punctul 3) |
-| `Ed_tx_simplu1._EDBASE1.KeyPress` | `9861-9867` (6) | — | nu |
-
-**`frm_date_aviz`** (`ofacturare.vc2:6566-7618`) — **13** metode `do_cauta_*`, numarul din plan e corect:
-
-| Metoda | Linii | Observatie |
-|---|---|---|
-| `do_cauta_altele` | `6882-6894` (12) | mai scurta decat pe factura (21) — set de tipuri mai mic |
-| `do_cauta_avize` | `6896-6930` (34) | apropiata ca marime de factura (36) |
-| `do_cauta_client` | `6932-7009` (77) | **mai lunga** decat pe factura (59) — trateaza eticheta variabila "Retur de la"/"Gestiune sursa" pe transfer |
-| `do_cauta_comanda` | `7011-7034` (23) | |
-| `do_cauta_contract` | `7036-7091` (55) | |
-| `do_cauta_fdoc` | `7093-7104` (11) | **identica cu factura**, vezi punctul 4 |
-| `do_cauta_gestiune_dest` | `7106-7131` (25) | **doar pe aviz** — gestiune destinatie la transfer subunitati |
-| `do_cauta_gestiune_init` | `7133-7144` (11) | mai scurta decat pe factura (15) |
-| `do_cauta_lucrare` | `7146-7165` (19) | |
-| `do_cauta_politica` | `7167-7182` (15) | **doar pe aviz** — `Ct_clb_politici_preturi` |
-| `do_cauta_responsabil` | `7184-7204` (20) | aceeasi lungime ca factura |
-| `do_cauta_sectie` | `7206-7240` (34) | |
-| `do_cauta_venchelt` | `7242-7275` (33) | |
-| `inainte_de_do_termin` | `7277-7352` (75) | **omonim**, vezi mai jos — mai scurta decat factura (106): fara validare data-scadenta, fara validare valuta, fara validare client (!) |
-| `Init` | `7354-7600` (247) | **omonim**, nu citit integral aici (doar `9563-9650`+`9733-9796` echivalentul pe factura) |
-| `Clb_dataact...LostFocus` | `7602-7605` | |
-| `Clb_dataireg...LostFocus` | `7607-7612` | |
-| `Clb_nract...LostFocus` | `7614-7616` | |
-
-**`frm_date_aviz` nu are `do_schimba_tipdoc`** — confirmat, container-ul `Ct_clb_fdoc` de pe aviz e
-o cautare simpla, fara combo si fara evenimentul `LostFocus` care declanseaza schimbarea de tip.
-
-**Total real: 16 + 13 = 29 metode `do_cauta_*`**, plus `do_schimba_tipdoc` (doar factura), `do_verifica`
-(doar factura), `inainte_de_do_termin` si `Init` (omonime pe ambele) — planul le numara global corect
-ca "17+13 ... plus restul", dar cifra "17" pe factura e gresita cu o unitate: **16**.
-
----
-
-## 2. Metodele omonime — capcana centrala a portarii
-
-**Nivelul care conteaza cel mai mult, necunoscut inca in plan**: `Init` si `inainte_de_do_termin` sunt
-**acelasi nume de metoda pe toate cele patru formulare-sursa implicate in unificare**
-(`frm_date_factura`, `frm_date_aviz`, `frm_facturare_articole`/`frm_facturare_articole2`,
-`frm_alte_date`), fiecare cu corp complet diferit (antet vs. compunere articole vs. date suplimentare).
-O singura clasa unificata nu poate avea patru metode `Init`. **Portarea "o singura data" a S3 inseamna
-concret: patru corpuri de `Init` si patru corpuri de `inainte_de_do_termin` trebuie topite intr-un
-singur `Init` si un singur `inainte_de_do_termin` (sau redenumite si inlantuite explicit)** — asta e
-efortul real, nu doar mutarea codului de validare camp-cu-camp.
-
-**`inainte_de_do_termin`, factura vs. aviz — diferenta reala, cu citat** (comparate direct, ambele corpuri
-citite integral, `ofacturare.vc2:9455-9561` si `:7277-7352`):
-
-- **Factura valideaza `id_client` obligatoriu; aviz nu valideaza deloc acest camp**:
- ```
- ofacturare.vc2:9510-9513 (doar pe factura)
- Case Empty(poDate.id_client) Or Isnull(poDate.id_client)
- amessagebox("Nu ati ales clientul!",48,"Atentie")
- This.ct_clb_nume_client.SetFocus()
- ```
- Motiv plauzibil (neconfirmat mai departe): avizele de transfer intre subunitati (tip 23/25/30/41) nu
- au neaparat un "client" — au o gestiune destinatie, validata separat.
-- **Factura valideaza scadenta si valuta; aviz nu are deloc aceste `Case`-uri** — `Empty(poDate.datascad)`,
- `poDate.datascad=21 in afara de 27/30). **Discriminatorul natural pentru ramificare exista deja**:
- `poDate.nIdTipDoc` (5=FACTURA, 6=AVIZ — calculat de apelant la `ofacturare.prg:192-196`) sau simpla
- apartenenta a lui `poDate.tip` la unul din cele doua seturi disjuncte, **nu** un flag nou.
-- **Contul folosit la verificarea de facturi duplicate difera**: `facturi_duplicate('4111', 0, ...)`
- (factura, `:9545`, cont clienti) vs. `facturi_duplicate('418', 0, ...)` (aviz, `:7341`, alt cont) —
- un literal hardcodat care trebuie sa devina el insusi parte din ramificare, nu doar mesajul.
-
-**Alte omonime cunoscute, cu semantica diferita, relevante pentru zona din jurul lui S3** (nu introduse
-aici — reconfirmate, vezi si `docs\handoff_13_formular_unificat.md:192-194`):
-- `do_calculeaza_discount` — **la nivel de document** pe `frm_facturare_articole` (`:13405-13424`) si
- `frm_facturare_articole2` (`:17670-17686`, verificat aici: identic ca semantica, scrie
- `Thisform.ndiscfactron`/`ndiscfactval`); **la nivel de linie** pe `frm_articol_factura` (`:1874-1976`,
- scrie `poArticol.discount_unitar*`). Nu intra direct in S3 (nu e printre metodele antetului), dar
- orice cod nou care apeleaza `do_calculeaza_discount` prin nume pe formularul unificat trebuie sa
- stie care semantica o vrea.
-- `do_verifica` — pe `frm_date_factura` (`:9440-9453`, verificare ANAF) si pe `frm_facturi`
- (verificare ANAF, aceeasi semantica) — omonim inofensiv, aceeasi actiune.
-- `do_cauta_gestiune_init` / `do_cauta_responsabil` / `do_cauta_sectie` / `do_cauta_venchelt` /
- `do_cauta_altele` / `do_cauta_comanda` / `do_cauta_contract` / `do_cauta_avize` / `do_cauta_lucrare` —
- **acelasi nume pe factura si aviz, lungimi diferite** (vezi tabelele de la punctul 1) — nu omonime
- periculoase (aceeasi intentie: cautare pe camp), dar **nu identice** — portarea trebuie sa ia corpul
- fiecareia separat, nu sa presupuna ca sunt duplicate de sters.
-- **Singura pereche confirmata identica byte-cu-byte**: `do_cauta_fdoc` (vezi punctul 4) — aceasta
- chiar poate fi portata o singura data, fara ramificare.
-
----
-
-## 3. Ce e deja in prototip vs. ce lipseste
-
-`frm_facturare_articole2` (`ofacturare.vc2:15741-19355`) are controalele de antet montate direct pe
-formular (confirmat in `inventar_controale_formulare.md`), dar **zero logica**:
-
-| Metoda/mecanism | Exista in `frm_facturare_articole2`? | Detaliu |
-|---|---|---|
-| Toate cele 29 `do_cauta_*` | **NU** | niciunul in lista de metode proprii a clasei (confirmat cu `vfp_symbols.ps1 -Class`) |
-| `do_schimba_tipdoc` | **NU, dar e APELAT** — cod orfan | `clb_fdoc.cboFdoc.Valid` (`:19255-19257`) contine `thisform.do_schimba_tipdoc()`, dar clasa **nu are** aceasta metoda in lista proprie. Daca userul ar schimba azi combo-ul `clb_fdoc` pe acest formular mort, ar cadea cu eroare de metoda inexistenta. Confirma independent constatarea din plan ("controalele sunt acolo, logica nu") — de fapt e mai rau: e cod care ar crapa daca s-ar activa calea, nu doar cod lipsa |
-| `inainte_de_do_termin` | **DA, dar cu alta semantica** | `:18809-18986` (178 linii) — valideaza ARTICOLE (stoc, discount, TVA), nu antetul; e omonimul de care vorbeste punctul 2, nu un candidat de reutilizare pentru validarea de antet |
-| `Init` | **DA, dar cu alta semantica** | `:18988-19080` (92 linii, citit integral aici) — confirmat: doar grid/curs-label/total-mode/coloane in/afara valuta; **niciun** `poDate.xxx -> control.Value`. Nu populeaza antetul deloc |
-| Serie/numar (`Clb_serie_act1`/`Clb_nract`) | Controale prezente, dar fara wiring de populare in `Init` | `Clb_serie_act1.TEXT_SIMPLU1.LostFocus` (`:19263-19270`) exista ca metoda proprie — nu verificat aici daca reproduce `genereazanumar` |
-
-**Concluzie punctul 3**: prototipul e o **coaja vizuala**, nu un schelet de 50% functional. Ce trebuie
-scris pentru S3 e efectiv tot codul de comportament — controalele economisesc timpul de aranjare in
-`.scx`/`.vcx`, nu timpul de portare a logicii.
-
----
-
-## 4. Ramificarea factura / aviz in interior
-
-**Discriminatorul de ramificare recomandat: `poDate.nIdTipDoc`** (5=FACTURA, 6=AVIZ), deja calculat de
-apelant inainte de `Createobject` (`ofacturare.prg:187-196`) si deja disponibil pe `poDate` in
-momentul in care formularul unificat ar porni `Init`. Alternativ, acelasi rezultat se obtine testand
-direct apartenenta lui `poDate.tip` la unul din cele doua seturi disjuncte folosite azi in
-`inainte_de_do_termin` (vezi punctul 2) — cele doua seturi nu se suprapun niciodata, deci nu exista
-ambiguitate. **Nu e nevoie de o proprietate noua** gen `lEsteAviz` — `nIdTipDoc` face deja treaba, si
-e deja pe obiectul `poDate` care trece prin tot lantul de apeluri.
-
-Ce trebuie sa ramifice concret, cu dovada:
-1. **`inainte_de_do_termin`** — Cases specifice fiecarei parti (vezi citatele de la punctul 2), plus
- constanta de cont (`'4111'` vs `'418'`) la `facturi_duplicate`.
-2. **`Init`** — seturile `Do Case poDate.tip` care decid ce se elimina (`RemoveObject`) difera pe
- fiecare parte (S1 documenteaza deja fiecare camp cu conditia lui de vizibilitate; portarea trebuie
- sa pastreze fiecare conditie identic, nu sa le generalizeze pe ghicite).
-3. **`do_schimba_tipdoc`** — **exista doar pe factura**; pe aviz nu exista mecanismul de schimbare a
- tipului de document dupa deschiderea formularului (containerul `ct_clb_fdoc` de pe aviz e cautare
- simpla, fara `_combobox1`). Ramificarea aici nu e "cod diferit pe aceeasi metoda" ci "metoda
- prezenta doar pe o ramura" — formularul unificat trebuie sa decida daca aviz capata acest
- comportament nou (schimbare tip dupa deschidere) sau ramane fara el, ca azi.
-4. **`do_cauta_fdoc`** — **nu ramifica**, e identic (punctul 1) — poate fi portat o singura data, fara
- `If nIdTipDoc=...`.
-5. **`do_cauta_client`** — aviz e cu 18 linii mai lung (77 vs 59) pentru eticheta variabila
- "Retur de la"/"Gestiune sursa" pe transfer (S1, randul "Client") — de citit integral la
- implementare pentru ramificarea exacta, nu verificat linie-cu-linie aici.
-
----
-
-## 5. `Init`-urile — ce face fiecare, in ce ordine, ce depinde de ce
-
-**Secventa de azi, pe drumul normal (factura din lista de preturi, fara eroare Oracle):**
-
-1. **Apelantul** (`ofacturare.prg:factureaza`, inainte de orice `Createobject`): construieste
- `poDate = Createobject("oDateFactura", ...)` si `poGeneratorNumere = Createobject("oGeneratorNumere")`
- (`:184-185`), seteaza `poDate.nIdTipDoc` (`:187-196`), cheama
- `poDate.completeaza_setari_document(...)` daca e copiere (`:200-206`), apoi
- `poGeneratorNumere.ResetNumere()` si `poDate.rezultat_serii = poGeneratorNumere.creeaza_cursor_serii(...)`
- (`:208-211`) — **toate acestea ruleaza inainte ca vreun formular sa existe**. Orice `Init` de mai jos
- presupune `poDate`/`poGeneratorNumere` deja populate.
-2. **`frm_date_factura.Init`** (`:9563-9796`, 234 linii, citit integral aici) — `DoDefault()`, apoi
- masoara inaltimile containerelor de antet intr-un array (`laPozitii`), decide pe `Do Case
- gnScadereStoc/poDate.tip` ce containere elimina (`RemoveObject`) si reface layout-ul pe verticala,
- initializeaza serie+numar (`.clb_serie_act.do_initializeaza(poDate.rezultat_serii)`, `:9737`), si
- **la final** seteaza focus: pe `ct_clb_valuta` daca documentul e in valuta si campul valutei apare
- deasupra tipului si nu are inca valuta aleasa, **altfel pe `ct_clb_fdoc`** (`:9788-9793`, citat
- integral la punctul 6). Depinde de: `poDate` (tip, in_valuta, ...), `poGeneratorNumere`
- (`creeaza_cursor_serii` deja rulat de apelant), variabile globale de firma (`gnScadereStoc`).
-3. **`frm_facturare_articole2.Init`** (`:18988-19080`, 92 linii, citit integral aici) — confirmat:
- **nu atinge niciun camp de antet**. Configureaza doar gridul (`nNrInregVizibile`), eticheta
- cursurilor valutare, modul total (`gnModTotFact`), si elimina coloanele RON sau valuta din grid
- dupa `poDate.in_valuta`. Depinde de: `poDate.zi_curs`/`in_valuta`/`tip`, `crscursuri` (populat de
- apelant intre pasii 2 si 3, nu de acest `Init`).
-4. **`frm_alte_date.Init`** (`ferestre_cere_date.vc2:3105-3207`, 103 linii, citit integral aici) —
- `DoDefault()`, citeste `poDate.dataora_exp`; **daca nu e proforma**: cauta ultimul delegat/masina
- folosite pentru client (apel Oracle `cauta_date_ultima_factura[_tip]`, `:3119-3136`), populeaza
- combo-ul de casa dintr-un cursor Oracle nou (`v_nom_casa`, `:3156-3173`), seteaza `opt_incasat`
- implicit daca `poDate.incasat<>0`; **daca e proforma**: elimina complet grupul delegat/masina/
- incasare (`RemoveObject` in cascada, `:3192-3201`) si redimensioneaza formularul la zona de text
- aditional. **Risc gasit, neurmarit mai departe**: pe eroare la interogarea combo-ului de casa,
- `Init` cheama `poGeneratorNumere.dezaloca_numar(5)` si `Return` (`:3159-3161`) — acelasi tipar de
- "dezalocare numar pe eroare SQL neasteptata" ca la bug-ul #16 (punctul 6), dar intr-un `Init`, nu
- intr-o bucla — **nu s-a verificat daca are aceeasi consecinta de recreare completa a formularului**;
- semnalat, nu investigat suplimentar aici din motive de buget de context.
-
-**Ordinea de dependente, explicit**: `poDate`+`poGeneratorNumere` (apelant) -> `frm_date_factura`/
-`frm_date_aviz.Init` (foloseste serie/numar deja create) -> **Oracle: cursorul de articole**
-(`ofacturare.prg:266-308`, aici poate pica bug #16) -> `frm_facturare_articole2.Init` (foloseste
-`crscursuri` populat intre pasi, nu de propriul `Init`) -> `frm_alte_date.Init` (face **inca** un apel
-Oracle nou, cu propriul risc de dezalocare). **Pentru formularul unificat, aceasta secventa de patru
-`Init`-uri trebuie sa devina un singur `Init` care ruleaza fazat** (o singura data la deschidere) —
-sau ramane o discutie deschisa daca vreo faza (Oracle-lookup-ul din `frm_alte_date.Init`) ramane
-intarziata pana la deschiderea sectiunii pliate, ca sa nu incarce round-trip-uri Oracle inutile cand
-utilizatorul nu ajunge niciodata la acea sectiune.
-
----
-
-## 6. Bug-ul #16 — mecanismul exact, verificat pe cod
-
-**Text original** (`COMUN\docs\todos.txt:45`): *"la revenire din formularul de curs valutar, focusul
-revine inainte de numar document, cred ca pe TIP DOCUMENT, si la iesire din serie se regenereaza numar
-act, ceea ce este periculos daca utilizatorul l-a schimbat".*
-
-**Verdict: NU e un bug de focus. E o bucla de reincercare care trateaza orice esec Oracle ca pe un "DA,
-mai fac un document" si reconstruieste formularul de antet de la zero — focusul si regenerarea
-numarului sunt doar simptomele vizibile ale acestei reconstructii.**
-
-Lantul complet, verificat linie cu linie:
-
-1. Utilizatorul completeaza antetul, apasa Termina — `inainte_de_do_termin` trece, formularul de antet
- se inchide (`pnButon=1`).
-2. Apelantul (`factureaza`, `ofacturare.prg:266-308`) construieste cursorul de articole din Oracle
- (`cursor_preturi`/etc., functie de `poDate.tip`). **Daca cererea esueaza** (`lnSucces<0`,
- `:313`) — inclusiv, dar nu numai, cu eroarea Oracle `-20005` "Nu este setat cursul..." (curs
- valutar lipsa pentru o valuta din listele de preturi ale utilizatorului, verificata neconditionat
- in `pack_facturare.verifica_cursuri_valute`, documentat deja in `zi_curs_validare.md`):
- ```
- ofacturare.prg:313-322
- If lnSucces < 0
- AMESSAGEBOX(goExecutor.oPrelucrareEroare(), 16, "Eroare")
- If goExecutor.nEroare = 20005
- vizualizeaza_curs(poDate.zi_curs) && deschide "formularul de curs valutar" (frm_curs, modal)
- ENDIF
- poGeneratorNumere.dezaloca_numar(poDate.nIdTipDoc) && numarul alocat se elibereaza
- Else
- ... [singurul loc unde se cere "Doriti sa continuati?" si se seteaza lnRaspuns]
- Endif
- ```
- `vizualizeaza_curs` (`oproceduri_curs.prg:8-42`) e confirmat: deschide `Createobject("frm_curs",
- tdDataCurs).Show(1)` — chiar formularul din reclamatie.
-3. **Punctul central, verificat prin numararea `If`/`Else`/`Endif` din fisier**: prompt-ul "Doriti sa
- continuati cu operatii de acest fel?" care seteaza variabila de bucla `lnRaspuns` **exista doar in
- ramura `Else` a lui `If lnSucces<0`** (`ofacturare.prg:555-564`, in interiorul aceluiasi bloc
- `If/Else/Endif` care se inchide abia la `:568`). **Pe ramura de eroare (`lnSucces<0`), `lnRaspuns`
- nu e niciodata atins.** Isi pastreaza valoarea din intrarea in aceasta iteratie a buclei — pe primul
- document, `6` (initializat la `:174`, inainte de `Do While lnRaspuns = 6` de la `:175`).
-4. Bucla externa (`Do While lnRaspuns = 6 ... Enddo`, `:175-571`) **reintra automat**, fara nicio
- intrebare catre utilizator, pentru ca `lnRaspuns` e inca `6`. In aceasta noua iteratie:
- `poGeneratorNumere.ResetNumere()` si `poDate.rezultat_serii = poGeneratorNumere.creeaza_cursor_serii(...)`
- ruleaza din nou (`:208-211`), apoi se creeaza **o instanta noua** de `frm_date_factura`/`frm_date_aviz`
- (`Createobject`, `:230`) si se arata modal (`:235`) — `poDate` insusi **nu** e recreat (ramane
- acelasi obiect, cu `nract`/`serie_act` deja setate de utilizator), dar **formularul da**, deci
- `Init` ruleaza de la capat.
-5. `frm_date_factura.Init` (`:9563-9796`) reface layout-ul si, **la final, seteaza focus necondiționat
- pe `ct_clb_fdoc`** (tip document) in cazul normal:
- ```
- ofacturare.vc2:9788-9793
- DO CASE
- CASE poDate.in_valuta = 1 and this.ct_clb_valuta.Top < this.ct_clb_fdoc.Top AND EMPTY(NVL(poDate.nume_valuta,''))
- this.ct_clb_valuta.SetFocus()
- OTHERWISE
- this.ct_clb_fdoc.SetFocus()
- ENDCASE
- ```
- **Aceasta e "focusul care revine pe TIP DOCUMENT"** din reclamatie — nu un bug izolat de focus, ci
- comportamentul normal de `Init` al unui formular nou, aparut unde utilizatorul nu se astepta la un
- formular nou.
-6. Cand focusul paraseste `ct_clb_fdoc` (Tab, click in alta parte — orice), se declanseaza
- `Ct_clb_fdoc._combobox1.LostFocus -> thisform.do_schimba_tipdoc()` (`:9857-9859`). Prima linie a
- acestei metode, **inainte de orice verificare "tipul chiar s-a schimbat?"**:
- ```
- ofacturare.vc2:9417 (in do_schimba_tipdoc, INAINTE de guard-ul de la :9419-9421)
- This.clb_serie_act._cbbase1.LostFocus()
- ```
- — apeleaza **neconditionat** handler-ul de LostFocus al combo-ului de serie, indiferent daca tipul
- documentului s-a schimbat sau nu.
-7. Acel handler (`serii_numere.vc2:138-140`, clasa `clb_serie_act`) cheama `genereazanumar` (`:114-136`):
- ```
- serii_numere.vc2:122-127
- If poGeneratorNumere.verifica_serie(This.nid_tipdoc) Or &lcValoare. = 0
- lcValoare = lcValoare+[=]+ALLTRIM(Str(poGeneratorNumere.aloca_numar(This.nid_tipdoc,Null),20,0))
- &lcValoare
- This.Parent.Refresh()
- Endif
- ```
- — **aloca un numar nou** si il scrie peste `poDate.nract` prin macro, **necondiționat de ce numar
- avea utilizatorul inainte**. **Asta e "iesirea din serie regenereaza numarul actului"** din
- reclamatie — confirmat exact, pana la linia care face scrierea.
-
-**Verdict pe intrebarea planului ("se rezolva #16 in S3, sau se reproduce bug-ul?"): se poate rezolva
-in S3, cu un cost mic, dar nu e o consecinta automata a unificarii — trebuie tratat explicit.**
-Cauza reala nu e in `frm_date_factura`/`do_schimba_tipdoc`/`clb_serie_act` (cod care se comporta
-"corect" fata de contractul lui local), ci in bucla de reincercare din apelant
-(`ofacturare.prg:174-571`), care **nu distinge "utilizatorul a confirmat ca vrea alt document" de
-"cererea Oracle a esuat"**. Doua directii posibile, ambele in afara perimetrului strict al portarii de
-antet, dar declansate direct de ea:
-- **(a) minimal**: in formularul unificat, dupa un esec Oracle la pasul de construire a cursorului de
- articole (echivalentul liniei `:313`), **nu se distruge formularul de antet** — antetul e deja o
- singura sectiune persistenta a aceluiasi formular, nu un obiect separat recreat de apelant; simpla
- arhitectura unificata (un `Init` per sesiune de emitere, nu per formular) elimina pasul 4 de mai sus,
- deci elimina intreg lantul 5-7. **Acesta e motivul pentru care unificarea are sansa reala sa rezolve
- #16 ca efect secundar** — dar numai daca implementarea nu recreeaza formularul intreg la reincercare
- dupa eroare Oracle (ceea ce ar reproduce bug-ul identic, doar mutat).
-- **(b) daca (a) nu e suficient** (de ex. daca dupa fix la curs tot trebuie relansata interogarea de
- articole): `lnRaspuns` (sau echivalentul lui in noua arhitectura) trebuie resetat explicit pe orice
- cale care iese din ramura de eroare, ca sa nu mai fie confundat cu "utilizatorul a spus DA".
-
-**Coordonarea cu #6 (decizia 30 si constrangerea din briefing) — verificat direct pe diff-uri, nu doar
-pe proza handoff-ului**: `docs\diff_s4_valuta_dialog*.patch` (trei fisiere) ating exclusiv
-`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 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.**
-
----
-
-## 7. Ordinea de lucru propusa pentru S3
-
-Pasi care lasa suita functionala dupa fiecare (calea veche ramane in productie pe tot parcursul —
-niciun pas nu sterge `frm_date_factura`/`frm_date_aviz`/`frm_alte_date` originale):
-
-1. **Fuzioneaza `Init`-urile de antet** (`frm_date_factura` + `frm_date_aviz`) intr-o metoda unica pe
- formularul unificat, ramificata pe `poDate.nIdTipDoc` (punctul 4). Verificare: formularul unificat
- se deschide pe fiecare din cele ~15 tipuri principale de `poDate.tip` folosite azi in cele doua
- `Init`-uri, si arata exact aceleasi campuri vizibile/eliminate ca varianta veche — comparatie
- camp-cu-camp fata de tabelul din `docs\S1_inventar_campuri_formular_unificat.md`.
-2. **Porteaza cele 29 `do_cauta_*`** (fara ramificare unde sunt identice — `do_cauta_fdoc` — cu
- ramificare pe `nIdTipDoc` unde difera). Verificare: fiecare cautare deschide acelasi dialog, scrie
- aceleasi proprietati pe `poDate`, muta focusul identic cu azi.
-3. **Fuzioneaza `inainte_de_do_termin`**, cu ramificarea documentata la punctul 2. Verificare: aceleasi
- mesaje de eroare, in acelasi ordine, pentru aceleasi campuri goale, pe fiecare tip.
-4. **Porteaza `do_schimba_tipdoc`** — decide explicit daca ramane doar-factura sau se extinde si pe
- aviz (punctul 4, pct. 3). **Aici se rezolva sau nu #16** (punctul 6) — de facut ca parte a acestui
- pas, nu separat, pentru ca schimbarea de arhitectura care il rezolva (un singur `Init` persistent)
- e chiar cea care se construieste la pasul 1.
-5. **Porteaza `but_modifica`/blocarea antetului** (decizia 9, deja proiectata in plan sectiunea I) —
- depinde de pasii 1-4 fiind stabili, pentru ca reutilizeaza aceleasi controale.
-6. **Integreaza bucla de emitere** (`factureaza`/`factureaza2`) cu noul formular unificat, tratand
- explicit esecul Oracle de la cursorul de articole (punctul 6, directia a/b).
-
-**Criteriul de "gata", rescris verificabil.** Azi planul spune "un document se emite integral din
-formularul unificat, pe tip 1, cu acelasi rezultat in `vanzari`/`act`/`rul` ca pe calea veche" — fara
-sa spuna cum se compara. Propunere concreta:
-- Se emite **acelasi document** (acelasi client, articole, cantitati, preturi) o data pe calea veche
- (`frm_date_factura` -> `frm_facturare_articole` -> `frm_alte_date`) si o data pe formularul unificat,
- pe date de test identice, in aceeasi zi contabila.
-- Se compara, randuri-cu-randuri, rezultatul in `VANZARI` (toate coloanele, nu doar sumele), `ACT`,
- `RUL`, `DOCUMENTE`, `JV2007` (nota contabila) — cel mai simplu cu doua interogari identice filtrate
- pe cei doi `ID_FACT`/`ID_VANZARE` rezultati, exportate si diff-uite text-cu-text (unealta: acelasi
- export SQL folosit deja pentru `PACK_FACTURARE` in `docs\ff_*.sql`, adaptat pe `SELECT * FROM VANZARI
- WHERE ID_FACT=...`).
-- Diferentele **asteptate** (marcate ca OK, nu ca esec): `ID_VANZARE`/`ID_FACT`/timestamp-uri de
- creare — orice altceva trebuie sa fie identic.
-- Se repeta pentru **cel putin un tip de factura in valuta** (S3 atinge direct campurile de valuta) si
- **un tip de aviz** (ramificarea de la punctul 4), nu doar tip 1.
-
----
-
-## 8. Ce nu se poate testa headless din S3
-
-Capcana cunoscuta (`COMUN\docs\depanare_testare_vfp.md`, memorie de proiect): sub harness `-A -T`,
-coloanele de grid nu se materializeaza (`ColumnCount=0`, `RecordSource` raman artefacte necitite) —
-relevant direct pentru `frm_facturare_articole2` (grid-ul de compunere), dar S3 propriu-zis nu atinge
-gridul.
-
-Specific pentru S3 (antet):
-- **Toate cele 29 `do_cauta_*`** deschid un dialog modal de cautare (`caut_ora.vcx`/similare) —
- 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
- 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
- vizibil, pentru ca `Createobject` ruleaza `Init` fara `Show()` — tiparul e deja validat in codebase.
-- **Focusul si secventa reala de `LostFocus`** (exact ce a produs bug #16) **nu se poate reproduce
- headless** — necesita fie `vfp_ui_harness.ps1` cu UI vizibil si input simulat pe masina, fie testare
- manuala de Marius; simularea unui `SetFocus()`/`LostFocus()` apelat direct din cod ocoleste tocmai
- secventa evenimentelor native care a cauzat bugul.
-- **Eroarea Oracle -20005 si redeschiderea `vizualizeaza_curs`** — reproductibila headless doar daca
- se poate forta controlat lipsa unui curs pentru o data de test (manipulare de date, nu de UI) — nu
- s-a verificat aici daca exista deja o retetare de date de test pentru asta.
-
----
-
-## Ce nu s-a putut stabili si de ce
-
-- **Corpul complet al `frm_date_aviz.Init`** (`:7354-7600`, 247 linii) — citit doar partial in sesiuni
- anterioare (pana la `~7533`, conform `inventar_controale_formulare.md:166-167`); nu re-citit integral
- aici din motive de buget de context. Structura generala (Do Case pe tip, RemoveObject, focus final)
- e foarte probabil simetrica cu `frm_date_factura.Init`, dar nu verificata linie-cu-linie.
-- **`do_cauta_venit`** (`frm_date_factura`, `:9393-9394`, o singura linie) — nu s-a citit continutul;
- posibil alias/stub mort, de verificat la implementare.
-- **Riscul semnalat la punctul 5** (`frm_alte_date.Init:3159`, `dezaloca_numar` pe eroare la
- interogarea combo-ului de casa) — **doar semnalat, neurmarit**: nu s-a verificat daca apelantul care
- cheama `frm_alte_date` are aceeasi bucla "retry silentios" ca `factureaza`, sau daca eroarea aici
- chiar opreste fluxul curat (`Return` explicit la `:3161`, spre deosebire de bug #16 unde nu exista
- `Return` echivalent). Merita o cercetare separata, de marimea celei de la punctul 6, inainte de
- implementare.
-- **`Clb_serie_act1.TEXT_SIMPLU1.LostFocus`** din `frm_facturare_articole2` (`:19263-19270`) — nu
- citit; nu s-a verificat daca reproduce corect `genereazanumar` sau e alt cod orfan ca cel de la
- punctul 3.
-- **Ramificarea exacta linie-cu-linie pentru restul celor 27 de perechi `do_cauta_*`** (dincolo de
- `do_cauta_client` si `do_cauta_fdoc`, comparate direct aici) — s-au comparat doar lungimile (indiciu
- de diferenta), nu continutul; de citit la implementare, nu presupus din lungime.
-- **`frm_modifica_factura`** — clasa reala traieste in `ofacturare_comun.vc2` (perimetrul #6, doar
- citire permisa), dar `vfp_symbols.ps1` a indexat-o din `.pre_s4butoane.bak.vc2` (linii duplicate,
- nesigure) — nu s-au recitit liniile reale, pentru ca `frm_modifica_factura` **nu intra in portarea
- S3** (e inlocuita de `but_modifica`, deja proiectat separat in plan, sectiunea I).
-
-## Bug-uri semnalate, nereparate
-
-1. **Cod orfan in `frm_facturare_articole2`**: `clb_fdoc.cboFdoc.Valid` (`ofacturare.vc2:19256`) cheama
- `thisform.do_schimba_tipdoc()`, metoda **inexistenta** pe aceasta clasa — ar arunca eroare VFP daca
- userul ar interactiona cu acest combo pe formularul mort. Fara consecinte azi (formularul nu e
- accesibil in productie, cf. plan sectiunea A), dar de curatat sau completat cand prototipul devine
- baza formularului unificat.
-2. **Bug #16, confirmat si localizat complet** (punctul 6) — in `ofacturare.prg:555-564` (si simetric
- in `factureaza2`, liniile ~1061 dupa numerotarea echivalenta, nu verificate linie-cu-linie aici):
- `lnRaspuns` nu se reseteaza pe ramura de eroare Oracle a buclei de emitere, cauzand recrearea
- completa si nesolicitata a formularului de antet. In afara perimetrului `ofacturare_comun.vc2`/
- `ofacturare_editare.prg` (deci nu ciocneste cu #6), dar in `ofacturare.vc2`/`ofacturare.prg`, cod
- comun suitei (afecteaza si ROACONT/ROAGEST/etc. daca folosesc acelasi `factureaza`/`factureaza2`
- din `COMUN` — neverificat aici daca alte produse il apeleaza, dar fisierul e in `COMUN\programe`,
- deci probabil da).
-3. **Risc structural similar, neconfirmat**: `frm_alte_date.Init:3159` — acelasi tipar
- "`dezaloca_numar` pe eroare SQL neasteptata", posibil fara aceeasi consecinta de reincercare
- silentioasa, dar nu verificat (vezi "Ce nu s-a putut stabili").
diff --git a/docs/cercetare/s3b_alte_date_analitice.md b/docs/cercetare/s3b_alte_date_analitice.md
deleted file mode 100644
index 5666d10..0000000
--- a/docs/cercetare/s3b_alte_date_analitice.md
+++ /dev/null
@@ -1,602 +0,0 @@
-# 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.
diff --git a/docs/cercetare/s3c_sursa_ca_parametru.md b/docs/cercetare/s3c_sursa_ca_parametru.md
deleted file mode 100644
index d9b2c96..0000000
--- a/docs/cercetare/s3c_sursa_ca_parametru.md
+++ /dev/null
@@ -1,426 +0,0 @@
-# S3c — Proiectare: sursa ca parametru, nu ca global
-
-Cercetare read-only pentru povestea **S3c** din `docs\plan_13_unificare_formular_facturare.md`
-(`#### S3c`, linia 1855; decizia 12, linia 473; L.3, linia 1733; „Canalul de precompletare”,
-liniile 465-474). Zero modificari de cod, zero write-back, zero `git_sync.ps1`, zero commit — in
-niciun produs din `D:\ROA`. Depinde de S2 (`docs\cercetare\s2_factureaza_unificare.md`), a carui
-proiectare a lasat explicit semnatura lui `factureaza` neschimbata „pentru ca e treaba lui S3c”
-(sectiunea 5 a acelui raport).
-
-Status: **complet**.
-
----
-
-## Verdict
-
-**Se poate face, e o interventie mica pe cod, dar textul planului supraestimeaza cat de „globala"
-e problema azi.** `goContract` nu e niciodata scris in `ROAFACTURARE` — nici in codul specific
-produsului, nici in `COMUN`-ul lui — deci ramura de precompletare din contract
-(`ofacturare_comun.prg:261-297`) e **cod mort in ROAFACTURARE azi**, nu doar teoretic riscant.
-Asimetria de resetare semnalata la L.3 (`ofundal_facturare.vc2:886-902`) exista textual, dar
-**nu produce niciun efect observabil azi**, pentru ca nu exista niciun scriitor al lui `goContract`
-in acest produs care sa lase ceva de resetat. Ea devine un risc real abia daca cineva adauga in
-viitor, in `ROAFACTURARE`, un cod care scrie `goContract` — situatie in care lipsa resetarii ar
-deveni activa dintr-o data, tacut. `goComanda`, in schimb, chiar e viu in `ROAFACTURARE`: are doi
-scriitori (`ocomenzi.vc2:1583` la clic pe „Factureaza”, **si** `ocomenzi.vc2:2199`, ca efect
-colateral al navigarii in grid), iar reset-ul explicit de la `ofundal_facturare.vc2:900` e singura
-plasa de siguranta reala azi.
-
-**Suprafata de regresie e mica si masurata exact**: doi scriitori de convertit
-(`ocomenzi.vc2:1580-1596` in familia ROAFACTURARE, `ferestre_contracte.vc2:1538-1549`+`:1598-1606`
-in ROACONTRACTE), trei fisiere comune de atins o singura data fiecare
-(`ofacturare.prg`, `oproceduri_facturare.prg`, `ofacturare_comun.prg`), si **zero schimbari** la
-celelalte ~31 puncte de intrare din inventarul S2 — toate cheama `factureaza(N)` cu un singur
-parametru, deci un al treilea parametru opozitional cu implicit `.F.`/`NULL` nu le atinge.
-
-**Corectie de scop fata de formularea planului**: „pana se convertesc toti apelantii" nu poate
-insemna, pentru `goContract`, „pana dispare global-ul" — `goContract` e bufferul de editare al
-intregului ecran de contracte din ROACONTRACTE (peste 100 de `ControlSource` legate de el,
-sectiunea 1), populat continuu de navigarea in grid, independent de facturare. Nu va disparea
-niciodata din ROACONTRACTE la aceasta poveste sau la vreuna viitoare rezonabila — S3c schimba doar
-**canalul prin care valoarea ajunge la `oDateFactura.Init`**, nu existenta globalei in ROACONTRACTE.
-Criteriul de „gata” de mai jos (sectiunea 8) e rescris sa reflecte asta.
-
----
-
-## 1. Inventarul scrierilor si citirilor `goComanda` / `goContract` in toata suita
-
-Cautare in `D:\ROA\ROAFACTURARE`, `D:\ROA\ROACONT`, `D:\ROA\ROAGEST`, `D:\ROA\ROAAUTO`,
-`D:\ROA\ROAACNPRO`, `D:\ROA\ROAIMOB`, `D:\ROA\ROACONTRACTE` — radacina fiecarui produs **si**
-`COMUN\`-ul lui explicit (capcana „Grep nu vede COMUN”). `D:\ROA\COMUNROA` nu contine niciuna din
-cele doua variabile (cautare separata, zero rezultate) — confirma ca sursa nu e livrata prin
-biblioteca partajata, ci prin fisierele COMUN duplicate per produs.
-
-### `goComanda`
-
-| Fisier | Linie | Rol | Produse |
-|---|---|---|---|
-| `Programe\roafacturare.prg` | `:473-474` | **Declarare**: `PRIVATE goComanda` / `goComanda = null`, la pornirea aplicatiei | doar ROAFACTURARE (fiecare produs are propriul `roafacturare.prg`/echivalent, nu verificat identic — irelevant, doar initializeaza la null) |
-| `COMUN\clase\ocomenzi.vc2:1580-1596` (`ct_comenzi.do_factura`) | `:1583` | **SCRIE**: `SELECT crsComenzi` / `SCATTER NAME goComanda MEMO`, apoi cheama `facturare_comenzi` | ROAFACTURARE, ROACONT, ROAGEST, ROAAUTO, ROAACNPRO, ROAIMOB (fisier identic pe MD5, sectiunea 6) |
-| `COMUN\clase\ocomenzi.vc2:2191-2207` (`_grdrow1.AfterRowColChange`) | `:2199` | **SCRIE** ca efect colateral: la fiecare schimbare de rand in grid-ul de comenzi, `SCATTER NAME goComanda MEMO`, folosit doar pentru `but_factura1.Visible = (goComanda.facturat = 0)` (`:2202`) — **nu are nicio legatura cu intentia de facturare**, dar suprascrie global-ul de fiecare data cand utilizatorul navigheaza in grid | idem, acelasi fisier identic |
-| `COMUN\programe\ofacturare_comun.prg:301-328` (`oDateFactura.Init`) | `:301` | **CITESTE**: `If tnTip = 3 And Type('goComanda') = 'O'` -> `.id_client`, `.nume_client`, `.cod_fiscal`, `.listaid`, `.descriere`, `.id_sectie`, plus un `SELECT sectie FROM nom_sectii` pe `goComanda.id_sectie` | identic pe 6/7 produse (sectiunea 6; ROAIMOB diverge cu o linie, dar nu pe acest bloc) |
-| `Clase\ofundal_facturare.vc2:899-902` (`Page2.Cw3.do_actiune`) | `:900` | **RESETEAZA** explicit: `goComanda = ''` inainte de `DO facturare_comenzi` | doar ROAFACTURARE (fisierul e specific produsului, nu COMUN) |
-
-Niciun alt fisier, in niciun produs verificat, nu scrie sau citeste `goComanda`.
-
-### `goContract`
-
-| Fisier | Linie | Rol | Produse |
-|---|---|---|---|
-| `ROACONTRACTE\Programe\roacontracte.prg:559-560` | `:559-560` | **Declarare**: `Public poCtr, goContract` / `Store '' To poCtr, goContract`, la pornirea aplicatiei | doar ROACONTRACTE |
-| `ROACONTRACTE\Clase\ferestre_contracte.vc2` | ~200 aparitii (liniile 977-11005, tabel complet in sectiunea de cautare) | **SCRIE si CITESTE** ca buffer de editare al intregului formular de contracte: `Scatter Name goContract Memo Blank` la creare (`:1026`, `:1186`), `SCATTER NAME goContract MEMO` la fiecare schimbare de rand in grid (`grid_contracte.AfterRowColChange`, `:1598-1606`), **peste 20** `ControlSource = "goContract."` pe controale (combo-uri, textbox-uri), `Gather Name goContract Memo` la salvare (`:1053`, `:2406-2472` etc.) | doar ROACONTRACTE |
-| `ROACONTRACTE\Clase\ferestre_contracte.vc2:1538-1549` (`but_factura.Click`) | — | **CITESTE implicit** (nu re-scrie): cheama `facturare_contracte` fara sa re-populeze `goContract` — se bazeaza pe scrierea facuta deja de `AfterRowColChange` la selectia randului curent | doar ROACONTRACTE |
-| `ROACONTRACTE\Clase\outlook2003bar.vc2`, `ofundal_roaclienti.vc2` | multiple | **CITESC** `goContract.id_ctr`/`.id_part` pentru navigare in bara laterala si ecrane de parteneri | doar ROACONTRACTE |
-| `ROACONTRACTE\Programe\roacontracte.prg`, `oparteneri_contracte.prg`, `oproceduri_roacontracte.prg` | multiple | **CITESC/SCRIU** `goContract` in fluxuri proprii ROACONTRACTE (incasari, plati, rate, garantii) — complet independente de facturare | doar ROACONTRACTE |
-| `COMUN\programe\ofacturare_comun.prg:261-297` (`oDateFactura.Init`) | `:261` | **CITESTE**: `If INLIST(m.tnTip, 2, 6, 52) And Type('goContract') <> 'U'` -> `.id_client`, `.nume_client`, `.cod_fiscal`, `.listaid`, `.descriere`, `.id_sectie`, `.sectie`, `.id_responsabil`, `.responsabil`, `.id_valuta`, `.nume_valuta`, plus interogare `fact_vcontracte` pentru scadenta | identic pe 6/7 produse (ROAIMOB diverge cu exact aceasta linie lipsa — sectiunea 6) |
-| `COMUN\clase\ferestre_atasamente.vc2`, `COMUN\programe\oproceduri_atasamente.prg` | 5 aparitii | **CITESC** `goContract.id_ctr`, dar **numai** in ramura `Case Upper(Alltrim(gcNumeProgram)) = "ROACONTRACTE"` — cod prezent in fiecare copie COMUN (deci si in ROAFACTURARE), dar mort acolo pentru ca `gcNumeProgram` nu e niciodata `"ROACONTRACTE"` in afara procesului ROACONTRACTE | identic pe toate produsele verificate, dar activ doar in ROACONTRACTE |
-
-**Confirmare directa: `goContract` nu e scris niciunde in `ROAFACTURARE`** — nici in `Programe\`,
-`Clase\`, `Ferestre\`, `Meniuri\`, nici in `COMUN\` (cautare pe `PUBLIC goContract`/`Public
-goContract` in tot arborele: zero rezultate, tabelul complet cu toate declaratiile `PUBLIC go*`
-gasite e in sectiunea 2). Singura mentiune a lui `goContract` in ROAFACTURARE e citirea garda de
-`Type()` din `ofacturare_comun.prg:261`, care ramane mereu falsa (`Type('goContract') = 'U'`) intr-o
-sesiune ROAFACTURARE.
-
-## 2. Verdict pe L.3 — asimetria de resetare
-
-**Textul din cod e adevarat, dar efectul practic e altul decat sugereaza formularea „de verificat”
-din plan.**
-
-- **Asimetria exista, literal**: `ofundal_facturare.vc2:899-902` (`Page2.Cw3`, ruta genericaa de
- comanda) face `goComanda = ''` inainte de `DO facturare_comenzi`; `ofundal_facturare.vc2:886-897`
- (`Page2.Cw2`, ruta generica de contract) **nu** face echivalentul pentru `goContract` — cheama
- direct `DO facturare_contracte WITH 'FACTURA LEI'/'INVOICE'/'FACTURA VALUTA'`.
-- **Dar `facturare_contracte` (`oproceduri_facturare.prg:119-136`) nu citeste si nu scrie
- `goContract` deloc** — primeste un string de tip (`'FACTURA LEI'` etc.) si cheama direct
- `factureaza(2)`/`factureaza(6)`/`factureaza(52)`. Precompletarea din contract se intampla
- **exclusiv** in `oDateFactura.Init`, la citirea globalei — nu exista niciun pas intermediar care
- ar putea fi „resetat”.
- In ROAFACTURARE, calea genericaa (Cw2) las utilizatorul sa aleaga contractul **in formular**,
- printr-un combo populat din `crscontracte` legat de `poDate.listaid`
- (`ofacturare.prg:283-291,433-440`) — un canal complet diferit, care nu trece prin `goContract`
- deloc (confirmat citind codul, sectiunea 3).
-- **Deci, in ROAFACTURARE azi, nu exista nicio secventa executabila in care `goContract` sa fie
- citit cu o valoare veche.** Pentru ca asta sa se intample ar trebui ca (a) ceva sa fi scris
- `goContract` mai devreme in aceeasi sesiune ROAFACTURARE — **nu exista niciun asemenea cod azi** —
- si (b) urmatorul apel sa fie cu `tnTip` in `(2, 6, 52)`. Fara (a), (b) singur nu ajunge nicaieri.
-- **Verdictul pe L.3**: asimetria de resetare **e reala ca defect de simetrie in cod** (o ruta isi
- curata globala inainte de apel, cealalta nu), dar **inert azi in ROAFACTURARE** — nu exista niciun
- document gresit care se poate emite azi din cauza ei, pentru ca variabila pe care ar trebui sa o
- resetezi nu e niciodata populata in acest produs. Devine un risc real **doar** daca un cod viitor
- (in ROAFACTURARE) incepe sa scrie `goContract` fara sa adauge simetric si resetul — exact genul de
- capcana pe care „parametru explicit, fara global implicit” o elimina structural, nu prin inca o
- linie de reset de tinut minte.
-- **In ROACONTRACTE, unde `goContract` chiar e viu, nu exista o ruta „generica fara precompletare”
- analoaga lui Cw2** — `but_factura.Click` (`:1538-1549`) e singurul punct de intrare si presupune
- intotdeauna un contract selectat in grid (populat de `AfterRowColChange`, `:1598-1606`, la fiecare
- schimbare de rand). Riscul teoretic acolo nu e „global ramas din alta sesiune de facturare”, ci
- „utilizatorul apasa Factureaza fara sa fi selectat explicit un rand dupa un refresh programatic” —
- un caz marginal, netratat de L.3 si nelegat de asimetria semnalata in plan.
-
-## 3. Doar doua globale, sau mai sunt?
-
-**Doar doua.** Verificat prin citirea completa a `oDateFactura.Init`
-(`ofacturare_comun.prg:223-332`) si a rutarii cursoarelor de articole din `ofacturare.prg:260-308`:
-
-- **`goDate`, `gnIdSet` ca surse de precompletare — nu exista.** `goDate` nu apare niciunde in
- `ofacturare.prg`/`ofacturare_comun.prg` (cautare directa, zero rezultate). `gnIdSet` nu exista ca
- atare — parametrul se numeste `tnIdSet`/`lnIdSet`, calculat **local** in `factureaza`
- (`lnIdSet = 25000 + tnTip - 1 + gnScadereStoc * 10`, `ofacturare.prg:123`) din `tnTip` si un
- optiune de configurare (`gnScadereStoc`), nu un canal de sursa.
-- **Singurele doua verificari `Type('go...')` din `oDateFactura.Init` sunt exact `goContract`
- (`:261`) si `goComanda` (`:301`)** — cautare `Type\('go` pe tot `ofacturare.prg` +
- `ofacturare_comun.prg`: zero alte rezultate in afara comutatorului de dezvoltator
- `gnFacturareNou` (irelevant aici, documentat in S2).
-- **`poDate.listaid` pentru avize (tip 4, 21, 28, 42, 47) NU trece printr-un global** — se scrie
- direct din cursorul de selectie al formularului: `poDate.listaid = Iif(Inlist(poDate.tip, 3, 21,
- 28, 42, 47), Alltrim(Str(id_comanda)), [])` (`ofacturare_comun.vc2:4255`, si varianta similara la
- `:4062`, `:7271`) — populat dintr-un `Scan`/`Locate` peste cursorul cu avizele bifate de utilizator
- in acelasi apel, nu dintr-o variabila globala persistenta intre apeluri. **Avizele nu intra in
- S3c** — nu au canal implicit de eliminat.
-- **Copierea (`toFactura`) e deja parametru, nu global** — `copiere_factura(toFactura)`
- (`oproceduri_facturare.prg:150-153`) -> `factureaza(toFactura.Tip, toFactura)`, si in
- `oDateFactura.Init`/logica de copiere valorile vin din `toDateAnterior` (parametrul), de exemplu
- `.listaid = toDateAnterior.id_vanzare` (`ofacturare_comun.vc2:387`) — **e exact precedentul pe
- care S3c il extinde la comanda/contract**, nu un al treilea canal implicit de adaugat la lista.
-- **`poDate` insusi nu e un canal de scurgere intre apeluri** — se creeaza cu `Createobject` la
- fiecare intrare in bucla lui `factureaza` (`ofacturare.prg:184`, doar `If Type('poDate') <> 'O'`,
- ceea ce e adevarat prima data si ramane fals doar in interiorul aceluiasi apel, la reintrarile
- bucla `Do While lnRaspuns = 6`) — deci nu poate purta stare intre doua clicuri distincte pe
- „Factureaza”.
-
-**Concluzie**: `goComanda` si `goContract` sunt singurele doua canale implicite relevante pentru
-decizia 12. Nu mai exista o a treia variabila de convertit odata cu ele.
-
-## 4. Semnatura propusa
-
-**`factureaza`** (`COMUN\programe\ofacturare.prg:81-82`), azi `Lparameters tnTip, toFactura`:
-
-```
-Lparameters tnTip, toFactura, toSursa
-```
-
-- **`toSursa`** — obiect, implicit `NULL` (nepasat de niciun apelant existent). Poarta **fie** un
- obiect cu forma lui `goComanda` (cand `tnTip = 3`), **fie** un obiect cu forma lui `goContract`
- (cand `tnTip IN (2, 6, 52)`) — exact aceeasi dualitate pe care codul de azi o rezolva deja prin
- ramificare pe `tnTip` in `oDateFactura.Init` (`:261` vs `:301`), deci nu introduce un tip nou de
- decizie, doar muta sursa valorii.
-- **Pozitia**: al treilea parametru, dupa `toFactura`, niciodata inaintea lui — la fel ca precedentul
- `V_TAXCODE`/`V_LOT` citat de tine: apelurile VFP sunt pozitionale, iar singurul mod sa nu rupi
- apelantii existenti e sa adaugi la coada, cu implicit. Toate cele ~31 de apeluri din inventarul S2
- care pasesc doar `tnTip` raman **neschimbate** — VFP completeaza automat parametrii nepasati la
- coada cu `.F.` (verificat comportamental: `Type()` pe un parametru nepasat intoarce `'L'` cu
- valoarea `.F.`, nu `'U'` — de tratat explicit in garda, vezi sectiunea 5).
-- **De ce nu inlocuieste `toFactura`**: `toFactura` inseamna „copiaza factura asta” (un document deja
- emis), `toSursa` inseamna „precompleteaza din documentul asta” (o comanda sau un contract inca
- nefacturat) — semantic distincte, si `copiere_factura` (`oproceduri_facturare.prg:150-153`) ar
- putea teoretic avea nevoie de amandoua simultan in viitor (copiere + realocare pe alt contract) —
- motiv suplimentar sa nu le contopesti intr-un singur parametru.
-
-**Constructorul `oDateFactura.Init`** (`ofacturare_comun.prg:223-224`), azi
-`Lparameters tnIdSet, tnTip`:
-
-```
-Lparameters tnIdSet, tnTip, toSursa
-```
-
-- Aceeasi regula de pozitionare: la coada. Singurul apelant azi e
- `Createobject("oDateFactura", lnIdSet, tnTip)` din `factureaza` (`ofacturare.prg:184`) — devine
- `Createobject("oDateFactura", lnIdSet, tnTip, toSursa)`. Nu exista alt loc din cod care
- instantiaza `oDateFactura` (cautare `Createobject("oDateFactura"` pe tot `COMUN`: un singur
- rezultat).
-
-## 5. Mecanismul de sursa de rezerva
-
-**Regula**: la fiecare din cele doua ramuri, se prefera `toSursa` daca a fost pasat ca obiect; daca
-nu, se cade pe globala, exact ca azi. Nu se schimba forma datelor citite (aceleasi campuri), doar
-sursa lor.
-
-```foxpro
-* ofacturare_comun.prg, oDateFactura.Init — inlocuieste liniile 261 si 301
-
-Local loSursa
-loSursa = Iif(Type('toSursa') = 'O', toSursa, Null)
-
-If INLIST(m.tnTip, 2, 6, 52) And (Type('loSursa') = 'O' Or Type('goContract') <> 'U')
- If Type('loSursa') <> 'O'
- loSursa = goContract
- Endif
- .id_client = loSursa.id_part
- .nume_client = loSursa.denumire
- * ... restul neschimbat, doar goContract -> loSursa
-Endif
-
-loSursa = Iif(Type('toSursa') = 'O', toSursa, Null) && re-evaluat, nu se refoloseste variabila de mai sus intre ramuri
-
-If tnTip = 3 And (Type('loSursa') = 'O' Or Type('goComanda') = 'O')
- If Type('loSursa') <> 'O'
- loSursa = goComanda
- Endif
- .id_client = loSursa.id_part
- * ... restul neschimbat, doar goComanda -> loSursa
-Endif
-```
-
-De ce doua evaluari separate ale lui `loSursa` (nu una singura la inceput): `toSursa` poarta o
-singura forma per apel (fie comanda, fie contract, niciodata amandoua — `tnTip` decide exclusiv
-care), dar garda trebuie sa verifice `tnTip` inainte sa presupuna forma, la fel ca azi. O variabila
-locala unica evita sa scrii `toSursa` de doua ori in tot blocul, fara sa schimbe logica.
-
-**Cum se stie cand se poate scoate globala** — criteriu verificabil, nu „cand se convertesc toti”:
-
-- **Pentru `goComanda`**: nu se poate scoate niciodata complet din `ROAFACTURARE`, pentru ca al
- doilea ei scriitor (`ocomenzi.vc2:2191-2207`, `AfterRowColChange`) nu are nicio legatura cu
- `factureaza` — exista doar pentru `but_factura1.Visible`. Criteriul realist: **linia de citire in
- `oDateFactura.Init` (`:301`) poate deveni neconditionata de fallback abia cand se confirma, prin
- `git_sync.ps1` + Grep, ca niciun apel la `factureaza(3, ...)` mai lasa `toSursa` nepasat** — adica
- se verifica apelantii lui `factureaza`, nu scriitorii globalei (care raman, pentru alt scop).
-- **Pentru `goContract`**: acelasi lucru, dar cu o observatie in plus — global-ul insusi
- (`Public goContract` in `roacontracte.prg:559-560`) **nu va disparea niciodata** cat timp exista
- formularul de contracte din ROACONTRACTE, care il foloseste ca buffer de editare, nu doar ca
- transport spre facturare. Criteriul de scos fallback-ul: **cand toate apelurile catre
- `factureaza(2/6/52, ...)`, in toate produsele, pasesc `toSursa` explicit** — verificabil cu
- aceeasi comanda `Select-String` ca in S2, aplicata pe `factureaza(2` / `factureaza(6` /
- `factureaza(52` in loc de `factureaza2`.
-- Pana atunci, fallback-ul ramane — el nu costa nimic in productie (o verificare `Type()` in plus),
- si e singura plasa de siguranta pentru cele ~31 puncte de intrare care nu au fost, nu vor fi, si
- nu trebuie sa fie convertite (nu au sursa de precompletat).
-
-## 6. Cele N copii ale fisierelor atinse — identice sau divergente?
-
-MD5 pe fiecare fisier, in cele 7 produse care au copie (`ROAFACTURARE`, `ROACONT`, `ROAGEST`,
-`ROAAUTO`, `ROAACNPRO`, `ROAIMOB`, `ROACONTRACTE`):
-
-| Fisier | Rezultat |
-|---|---|
-| `COMUN\programe\ofacturare.prg` (2662 linii) | **Identic pe toate cele 7** — un singur MD5 |
-| `COMUN\programe\oproceduri_facturare.prg` (2393 linii) | **Identic pe toate cele 7** — un singur MD5 |
-| `COMUN\clase\ocomenzi.vc2` (8301 linii) | **Identic pe cele 6** care il au (nu verificat separat in ROACONTRACTE, care nu are comenzi) |
-| `COMUN\programe\ofacturare_comun.prg` (2224 linii) | **Identic pe 6 din 7** — `ROAIMOB` diverge cu **exact o linie lipsa**: `:264`, `.cod_fiscal = ALLTRIM(NVL(goContract.cod_fiscal, ''))`, absenta din copia ROAIMOB (2223 linii). Restul fisierului, inclusiv blocul `goComanda`/`goContract` de la `:261-328`, e identic caracter cu caracter. |
-
-**Spre deosebire de `ofacturare.vc2` (7 copii, 4 variante MD5 distincte, citat ca precedent de
-comparat)**, fisierele atinse de S3c sunt aproape perfect sincronizate — un singur punct de drift,
-minor si izolat. Concluzie pentru propagare: modificarea din `ofacturare.prg` si
-`oproceduri_facturare.prg` se poate copia **caracter cu caracter** in toate cele 7 produse fara nicio
-adaptare. Modificarea din `ofacturare_comun.prg` se poate copia identic in 6 produse, dar **in
-ROAIMOB trebuie aplicata pe baza divergentei existente** (linia `cod_fiscal` lipseste deja acolo —
-o copiere oarba a diff-ului ar putea sa nu se aplice curat sau sa reintroduca acea linie fara sa fie
-intentionat; de verificat manual la sincronizare, nu doar copiat).
-
-`ferestre_contracte.vc2` (ROACONTRACTE) e specific produsului, nu are copii de sincronizat.
-
-## 7. Suprafata de regresie masurata
-
-**Fisiere care chiar se modifica** (5, plus 1 verificare de sincronizare):
-
-| # | Fisier | Ce se schimba | Cate copii de propagat |
-|---|---|---|---|
-| 1 | `COMUN\programe\ofacturare.prg:81-82` | semnatura `factureaza`, +`toSursa` | 7 (identice, copiere directa) |
-| 2 | `COMUN\programe\ofacturare_comun.prg:223-224, 261-328` | semnatura `Init`, +`toSursa`; ramurile de citire cu fallback | 7 (6 identice + ROAIMOB cu drift de reconciliat) |
-| 3 | `COMUN\programe\oproceduri_facturare.prg:119-141` | `facturare_contracte(tcTip, toSursa)`, `facturare_comenzi(toSursa)`, relay catre `factureaza(N, NULL, toSursa)` | 7 (identice, copiere directa) |
-| 4 | `COMUN\clase\ocomenzi.vc2:1580-1596` (`do_factura`) | `SCATTER NAME loComanda MEMO` (local, nu global) + `DO facturare_comenzi WITH loComanda IN oproceduri_facturare.prg` | 6 (identice, copiere directa) |
-| 5 | `ROACONTRACTE\Clase\ferestre_contracte.vc2:1538-1549` (`but_factura.Click`) | trimite `goContract` (sau o copie locala scatter-uita din randul curent) explicit ca al doilea parametru la `DO facturare_contracte WITH lcTip, goContract IN ...` | 1 (specific ROACONTRACTE) |
-
-**Apelanti care NU se modifica** (confirmat, nu presupus): toate cele ~31 de puncte de intrare din
-inventarul S2 (`Meniuri\politica.mn2`, `Meniuri\contracte.mn2`, `Meniuri\aviz_*.mn2`,
-`ofundal_facturare.vc2:883-905`) cheama `factureaza(N)` cu un singur argument sau
-`facturare_contracte`/`facturare_comenzi` fara sursa — al treilea parametru ramane implicit `NULL`,
-fallback-ul pe global preia (pentru cele care oricum nu aveau sursa reala, fallback-ul da acelasi
-rezultat ca azi: nimic de precompletat). **Inclusiv `ofundal_facturare.vc2:886-902` (Page2.Cw2/Cw3)
-raman neschimbate** — `Cw3` isi pastreaza `goComanda = ''` (devine redundant, dar inofensiv, odata ce
-`do_factura` trimite explicit; se poate curata separat, nu la aceasta poveste), `Cw2` ramane cum e.
-
-**Total: 5 fisiere reale de editat, in 4 continuturi distincte de modificare** (fisierele #1-#3 au
-acelasi continut in toate copiile lor), propagate in pana la 7 produse — mult sub suprafata unei
-modificari „de suita” tipice, pentru ca `ofacturare.prg`/`oproceduri_facturare.prg` sunt deja
-perfect sincronizate (sectiunea 6).
-
-## 8. Ordinea de executie, ca suita sa nu fie stricata niciun moment
-
-Spre deosebire de S2 (unde `factureaza2` nu avea alt apelant decat el insusi, deci risc de stricare
-aproape nul), aici **exista o fereastra in care semnaturile trebuie sa fie compatibile intre fisiere
-diferite** (`ofacturare.prg` cheama `oDateFactura::Init`, `oproceduri_facturare.prg` cheama
-`factureaza`) — ordinea trebuie sa garanteze ca niciun punct intermediar nu are un apelant cu
-semnatura veche impotriva unui apelat cu semnatura noua incompatibila. Pentru ca **toti parametrii
-noi sunt optionali, la coada**, riscul e de fapt mic — o semnatura veche care cheama o rutina noua
-functioneaza (parametrul lipsa devine implicit), problema ar aparea doar invers (rutina veche
-chemata cu un parametru in plus, care s-ar ignora silentios in VFP — tot fara eroare, dar fara
-efect). Deci ordinea de mai jos e despre corectitudine, nu despre a evita crash-uri:
-
-1. **`oDateFactura.Init`** (`ofacturare_comun.prg`) — adauga `toSursa`, muta logica de citire pe
- modelul din sectiunea 5. Se poate face si testa izolat: fara niciun apelant care sa paseze
- `toSursa` inca, comportamentul ramane identic cu azi (fallback pe global, mereu).
-2. **`factureaza`** (`ofacturare.prg`) — adauga `toSursa`, il paseaza la `Createobject("oDateFactura",
- lnIdSet, tnTip, toSursa)`. Inca niciun apelant nu paseaza `toSursa` — comportament neschimbat.
-3. **`oproceduri_facturare.prg`** — `facturare_contracte`/`facturare_comenzi` primesc `toSursa` si il
- relaeaza. Inca niciun apelant real nu il paseaza — comportament neschimbat.
-4. **Abia acum, apelantii reali**: `ocomenzi.vc2:do_factura` trimite `loComanda` explicit;
- `ferestre_contracte.vc2:but_factura.Click` trimite `goContract` explicit (in ROACONTRACTE). Din
- acest punct, comportamentul chiar se schimba (sursa vine din parametru, nu din citirea globalei),
- dar rezultatul trebuie sa fie identic — parametrul poarta exact aceleasi campuri pe care globala
- le avea.
-5. **Sincronizare in celelalte 6 produse**: pasii 1-3 se copiaza caracter cu caracter (identice,
- sectiunea 6), cu atentia speciala la ROAIMOB (drift de o linie). Pasul 4 pe partea de comenzi se
- copiaza si el (fisierul e identic in toate). Nu exista pas 4 de propagat pe partea de contract in
- afara de ROACONTRACTE (nu exista alt produs cu formular de contracte care sa scrie `goContract`).
-6. **Un singur produs se poate testa complet integrat de la sine**: ROAFACTURARE (pasii 1-4, partea
- de comanda). ROACONTRACTE cere o rulare separata (build propriu, sincronizat manual) pentru
- pasul 5 pe partea de contract — acelasi tip de limitare semnalata deja in S2 pentru
- `factureaza2`.
-
-## 9. Ce nu se poate testa headless
-
-- **Toate cele ~31+2 puncte de intrare sunt declansate din UI** (clic pe buton, `ON SELECTION BAR`
- in meniu) — niciunul nu are un test headless existent, la fel ca in S2.
-- **Testarea „parametrul castiga peste global” cere manipulare de sesiune**: singurul mod sa verifici
- ca `toSursa` are prioritate e sa populezi manual `goComanda`/`goContract` cu o valoare **diferita**
- de cea din parametru si sa confirmi ca documentul rezultat foloseste parametrul — asta cere fie
- cod de test care seteaza global-ul inainte de apel (posibil headless, dar artificial fata de
- fluxul real), fie o sesiune interactiva VFP cu comenzi tastate manual in fereastra de comenzi.
-- **Efectul colateral al `AfterRowColChange` (`ocomenzi.vc2:2199`) nu se poate simula headless** —
- harnessul `-A -T` nu declanseaza fiabil evenimente de grid (confirmat de precedentul din memorie
- „Coloanele de grid nu se materializeaza headless”), deci nu se poate verifica automat ca navigarea
- in grid tot suprascrie `goComanda` dupa modificare (comportament care ramane neschimbat, dar
- trebuie confirmat vizual, nu presupus).
-- **ROACONTRACTE nu poate fi testat din arborele de lucru ROAFACTURARE** — cere build si rulare
- separata, cu propriul executabil si propria sincronizare a `ofacturare.prg`/`ofacturare_comun.prg`
- /`oproceduri_facturare.prg` (nu sunt acelasi fisier fizic, sunt copii).
-- **Rezultatul final** (facturare emisa cu antetul corect precompletat din comanda/contract) se
- verifica doar prin continutul lui `crsfactura`/`VANZARI`/formularul de antet, vizual sau prin
- interogare Oracle read-only dupa emitere — nu exista assert automat de facut.
-
-## 10. Riscuri si ce ramane de decis de Marius
-
-**Riscuri**:
-
-- **Cel mai probabil sa se strice**: garda `Type('loSursa') = 'O' Or Type('goContract') <> 'U'` din
- sectiunea 5 — daca se scrie gresit (de exemplu `And` in loc de `Or`), fallback-ul pe global s-ar
- rupe silentios pentru toti apelantii care inca nu au fost convertiti, fara nicio eroare vizibila
- (`oDateFactura` ar porni pur si simplu fara precompletare). Se testeaza explicit pe cel putin un
- apel neconvertit (orice `factureaza(N)` cu un singur argument, tip 1) dupa modificare.
-- **Al doilea cel mai probabil**: parametrul nou nepasat trebuie verificat `Type('toSursa') = 'O'`,
- nu `Type('toSursa') <> 'U'` — un parametru VFP nepasat nu e `'U'` (asta e pentru variabile
- nedeclarate), ci `'L'` cu valoarea `.F.` implicita a lui `LPARAMETERS`. O garda gresita
- (`<> 'U'`) ar trece mereu adevarat si ar incerca sa citeasca `.id_part` de pe `.F.`, eroare de
- rulare imediata la primul apel neconvertit. **De verificat cu un test minimal inainte de a atinge
- fisierele reale** — nu presupune, verifica comportamentul `Type()` pe un parametru nepasat intr-un
- `.prg` de proba.
-- **ROACONTRACTE, singurul apelant real din alt produs** — acelasi risc semnalat in S2: netestabil
- din acest arbore de lucru, cere confirmare manuala separata.
-- **Drift-ul de o linie din `ofacturare_comun.prg` in ROAIMOB** — o copiere mecanica a diff-ului ar
- putea esua silentios sau reintroduce linia lipsa fara sa fie intentia — de aplicat manual acolo,
- nu prin copy-paste orb.
-- **`Cw3.do_actiune` (`ofundal_facturare.vc2:900`) ramane cu `goComanda = ''` redundant** dupa
- conversia lui `do_factura` — nu e o problema (ramane inofensiv), dar merita mentionat explicit ca
- „lasat asa, intentionat” in codul livrat, ca sa nu para o omisiune la revizuirea diff-ului.
-
-**Ce ramane de decis de Marius**:
-
-1. **Forma lui `toSursa`**: ramane duck-typing pe obiect scatter (ca azi), sau se formalizeaza o
- clasa cu doua forme (`oSursaComanda`/`oSursaContract`)? Recomandare: ramane duck-typing — nu
- schimba nimic functional, adauga doar o clasa noua de intretinut pentru un beneficiu marginal la
- aceasta poveste.
-2. **Se face si conversia partii de comanda si cea de contract in acelasi commit, sau separat?**
- Ambele ating exact aceleasi trei fisiere comune (`ofacturare.prg`, `ofacturare_comun.prg`,
- `oproceduri_facturare.prg`) — separarea nu reduce suprafata de regresie pe fisierele comune, doar
- amana testarea reala pe ROACONTRACTE. Recomandare: **un singur commit**, cu testare manuala pe
- ambele produse inainte de a-l considera gata.
-3. **Se curata acum redundanta `goComanda = ''` de la `Cw3` (sectiunea „Riscuri”), sau se lasa pentru
- o poveste ulterioara de curatenie?** Nu afecteaza corectitudinea — decizie de stil, nu de
- comportament.
-4. **Criteriul de „gata” rescris** (inlocuieste formularea din plan, linia 1861-1862):
- - *Structural*: `Select-String -Path ofacturare.prg,ofacturare_comun.prg,oproceduri_facturare.prg
- -Pattern 'toSursa'` gaseste parametrul in toate cele trei fisiere, in toate cele 7 produse care
- au copii, cu semnatura identica.
- - *Comportamental, cale convertita*: facturarea pornita din `ocomenzi.vc2:do_factura` cu
- `goComanda` populat manual cu **alta** comanda decat cea trimisa prin `toSursa` produce
- documentul corespunzator parametrului, nu globalei — testat manual, cu global-ul deliberat
- „murdar” dintr-o navigare anterioara in grid.
- - *Comportamental, cale neconvertita*: oricare din cele ~31 de apeluri care trimit doar `tnTip`
- produce acelasi document ca inainte de modificare (fallback pe global, sau fara precompletare
- acolo unde nu exista global de citit).
- - *ROACONTRACTE*: facturarea din `but_factura.Click` cu contractul trimis explicit prin
- `toSursa` produce acelasi rezultat ca azi (precompletare identica), verificat manual pe build
- separat.
-
----
-
-## Ce nu s-a putut stabili si de ce
-
-- **Continutul exact al obiectului `loComanda`/`goContract` scaturat** nu a fost comparat camp cu
- camp intre ce citeste azi `oDateFactura.Init` si ce ar contine un `SCATTER` facut in afara
- contextului `crsComenzi`/`cContracte` curent — presupunerea (rezonabila, dar neverificata pe date)
- e ca structura cursorului nu se schimba intre cele doua puncte de scatter.
-- **Daca exista alte produse din suita (dincolo de cele 7 verificate) care au propriile copii ale
- `ofacturare.prg`/`ofacturare_comun.prg`/`oproceduri_facturare.prg`** — cautarea s-a limitat la
- produsele numite explicit in sarcina; alte ~30 de produse mentionate in S2 ca avand copii ale
- `ofacturare.prg` (ROARETAIL etc.) nu au fost verificate pentru `goComanda`/`goContract` la aceasta
- poveste.
-- **Testarea reala pe ROACONTRACTE** nu a fost efectuata (read-only, fara rulare de cod) — doar
- confirmata structura codului sursa.
-
-## Bug-uri semnalate, nereparate
-
-Niciunul nou — cercetarea a confirmat un defect de simetrie deja semnalat in plan (L.3), l-a
-verificat pe cod pana la verdictul „inert azi in ROAFACTURARE” (sectiunea 2), si nu a gasit alte
-probleme in fisierele atinse.
diff --git a/docs/cercetare/s4_cautare_articole_server.md b/docs/cercetare/s4_cautare_articole_server.md
deleted file mode 100644
index 55e8887..0000000
--- a/docs/cercetare/s4_cautare_articole_server.md
+++ /dev/null
@@ -1,482 +0,0 @@
-# Cercetare — proiectare S4: cautarea articolelor pe server, in linie
-
-Investigatie READ-ONLY pentru povestea **S4** din `docs\plan_13_unificare_formular_facturare.md:1865-1874`,
-plus sectiunea `### C. Incarcarea articolelor — de ce dureaza si ce inlocuieste` (`:589-614`).
-Fara editari de cod, fara `git_sync.ps1`/`txt2vcx.ps1`, fara commit. `COMUN\clase\ofacturare_comun.vc2`
-si `COMUN\programe\ofacturare_editare.prg` (perimetrul #6) doar citite, nu atinse. Pe Oracle doar
-`SELECT`, prin exportul `PACK_FACTURARE` de pe disc — nu s-a rulat nimic pe server.
-
-## Verdict (rezumat)
-
-Mecanismul de inlocuire propus in plan **exista deja, dar e un prototip la jumatate**:
-`grd_factura.cCodMat.cboCodmat` / `cCboDenumire` (`ofacturare.vc2:16751-16797`, wiring la
-`:19288-19334`) cauta pe server prin `combosql` si scriu `codmat`/`denumire`/`id_articol` in
-`crsfactura` — dar **nu scriu nimic altceva**, pentru ca sursa lor (`vnom_articole`) nu are pret,
-TVA, valuta, `id_pol`, `gestionabil`. Asta confirma exact ce zice planul la punctul C: partea Oracle
-de facut e o **varianta filtrata pe articol a celor cinci cursoare de facturare**, nu o cautare noua.
-
-Descoperirea care schimba proiectarea fata de textul din plan: **`crsarticole` nu e doar sursa de
-populare a gridului — e un registru al cantitatii ramase de facturat**, citit si scris de
-`do_adauga_tot`, `do_sterge` si `do_scrie_factura` pentru toate tipurile cu document sursa (comanda,
-aviz, contract-lista-de-preturi). Stergerea unei linii **reface** cantitatea in `crsarticole`
-(`:14640-14669`), iar la scriere se face `Calculate Sum(cantitate) To lnCantitateRamasa` peste
-`crsarticole` ca sa se decida daca se inchide automat comanda/avizul (`:14303-14311`, `:14334-14338`).
-Asta inseamna ca **incarcarea in masa nu poate disparea pentru aceste tipuri**, indiferent de S4 —
-nu doar pentru ca planul a decis sa pastreze "adauga tot", ci pentru ca bookkeeping-ul de cantitate
-ramasa e cablat direct pe cursorul incarcat. S4 se aplica deci curat doar pe ramurile de **lista de
-preturi** (`cursor_preturi`, plus jumatate din `cursor_contract` si `cursor_gestiune`) — vezi punctul 7.
-
-A doua descoperire: calea de scriere a pretului la nivel de linie (`adauga_articol_factura`,
-verificata separat in S10, `docs\cercetare\s10_pret_rederivat.md`) **primeste deja pretul ca
-parametru** in loc sa-l re-deriveze — exact precedentul pe care trebuie sa-l urmeze si varianta
-filtrata: cauta pretul o singura data, la alegerea liniei, si il transmite mai departe neschimbat.
-
-## 1. Inventarul celor cinci cursoare Oracle
-
-Sursa: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (corpul
-pachetului; liniile de mai jos sunt pe corp, `:2138+`, nu pe spec `:335+` — offset **+17** fata de
-citatele vechi din plan, confirmat si in S10).
-
-### 1.1 `cursor_preturi` — lista de preturi, ramura principala (`:2138-2644`)
-
-```
-PROCEDURE cursor_preturi(V_DATA_CURS IN DATE, V_TIP IN NUMBER, V_ID_VALUTA IN NUMBER,
- V_ID_GESTIUNE_INIT IN NUMBER, V_LUNA IN NUMBER, V_AN IN NUMBER,
- V_ID_UTIL IN NUMBER, V_ID_SUCURSALA IN NUMBER,
- V_CURSOR OUT cursor_facturare)
-```
-
-**Fara filtru pe articol** — semnatura n-are niciun parametru de cod/denumire. Ramuri pe `V_TIP`
-(`CASE`, `:2159-2643`):
-
-| Ramura | Cand | Sursa randurilor | Observatie |
-|---|---|---|---|
-| `V_TIP = 45` | restaurant | `utilizatori_rol_intern` -> `politici_grupuri` -> `crm_politici_preturi` -> `crm_politici_pret_art` -> `nom_articole`, plus `curs`/`nom_valute` | fara filtru de stoc, `cantitate` fixa la 1 (`:2193`) |
-| `V_TIP IN (1,2)` | factura in lei | acelasi lant de politici, plus `LEFT JOIN` pe `STOC` agregat pe gestiunile utilizatorului | `WHERE` final filtreaza pe stoc > 0 sau `RF_FACTURARE_FARA_STOC` (`:2387-2388`) |
-| `V_TIP IN (5,6,10,52)` | factura in valuta | `FACT_VPRETURI_UTILIZATOR` (view precalculat, nu politici brute) + `STOC` + `CURS` | `WHERE A.ID_UTIL = V_ID_UTIL AND ((A.ID_VALUTA = V_ID_VALUTA AND A.IN_VALUTA=1) OR A.ID_POL = politica_stoc)` (`:2461-2462`) |
-| `V_TIP = 7` | credit note | `FACT_VPRETURI_UTILIZATOR`, filtrat suplimentar `NVL(A.nota_discount,0)=1` (`:2538`) | doar articole de discount |
-| `ELSE` (aviz, tip implicit) | orice alt tip | `FACT_VPRETURI_UTILIZATOR`, fara filtrul de valuta din ramura 5/6/10/52 | ramura cea mai generala |
-
-Coloane comune returnate (uniforme pe toate ramurile, ceea ce conteaza pentru mapare — punctul 6):
-`id_c, id_articol, lot, serie, id_pol, id_valuta, nume_lista_preturi, discount_unitar,
-discount_unitar_val, codmat, codbare, denumire, um, gestionabil, cantitate, proc_tvav,
-preturi_cu_tva, curs, multiplicator, pret, pret_val, tip_valuta, nume_val` (+ `modificabil`,
-`id_gestiune`, `cont` doar pe ramura restaurant).
-
-Apeleaza intai `initializeaza_facturare`, `completare_politica_stoc` si
-**`verifica_cursuri_valute(V_DATA_CURS, V_ID_UTIL)`** (`:2149-2153`) — validare **neconditionata**
-a cursurilor pentru toate valutele din listele de preturi ale utilizatorului, indiferent de articolul
-cautat. Relevant pentru S4d (`-20005`).
-
-### 1.2 `cursor_contract` — factura/aviz pe contract (`:2646-2950`)
-
-```
-PROCEDURE cursor_contract(V_DATA_CURS, V_TIP, V_ID_VALUTA, V_LISTAID, V_ID_GESTIUNE_INIT,
- V_LUNA, V_AN, V_ID_UTIL, V_ID_SUCURSALA,
- V_ID_AGENT OUT, V_NUME_AGENT OUT,
- V_CURSOR OUT cursor_facturare, V_CURSOR2 OUT cursor_facturare)
-```
-
-**Doua cursoare de iesire.** `V_CURSOR2` (`:2718-2938`) e specific contractului: `UNION ALL` intre
-(a) articole cu `OPT_FACTURARE = 3` din `CTR_ARTICOLE` si (b) rate din `CTR_SCADENTAR` pentru
-`OPT_FACTURARE IN (1,2)`, cu `id_articol = NULL` pe randurile de rata — filtrate pe
-`V_LISTAID` (lista de `id_ctr`) prin `charn2collection`. La final (`:2940-2948`) **cheama
-`cursor_preturi` cu aceiasi parametri** si scrie rezultatul in `V_CURSOR` — deci jumatate din
-`cursor_contract` e literalmente `cursor_preturi`.
-
-In VFP, cele doua cursoare de iesire ajung (observat pe cod, nu documentat explicit in `goExecutor`)
-in `crsarticole` (=`V_CURSOR`, lista de preturi) si `crsarticole1` (=`V_CURSOR2`, liniile contract +
-rate) — vezi `ofacturare.vc2:13778` (`lcCursorStoc = Iif(poArticol.opt_facturare = 0, [crsarticole],
-[crsarticole1])`) si `Destroy` (`:12804-12811`) care inchide ambele.
-
-**Randurile de rata nu au `id_articol`** — nu pot fi gasite printr-o cautare cod/denumire; raman
-legate de gridul `crsarticole1` existent (`grd_contracte`), bounded de numarul de rate ale
-contractului, nu de catalog. Vezi punctul 7.
-
-Valideaza cursurile valutare **doar** pentru valutele prezente in `CTR_SCADENTAR`/`CTR_ARTICOLE` ale
-contractelor din `V_LISTAID` (`:2679-2716`) — spre deosebire de `cursor_preturi`, care valideaza tot
-ce are utilizatorul in politici. Filtru deja ingust pe sursa, dar tot pe tot contractul, nu pe
-articol.
-
-### 1.3 `cursor_comanda` — factura/aviz pe comanda (`:2952-3171`)
-
-```
-PROCEDURE cursor_comanda(V_DATA_CURS, V_TIP, V_LISTAID, V_ID_UTIL, V_CURSOR OUT cursor_facturare)
-```
-
-`V_LISTAID` e **un singur `id_comanda`** (`TO_NUMBER(V_LISTAID)`, `:2963` — nu o lista, desi
-parametrul se numeste la fel ca la contract/avize). Doua ramuri identice ca forma (`V_TIP <= 20` =
-factura, altfel aviz, `:2994-3170`), ambele pe `COMENZI_ELEMENTE` filtrat `WHERE A.ID_COMANDA =
-V_ID_COMANDA` (`:3078`, `:3166`) — **deja filtrat pe un singur document sursa**, nu pe tot catalogul.
-`LEFT JOIN` cu suma cantitatilor deja facturate din `VANZARI_DETALII` pe acelasi `ID_COMANDA`
-(`:3060-3068`) calculeaza `cantitate` ca **ramas de facturat**, nu cantitatea comandata bruta —
-exact sursa pentru bookkeeping-ul de "adauga tot" / stergere de la punctul urmator.
-
-### 1.4 `cursor_avize` — factura din avize (`:3703-3874`)
-
-```
-PROCEDURE cursor_avize(V_LISTAID, V_ID_UTIL, V_DISCOUNT OUT NUMBER, V_CURSOR OUT cursor_facturare)
-```
-
-`V_LISTAID` = lista de `id_vanzare` (avize sursa), separate prin virgula. O singura interogare,
-fara `CASE` pe tip — agrega `VANZARI_DETALII` pe cheie compusa (articol, pol, lot, serie, discount,
-TVA, gestiune, cont, pret...) si scade ce a fost deja facturat din `VANZARI_CANTITATI`
-(`WHERE A.CANTITATE <> NVL(B.CANTITATE, 0)`, `:3871`) — acelasi tipar "ramas de facturat" ca la
-comanda. **Nu are ramuri pe `V_TIP`** — planul o citeaza ca exemplu de "aceleasi ramuri pe tip", dar
-real e cea mai simpla dintre cele cinci: un singur `SELECT`.
-
-### 1.5 `cursor_gestiune` — transfer intre subunitati pe lista de preturi (`:4158-4310+`)
-
-```
-PROCEDURE cursor_gestiune(V_DATA_CURS, V_ID_POL, V_ID_GESTIUNE, V_LUNA, V_AN,
- V_ID_UTIL, V_ID_SUCURSALA, V_CURSOR OUT cursor_facturare)
-```
-
-Foloseste `V_ID_POL` **fix** (nu politica derivata din utilizator ca la `cursor_preturi`), pe
-`STOC` filtrat `ID_GESTIUNE = V_ID_GESTIUNE` `JOIN` `CRM_POLITICI_PRET_ART WHERE ID_POL = V_ID_POL`
-(`:4266-4280`) — deja restrans la o singura gestiune si o singura politica, dar tot fara filtru pe
-articol; `GROUP BY` pe articol agrega stocul.
-
-## 2. De unde sunt executate; cine consuma `crsarticole`
-
-**Executia:** un singur loc, `ofacturare.prg:266-311` (`factureaza`), rutare pe `tnTip` (punct de
-plecare confirmat, `Do Case` la `:266-308`) -> `goExecutor.oExecute(lcSqlCursor, [crsarticole])`
-(`:310-311`). Acelasi tipar apare a doua oara in `factureaza2` (`ofacturare.prg:824+`, ramura
-`frm_facturare_articole2`, prototipul).
-
-**Consumatorii `crsarticole` in perimetrul S4** (`frm_facturare_articole`, `ofacturare.vc2:11xxx-15300`;
-lista completa via `vfp_symbols -Grep 'crsarticole\b' -CodeOnly`):
-
-| Metoda | Linii | Ce face cu `crsarticole` | Ramane dupa S4? |
-|---|---|---|---|
-| `Destroy` | `12804-12811` | inchide cursorul | da, neschimbat |
-| `do_adauga_articol` | `12813-13167` | citeste **un rand ales** (`Scatter Name poArticol`), il scrie in `crsfactura` | **inlocuit** de randul intors de cautarea pe server, pe ramurile de lista de preturi — vezi punctul 7 |
-| `do_adauga_tot` | `13169-13198` | `Scan` peste tot cursorul, cheama `do_adauga_articol` pe fiecare rand | **pastrat neschimbat**, dar numai pe tipurile cu document sursa |
-| `do_cauta` | `13566-13593` | filtru client-side (`Set Filter`) peste cursorul deja incarcat, dupa text tastat in `txtArticole`/`txtCodmat` si politica aleasa | **dispare** pe ramurile de lista de preturi — inlocuit de `combosql` |
-| `do_scrie_factura` | `14301-14338` | `Calculate Sum(cantitate) To lnCantitateRamasa` peste `crsarticole`, decide daca se inchide comanda/avizul sursa (`pnParametruAditional`) | **pastrat neschimbat** — vezi verdictul |
-| `do_sterge` | `14608-14669` | la stergerea unei linii din `crsfactura`, **reface** cantitatea in `crsarticole`/`crsarticole1` (`Replace cantitate With cantitate + poArticol.cantitate`) | **pastrat neschimbat** pe tipurile cu bookkeeping; pe lista de preturi nu exista azi replace-back real (cantitatea nu scade la adaugare pe acele tipuri — stocul se verifica separat, prin `cursor_gestiuni_articol*`) |
-| `do_modifica` | `13778` | alege `crsarticole` sau `crsarticole1` dupa `opt_facturare` pentru verificare stoc | pastrat, tine de gestiunea aleasa la editarea unei linii deja adaugate |
-| `cb_politici_preturi.InteractiveChange` | `15647-15658` | cheama `do_cauta()` (filtru client-side) | **dispare** — pe varianta noua, schimbarea politicii devine parametru al cautarii pe server (`id_pol` in `WHERE`), nu filtru local |
-| `KeyPress` (navigare grid) | `15463-15486` | navigare in cursor la taste sageata | **dispare** pe ramurile fara grid de sus |
-
-`frm_facturare_articole2` (prototipul, `:17xxx-18xxx`) are exact aceeasi structura pe
-`do_adauga_articol` / `do_adauga_tot` / `do_scrie_factura` / `do_sterge` — nu difera in aceasta
-privinta.
-
-**Concluzie pentru cat se poate scoate:** `do_cauta` si filtrul din `cb_politici_preturi` dispar
-integral (inlocuite de cautarea pe server). `do_adauga_articol` isi schimba sursa randului (de la
-`Scan` in cursorul local la randul ales de `combosql`), dar restul lui (verificare stoc, alegere
-gestiune via `cursor_gestiuni_articol*`, scriere in `crsfactura`) **nu se schimba** — vezi punctul 6.
-`do_adauga_tot`, `do_sterge` (partea de bookkeeping) si `do_scrie_factura` (`lnCantitateRamasa`)
-**nu pot fi scoase** cat timp `crsarticole` ramane sursa lor de adevar pentru "cat a mai ramas" —
-motiv suplimentar, nu doar UX, pentru care "adauga tot" ramane cablat pe incarcare in masa acolo
-unde exista document sursa.
-
-## 3. Cat costa azi incarcarea, pe forma interogarii (nu pe timpi masurati — decizia 31)
-
-**`cursor_preturi` (ramurile 1/2 si generala) nu are niciun filtru pe articol** — semnatura n-are
-parametru de cod/denumire (`:2138-2146`). Rezultatul e **intreg catalogul accesibil utilizatorului**:
-`utilizatori_rol_intern` -> `politici_grupuri` -> `crm_politici_preturi` (toate politicile active la
-data cursului) -> `crm_politici_pret_art` (toate liniile de pret ale acelor politici) -> `nom_articole`.
-Numarul de randuri creste cu produsul dintre "cate politici de pret vede utilizatorul" si "cate
-articole are fiecare politica" — nu cu numarul de articole cautate, care e de regula 1.
-
-Trei surse structurale de cost, vizibile direct in forma interogarii, nu masurate:
-
-1. **`LEFT JOIN` pe `STOC` agregat** (`:2359-2378`, ramura 1/2) — subquery cu `GROUP BY ID_ARTICOL`
- peste tot stocul lunii curente, pe toate gestiunile la care utilizatorul are drept, recalculat la
- fiecare deschidere de formular, indiferent daca utilizatorul cauta un singur articol.
-2. **`FACT_VPRETURI_UTILIZATOR`** (ramurile 5/6/10/52 si 7 si aviz) e un view, nu un tabel — planul
- nu detaliaza corpul lui aici (ar fi o cercetare separata), dar fiind sursa pentru "toate preturile
- vizibile utilizatorului", are aceeasi forma: cost proportional cu marimea catalogului, nu cu
- cautarea.
-3. **`verifica_cursuri_valute`** (`:2153`, chemata necondiționat la fiecare apel) valideaza cursul
- pentru **toate** valutele din politicile utilizatorului, nu doar valuta articolului cautat —
- cost fix per deschidere, independent de ce se cauta.
-
-Concluzia structurala: interogarea de azi calculeaza raspunsul pentru "orice articol ar putea alege
-utilizatorul", cand formularul are nevoie doar de "articolul pe care tocmai l-a tastat". Filtrarea pe
-`id_articol`/`codmat`/`denumire` reduce fiecare din cele trei surse la un numar de randuri marginit
-de cate politici de pret contin acel articol (de regula 1, rar cateva), nu de marimea catalogului.
-
-## 4. Proiectarea variantei filtrate, cursor cu cursor
-
-Toate cinci sunt proceduri PL/SQL in `PACK_FACTURARE`, apelate direct din VFP prin
-`{call pack.proc(...)}` + `goExecutor.oExecute`, fara view intermediar si fara strat ORM — deci
-minimul de schimbare e **acelasi tipar**: o procedura noua (sau o supraincarcare cu parametru
-suplimentar) in acelasi pachet, apelata din acelasi loc (`ofacturare.vc2`, metoda nou-introdusa pe
-`combosql`, nu din `ofacturare.prg`, care ramane neschimbat — el tot incarca varianta "in masa"
-acolo unde ramane necesara).
-
-**Alegere de proiectare, nu fapt verificat:** supraincarcare (aceeasi denumire, parametru nou
-opțional `V_FILTRU_COD IN VARCHAR2 DEFAULT NULL` / `V_FILTRU_DEN IN VARCHAR2 DEFAULT NULL`) e mai
-sigura decat o procedura noua, pentru ca **garanteaza** aceleasi ramuri de `CASE`, acelasi `JOIN`,
-aceeasi logica de rotunjire — orice divergenta viitoare intre "cursor complet" si "cursor filtrat" ar
-fi un bug de sincronizare greu de prins. Cu supraincarcare, filtrul se adauga o singura data, in
-`WHERE`-ul final al fiecarei ramuri, nu in logica de business.
-
-| Cursor | Ce se adauga | Unde (linia `WHERE`/`CASE` care primeste filtrul) |
-|---|---|---|
-| `cursor_preturi` | `AND (V_FILTRU_COD IS NULL OR C.CODMAT LIKE V_FILTRU_COD) AND (V_FILTRU_DEN IS NULL OR UPPER(C.DENUMIRE) LIKE UPPER(V_FILTRU_DEN))` — pe alias-ul articolului, `C` pe patru din cinci ramuri, `A` pe ramurile cu `FACT_VPRETURI_UTILIZATOR` | dupa `WHERE` existent, pe fiecare din cele 5 ramuri (`:2264`, `:2387-2388`, `:2464-2465`, `:2540-2541`, `:2640-2641`) — 5 locuri, nu unul |
-| `cursor_contract` | acelasi filtru pe `V_CURSOR` (delegat catre `cursor_preturi`, gratuit); pe `V_CURSOR2` filtrul se adauga in `UNION ALL`-ul de la `:2752` (partea cu `id_articol`), **nu** pe partea de rate (`id_articol IS NULL` — nu se pot filtra pe cod, raman needitate de filtru) | `:2825` (join articol) + propagare in `WHERE`-ul de la `:2819` |
-| `cursor_comanda` | filtru pe `C.CODMAT`/`C.DENUMIRE` in `WHERE A.ID_COMANDA = V_ID_COMANDA` (`:3078`, `:3166`) — **dar nu are sens sa se filtreze**: cf. punctul 7, comanda ramane pe calea "adauga tot" | de proiectat doar daca decizia de la punctul 7 se schimba |
-| `cursor_avize` | idem — nu are sens, acelasi motiv | idem |
-| `cursor_gestiune` | filtru pe `C.CODMAT`/`C.DENUMIRE` in interogarea de la `:4234-4237`, inainte de `GROUP BY` | `:4266-4293` |
-
-**Parametrii care raman identici** pe varianta filtrata: `V_DATA_CURS`, `V_TIP`, `V_ID_VALUTA`,
-`V_ID_GESTIUNE_INIT`, `V_LUNA`, `V_AN`, `V_ID_UTIL`, `V_ID_SUCURSALA` — tot ce vine din `poDate` /
-sesiune la deschiderea formularului, nu se recalculeaza per cautare. Doar filtrul de text e nou, plus
-(pentru `cursor_preturi` in noua utilizare) eventual `V_ID_POL` daca utilizatorul a ales explicit o
-lista de preturi in combo-ul `cb_politici_preturi` — azi acel combo doar filtreaza local
-(`ofacturare.vc2:15647-15658`, comentat inlocuit cu `do_cauta()`); pe varianta noua devine parametru
-real al interogarii.
-
-**Ce nu se poate verifica din cod, ramane de decis de Marius:** daca filtrul pe `codmat` foloseste
-`LIKE` "incepe cu" (ca `combosql` de azi, `nCharCountBegin`/cautare incrementala) sau match exact la
-alegerea din lista — combosql de azi face amandoua (tastare = "incepe cu" pe server, alegere din
-lista = valoare exacta), deci varianta cea mai apropiata de comportamentul actual e sa pastreze
-acelasi tipar: interogarea filtrata se cheama la fiecare tastare (ca azi, `RefreshData`), iar
-valoarea finala aleasa vine din randul deja adus, nu dintr-o interogare separata "exact match".
-
-## 5. `combosql` — contract si exemple reale
-
-**Clasa:** `combosql AS combobox`, `COMUN\clase\_cb_base.vc2:519-843`. Nu e specifica facturarii —
-traieste in biblioteca comuna a suitei, dar cautarea nu a gasit nicio alta utilizare, nici in
-`ROAFACTURARE`, nici in `COMUNROA`/`ROAGEST` (`grep -rn "AS combosql WITH"` — zero potriviri in afara
-`ofacturare.vc2:16751/16785/16861`, cele trei coloane ale gridului prototip). **Singurul exemplu real
-de folosire e chiar prototipul din plan** — nu exista alt loc in suita de copiat.
-
-**Proprietati relevante** (`_memberdata`, `:560-575`):
-
-| Proprietate | Rol |
-|---|---|
-| `csourcesql` | `SELECT` fara `WHERE`/`ORDER BY` — baza interogarii |
-| `csourcewhere` | conditia `WHERE` fixa (ex. `inactiv = 0`) |
-| `csourceorder` | `ORDER BY`, implicit `pfieldactiv` |
-| `pcursorname` | numele cursorului cu rezultatele |
-| `pfieldactiv` | campul dupa care se cauta si se afiseaza |
-| `psecondfield` | al doilea camp de cautare (optional) |
-| `ncharcountbegin` | cate caractere minim inainte sa porneasca interogarea pe server |
-| `llimittolist` | daca valoarea trebuie sa existe in lista |
-
-**Mecanismul** (`refreshdata`, `:796-830`): construieste
-`SELECT ... FROM (cSourceSql) WHERE (cSourceWhere) AND (pFieldActiv LIKE ?pcValue [OR psecondfield
-LIKE ?pcValue]) ORDER BY ...`, cu `?pcValue` = `cSearchString + '%'` (incepe cu) sau
-`'%'+cSearchString+'%'` (contine, la Ctrl+Enter) si il executa prin
-**`goExecutor.oExecuta`** (`selectdata`, `:832-840`) — acelasi executor folosit peste tot in suita
-pentru apeluri Oracle, deci **niciun mecanism nou de transport**, doar un SQL nou de trimis.
-`KeyPress` (`:610-776`) gestioneaza incremental tastarea: la fiecare caracter tastat re-executa
-`RefreshData(1)` daca lungimea depaseste `nCharCountBegin`.
-
-**Contractul de legare la o coloana de grid**, dedus din prototip (`ofacturare.vc2:16751-16762` +
-`:19288-19306`):
-
-1. se adauga ca `CurrentControl` al coloanei (`Column1.CurrentControl = "cCboDenumire"`, `:16621`);
-2. `ControlSource` leaga afisarea de campul din cursorul de linii (`crsFactura.codmat`, `:16754`);
-3. **evenimentul de reactie e `LostFocus`, nu `Valid` sau `InteractiveChange`** — abia la parasirea
- celulei se scriu campurile in cursorul de linii, cu paza `If this.Value <> thisform.cOldValue`
- (setat in `When`, `:19308-19310`) ca sa nu se rescrie fara motiv;
-4. `LostFocus` de azi scrie **doar** campurile pe care le are `vnom_articole`: `codmat`, `denumire`,
- `id_articol` (`:19293`) — nimic despre pret, TVA, valuta. **Aici se opreste prototipul azi**; tot
- ce trebuie adaugat pentru S4 e sa inlocuiasca `crsCodmat`/`crsDenumire` (rezultatul din
- `vnom_articole`) cu rezultatul cursorului Oracle filtrat de la punctul 4, care are toate coloanele,
- si sa extinda `REPLACE`-ul de la `:19293`/`:19317` cu restul campurilor din tabelul de la punctul 6.
-
-**Ce nu ofera azi `combosql` si trebuie adaugat, nu doar copiat:** `csourcesql` e un `SELECT`
-static definit in `.vcx` la design-time, nu poate primi parametrii dinamici ai documentului curent
-(`poDate.zi_curs`, `poDate.tip`, `poDate.id_valuta`...) direct in proprietate. Pentru cursorul
-Oracle cu 8 parametri, populate din `poDate`/sesiune, `csourcesql`/`csourcewhere` trebuie construite
-dinamic in `Init` sau la schimbarea documentului (nu sunt string-uri fixe ca azi), sau — alternativa
-mai simpla — `refreshdata`/`selectdata` se suprascriu punctual pe instanta din grid, ca sa apeleze
-`{call pack_facturare.cursor_preturi_filtrat(...)}` in loc de `SELECT ... FROM (cSourceSql)`. A doua
-varianta pastreaza restul mecanismului (`KeyPress`, incremental, `LostFocus`) neschimbat si e
-schimbarea minima — de confirmat cu Marius, nu o certitudine de cod.
-
-## 6. Maparea camp-cu-camp
-
-Sursa cea mai fiabila pentru "ce completeaza azi `crsarticole` in linie" nu e cursorul Oracle brut, ci
-`Gather Name poArticol Fields Like ...` din `do_adauga_articol` (`ofacturare.vc2:12945-12957`,
-identic pe `frm_facturare_articole2` la `:17226+`) — acolo se vede exact ce trece din randul scanat
-in `crsfactura`.
-
-| Camp in `crsfactura` | Vine din `crsarticole` (coloana cursorului Oracle) | Pe varianta filtrata |
-|---|---|---|
-| `id_articol`, `codmat`, `codbare`, `denumire`, `um` | direct din cursor | identic — filtrul e chiar pe aceste coloane |
-| `pret_achizitie` | **nu** din `crsarticole` — vine din `poArtLista`/`crsartselectate` (rezultatul lui `cursor_gestiuni_articol*`, ales dupa `crsarticole`), nu din cursorul de lista de preturi | **neschimbat** — pasul e deja separat azi, ramane separat |
-| `id_pol` | direct (`crsarticole.id_pol`) | identic |
-| `Cont` | direct (`crsarticole.cont`, doar ramura restaurant o are explicit; pe restul vine `'371'` implicit sau din `cursor_gestiuni_articol*`) | identic pe ramurile care il au; **de verificat** pe ramurile 1/2/5/6/7/10/52/aviz — cursorul nu are `CONT` explicit in `SELECT` (`:2268-2329` etc.), deci provine din `do_alege_stoc`, nu din `crsarticole` |
-| `id_gestiune` | direct doar pe ramura restaurant (`A.ID_GESTIUNE`, `:2220`); pe rest vine din alegerea de gestiune (`cursor_gestiuni_articol*`) | identic — pasul de alegere gestiune ramane neschimbat |
-| `Proc_Tvav`, `pretftva`, `Pretctva`, `discountftva`(`discount_unitar`), `discountctva` | direct din cursor, plus `do_initializeaza_articol` (`:13618-13659`) care deriva `pretftva`/`pretctva`/`tva` reciproc dupa `preturi_cu_tva` | identic — logica de derivare e in VFP, nu se schimba |
-| `id_valuta`, `tip_valuta`, `nume_val`, `Curs`, `multiplicator` | direct din cursor | identic |
-| `gestionabil` | direct din cursor | identic (inclusiv regula de proforma, `ofacturare.prg:333-336`, care suprascrie `gestionabil=0` — ramane in `ofacturare.prg`, neschimbata) |
-| `id_jtva_coloana` | direct doar pe ramurile care il au explicit in `SELECT` (aviz/contract/retur); pe `cursor_preturi` (1/2/5/6/7/10/52) **nu apare in lista de coloane** returnate (`:2264-2329`) | **de verificat cu Marius** — daca lipseste azi, `Gather ... id_jtva_coloana` scrie `NULL`/valoare implicita; filtrarea nu schimba nimic aici, dar merita clarificat inainte de implementare, nu presupus |
-| `pretv_orig`, `pretd`, `id_valuta_d` | nu apar in `cursor_preturi`; vin din `poArtLista`/`crsartselectate` (alegerea de gestiune) | neschimbat |
-| `taxcode`, `explicatie`, `id_lucrare_rez`, `id_part_rez`, `id_ctr`, `opt_facturare` | nu din `crsarticole` — din `poArticol`/context (`do_initializeaza_articol`, `do_alege_stoc`) | neschimbat |
-| `pret_cu_tva` (flag `preturi_cu_tva`) | direct din cursor (`A.PRETURI_CU_TVA` / `D.PRETURI_CU_TVA`) | identic |
-
-**Concluzie pentru punctul 6 al cerintei:** nicio coloana din cele cerute explicit (pret, cota TVA,
-valuta, `id_pol`, `gestionabil`, `pret_cu_tva`) nu ridica probleme — toate vin direct din cursorul
-Oracle si filtrarea pe articol nu le atinge. Singurul semnal de atentie e `id_jtva_coloana`, absent
-din `cursor_preturi` insusi (posibil completat in alt pas, neverificat aici — iese din perimetrul
-"cele cinci cursoare", ar cere citirea intregului `do_adauga_articol`/`calculeaza_totaluri`).
-
-## 7. „Adauga tot" — ce ramane si de ce (nu doar decizia din plan)
-
-Planul spune "se pastreaza adauga tot pentru tipurile cu document sursa (comanda, aviz, contract) —
-acolo setul e marginit". Cercetarea (punctul 2) arata un motiv suplimentar, mai tare decat marimea
-setului: **bookkeeping-ul de cantitate ramasa** (`do_sterge`, `do_scrie_factura`) citeste si scrie
-direct in `crsarticole`, deci acel cursor **trebuie sa existe incarcat in memorie** cat timp
-formularul e deschis, indiferent cum alege utilizatorul liniile.
-
-**Vizibilitatea de azi a butonului `but_urmator_tot1`** ("adauga tot"), confirmata pe cod
-(`ofacturare.vc2:15108-15248`, `Do Case poDate.tip`):
-
-| Tip | Vizibil "adauga tot" azi | Sursa cursorului |
-|---|---|---|
-| proforma (`eProforma=1`) | da (`:15113`) | `cursor_preturi` sau alt cursor dupa tip, marcat negestionabil |
-| copiere (`lCopiere`) | da (`:15120`) | `cursor_preturi` (varianta copiere, `ofacturare.prg:464-473`) |
-| `1, 5, 7, 10` — lista de preturi | **nu** | `cursor_preturi` |
-| `2, 6` — contract | **nu** | `cursor_contract` |
-| `3` — comanda | da (`:15150`) | `cursor_comanda` |
-| `4` — avize | da (`:15166`) | `cursor_avize` |
-| `21, 28, 42, 47` — aviz din comanda | da (`:15177`) | `cursor_comanda` |
-| `22, 29` — aviz din lista de preturi | **nu** | `cursor_preturi` |
-| `23, 41` — transfer subunitati | **nu** menționat explicit vizibil | `cursor_gestiune` |
-| `25` — transfer din comanda | da (`:15215`) | `cursor_comanda` |
-| `26` — aviz din contract | **nu** | `cursor_contract` |
-| `8, 9` — retur | da (`:15240`) | `cursor_retur` (nu e in cele 5, iese din perimetru) |
-| `24` — aviz retur | da (`:15245`) | `cursor_retur` |
-
-**Coincide exact** cu impartirea utila pentru S4: butonul e vizibil azi pe tipurile unde
-`do_adauga_tot` are sens pentru ca setul e mic **si** bookkeeping-ul de ramas il cere
-(comanda/aviz-din-comanda/retur), si e ascuns pe tipurile de lista de preturi (1/5/7/10, 22/29) si pe
-contract-lista-de-preturi (2/6/26) — exact ramurile pe care cautarea filtrata inlocuieste incarcarea
-in masa. **Contractul insa nu are azi "adauga tot" vizibil deloc** (nici pe partea de rate, nici pe
-partea de articole) — planul semnaleaza asta separat, la S4b, ca gol de acoperit (tipurile 2, 6, 26,
-52 lipsesc din conditiile de vizibilitate), nu ca ceva de pastrat.
-
-**Concret, ce se schimba per tip:**
-- **Lista de preturi (1,5,7,10,22,29) si transfer pe lista (23,41,45,48,49):** `crsarticole` nu se
- mai incarca la deschidere; `combosql` cauta filtrat; "adauga tot" ramane ascuns (ca azi — n-are
- sens pe catalog intreg).
-- **Comanda (3,21,25,28,42,47) si avize (4):** `crsarticole` **ramane incarcat in masa**, neschimbat;
- `combosql` **nu se activeaza** pe aceste tipuri (sau, daca se activeaza pentru UX, cauta *in*
- cursorul deja incarcat, nu pe server — cautare locala, nu Oracle) pentru ca bookkeeping-ul de
- cantitate ramasa il cere oricum incarcat.
-- **Contract (2,6,26,52):** dublu — `crsarticole` (jumatatea `cursor_preturi`) trece pe cautare
- filtrata ca orice lista de preturi; `crsarticole1` (rate + articole `OPT_FACTURARE=3`) **ramane
- incarcat in masa**, bounded de contract, neschimbat de S4 (randurile de rata n-au `id_articol`,
- nu pot fi cautate).
-- **Retur (8,9,24):** in afara celor cinci cursoare cerute (`cursor_retur`/`cursor_retur_document`),
- proiectat separat la S4f — nesemnalat aici ca problema, doar exclus din perimetru.
-
-## 8. Interactiunea cu S4b si S10
-
-**Cu S4b (bara de butoane / meniul de adaugare):** S4b proiecteaza meniul `xmenu()` "Adauga
-articole" cu optiunile pe sursa (tot / alege), inclusiv acoperirea golului de pe contract (tipurile
-2/6/26/52). S4 ii da continutul concret pentru ramura "cauta in linie": pe tipurile de lista de
-preturi (unde S4b nu are nevoie de optiunea "tot" azi), linia de grid cu `combosql` **este** metoda
-de adaugare — nu exista un dialog separat de ales. Pe tipurile cu document sursa, S4 nu schimba
-nimic din ce proiecteaza S4b: meniul ramane cablat pe `do_adauga_tot`/alegere din `crsarticole`
-existent. Punctul de atingere real: daca S4b decide sa afiseze si pe contract un "adauga tot" (gol
-semnalat la punctul 7), acel "tot" trebuie sa opereze pe `crsarticole1` (rate+articole), nu pe
-`crsarticole` (lista de preturi) — cele doua cursoare raman distincte si dupa unificare.
-
-**Cu S10 (pretul care nu trebuie re-derivat, `docs\cercetare\s10_pret_rederivat.md`):** verificarea
-S10 arata ca `adauga_articol_factura` **primeste pretul ca parametru** (`V_PRET_ACHIZITIE_TEMP` si
-restul) si nu-l recalculeaza, cu o singura exceptie tacuta: liniile de contract cu
-`OPT_FACTURARE = 3`, unde `CTR_ARTICOLE.PRET_UNITAR` **suprascrie** pretul trimis, necondiționat de
-sursa. Pentru S4, asta inseamna doua lucruri concrete:
-1. cursorul filtrat (`cursor_preturi`/`cursor_gestiune` cu filtru pe articol) se cheama **o singura
- data**, la selectarea liniei in `combosql` (`LostFocus`) — pretul obtinut atunci se scrie in
- `crsfactura` si **nu se re-interogheaza** la scriere, exact ca azi pe calea `crsarticole` completa;
-2. pe **contract**, indiferent daca linia a fost aleasa prin `crsarticole1` (needitat de S4) sau,
- ipotetic, printr-o cautare filtrata viitoare, riscul de suprascriere tacuta descris in S10 exista
- deja si S4 nu-l introduce si nu-l rezolva — il mosteneste neschimbat, pentru ca punctul de
- suprascriere e in `adauga_articol_factura` (scriere), nu in cursorul de cautare (citire).
-
-## 9. Ordinea de executie in pasi
-
-1. **Pas 1 — Oracle, `cursor_preturi` filtrat.** Supraincarcare cu `V_FILTRU_COD`/`V_FILTRU_DEN`
- opționale, aceleasi 5 ramuri, filtru adaugat in `WHERE`-ul fiecareia (punctul 4). *Gata cand:*
- apelat cu filtru gol, cursorul e identic randuri-cu-randuri (aceleasi coloane, aceleasi valori, pe
- fiecare din cele 5 ramuri de `V_TIP`) cu varianta actuala pe acelasi set de parametri — comparatie
- directa pe SQL, nu pe timp.
-2. **Pas 2 — Oracle, `cursor_gestiune` filtrat.** Acelasi tipar, un singur `SELECT`, mai simplu.
- *Gata cand:* idem, comparatie randuri-cu-randuri cu filtru gol.
-3. **Pas 3 — Oracle, `cursor_contract`, doar partea `V_CURSOR`.** Filtrul se propaga gratuit prin
- apelul catre `cursor_preturi` de la `:2940-2948`; nicio schimbare suplimentara necesara daca Pasul
- 1 e facut corect. *Gata cand:* `cursor_contract` cu filtru gol produce acelasi `V_CURSOR` ca
- inainte de Pasul 1 (regresie, nu functie noua).
-4. **Pas 4 — VFP, `combosql` pe `cCodMat`/`cCboDenumire`.** Inlocuieste `csourcesql`/`SelectData` cu
- apelul la cursorul filtrat (punctul 5); extinde `LostFocus` (`:19288-19330`) sa scrie toate
- campurile din tabelul de la punctul 6, nu doar `codmat`/`denumire`/`id_articol`. *Gata cand:*
- alegerea unei linii in grid, pe un document de tip lista-de-preturi, produce in `crsfactura`
- aceleasi valori ca alegerea aceluiasi articol azi din `crsarticole` incarcat complet — comparatie
- pe date, punctul 10.
-5. **Pas 5 — VFP, oprirea incarcarii in masa pe tipurile vizate.** In `ofacturare.prg:266-311`, pentru
- `tnTip` din ramurile de lista de preturi (1,5,7,10,22,29,23,41,45,48,49) si jumatatea `cursor_preturi`
- a contractului, `goExecutor.oExecute` nu se mai cheama la deschidere — grid-ul porneste gol,
- `combosql` populeaza la cerere. *Gata cand:* deschiderea formularului pe aceste tipuri nu executa
- niciun apel `cursor_preturi`/`cursor_gestiune`/`cursor_contract` (verificabil in log-ul
- `goExecutor`/`WAIT WINDOW ... NOWAIT` din `combosql.selectdata`, care ramane singurul loc care
- cheama Oracle pentru articole).
-6. **Pas 6 — verificare "adauga tot" neatins.** Pe comanda/aviz/contract-rate, `do_adauga_tot`,
- `do_sterge`, `do_scrie_factura` raman neschimbate (Pasii 1-5 nu le ating codul). *Gata cand:*
- regresie manuala pe un document din comanda si unul din aviz — comportament identic cu azi.
-
-*Depinde de:* S3 (planul o marcheaza asa; portarea antetului trebuie sa existe inainte, ca sa aiba
-`poDate` populat corect la deschiderea gridului).
-
-## 10. Cum se verifica „aceleasi valori ca azi"
-
-**Testabil pe date (nu doar pe cod), propunere concreta:** pentru fiecare tip reprezentativ (1 sau 5
-pentru lista de preturi, 2 pentru contract, 41 pentru transfer-gestiune), se alege un articol prezent
-in cursorul complet de azi si se compara randul din `crsarticole` (deschidere veche, neschimbata) cu
-randul intors de cursorul filtrat pe acelasi articol, aceiasi parametri (`zi_curs`, `id_valuta`,
-`id_gestiune_init`, utilizator) — comparatie coloana cu coloana, in Oracle direct (doua `SELECT`-uri,
-`MINUS` intre ele pe coloanele comune) sau in VFP prin doua cursoare deschise simultan. Se repeta pe
-un articol cu politica de discount, unul in valuta si unul fara stoc (`RF_FACTURARE_FARA_STOC`), ca
-sa acopere ramurile de `CASE` din punctul 1.
-
-**Ce nu se poate testa headless — capcana cunoscuta** (`grid-coloane-nu-se-materializeaza-headless`,
-memorie de proiect): sub `-A -T`, `ColumnCount`/`RecordSource` ale gridului sunt artefacte, nu
-reflecta ce vede operatorul. Deci **partea VFP** (alegerea din `combosql`, `LostFocus`-ul care scrie
-in `crsfactura`) nu se poate verifica prin harnessul headless obisnuit — cere fie harnessul UI
-vizibil existent, fie verificare directa pe cursorul `crsfactura` dupa un apel programatic la metoda
-`LostFocus` (posibil, pentru ca metoda insasi nu depinde de randare, doar de `This.Value` — de
-confirmat la implementare). Partea Oracle (comparatia de cursoare de mai sus) **e** testabila
-headless, prin `SELECT`, fara nicio dependenta de VFP.
-
-## 11. Riscuri si ce ramane de decis de Marius
-
-- **`id_jtva_coloana` lipsa din `cursor_preturi`** (punctul 6) — de clarificat inainte de
- implementare daca e completat in alt pas (nevazut aici) sau ramane `NULL` si azi; filtrarea nu
- schimba comportamentul, dar nota trebuie inchisa ca sa nu para un bug nou introdus de S4.
-- **Mecanismul de legare `combosql` -> cursor Oracle parametrizat dinamic** (punctul 5, ultimul
- paragraf) e o alegere de implementare, nu un fapt de cod — `csourcesql` static din `.vcx` nu poate
- primi parametrii de sesiune direct; solutia propusa (suprascriere punctuala `refreshdata`) e
- rezonabila, dar nu e singura posibila si nu exista alt exemplu in suita de comparat.
-- **Contractul ramane cu doua surse de date pe acelasi grid conceptual** (`crsarticole` filtrat +
- `crsarticole1` needitat) — de confirmat ca UX-ul (doua zone: cautare + grid rate) e acceptabil, nu
- doar tehnic corect.
-- **`cursor_gestiune` (transfer subunitati) nu are azi buton "adauga tot" vizibil** (tabelul din
- punctul 7 nu-l gaseste in `Do Case`) — de verificat separat daca tipurile 23/41 au alt mecanism de
- adaugare in masa, neacoperit de cautarea in `crsarticole`/`crsarticole1` directa; nu s-a citit codul
- suplimentar necesar pentru raspuns cert aici.
-- **Validarea de curs valutar (`verifica_cursuri_valute`, punctul 1.1) ramane neconditionata** chiar
- si pe varianta filtrata, daca se pastreaza in procedura supraincarcata — poate produce `-20005` la
- prima cautare a unui articol, inainte ca utilizatorul sa fi vazut vreun rand, pe o valuta pe care
- n-o foloseste azi doar pentru ca incarcarea in masa "o gasea" oricum. De discutat cu Marius daca
- validarea trebuie restransa la valuta articolului cautat sau ramane globala (comportament
- identic cu azi, doar declansat mai des — la fiecare cautare, nu o data la deschidere).
-- **Numarul exact de apeluri Oracle pe sesiune de cautare** (un apel per tastare, cu debounce prin
- `nCharCountBegin`) nu a fost masurat si nu trebuie masurat aici (decizia 31) — dar merita setat
- explicit `nCharCountBegin` >= 2-3 la implementare, ca sa nu se piarda avantajul filtrarii intr-un
- numar mare de interogari de o litera.
-
-## Handoff
-
-Cercetare incheiata in aceasta sesiune, fara nevoie de predare — toate cele 11 puncte cerute sunt
-acoperite mai sus, cu citate `fisier:linie` verificate pe fisierul real (nu `.bak`). Niciun fisier de
-cod atins, niciun `git_sync.ps1`/`txt2vcx.ps1` rulat, nicio scriere pe Oracle.
diff --git a/docs/cercetare/s4_punct2_registru_cantitate_ramasa.md b/docs/cercetare/s4_punct2_registru_cantitate_ramasa.md
deleted file mode 100644
index 18ef086..0000000
--- a/docs/cercetare/s4_punct2_registru_cantitate_ramasa.md
+++ /dev/null
@@ -1,615 +0,0 @@
-# Cercetare — proiectare S4 punctul 2: decuplarea registrului de cantitate ramasa de `crsarticole`
-
-Investigatie READ-ONLY pentru **punctul 2** al povestii S4 din
-`docs\plan_13_unificare_formular_facturare.md:2099-2113`. Continua raportul punctului 1
-(`docs\cercetare\s4_cautare_articole_server.md`) si corectiile din `docs\cercetare\s4_puncte_deschise.md`.
-Fara editari de cod, fara `git_sync.ps1`/`txt2vcx.ps1`, fara commit, fara scriere pe Oracle (numai
-`SELECT`). Nu ating `COMUN\clase\ofacturare_comun.vc2` si `COMUN\programe\ofacturare_editare.prg`
-(perimetrul altei sarcini). **Decizia 39 (S4 ramane integrala, se desface registrul) nu e
-reargumentata** — proiectez CUM, nu DACA.
-
-Sursa VFP: `COMUN\clase\ofacturare.vc2` (`frm_facturare_articole`; `frm_facturare_articole2`/prototip
-citit doar pentru confirmare, are aceeasi structura). Sursa Oracle:
-`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (corpul
-pachetului, `versiune_db.txt` = `2026_08_09_02`).
-
-## Verdict (rezumat)
-
-**Descoperirea centrala: `crsarticole.cantitate` are azi DOUA roluri distincte, nu unul, si numai
-unul din ele e "registrul de cantitate ramasa" pe care planul il numeste riscant.**
-
-- **Rol A — cantitate ramasa de facturat dintr-un document sursa** (doar comanda: tip
- `3,21,25,28,42,47`; si avize: tip `4`). Cursoarele Oracle (`cursor_comanda`, `cursor_avize`) o
- **calculeaza deja live** la deschidere ca `cantitate_document - deja_facturat`. `do_scrie_factura`
- o re-suma din `crsarticole` (`Calculate Sum`) **doar ca sa decida ce sa trimita mai departe**
- (`pnParametruAditional`) — dar Oracle **recalculeaza acelasi lucru independent, din tabele reale**,
- in `inchide_comanda()` si `marcheaza_facturat()`, chiar in procedura care scrie factura. Cursorul
- VFP e o **copie redundanta a unui calcul pe care Oracle il repeta oricum la scriere** — exact
- problema "sursa unica" semnalata in misiune, si exact motivul pentru care decuplarea e posibila
- fara sa piarda paritatea: mutam citirea "cat a mai ramas" din cursorul local intr-un apel Oracle
- facut la momentul potrivit, nu intr-o a doua copie tinuta manual.
-- **Rol B — plafon de cantitate in sesiune** (lista de preturi gestionabila `1,22,29,2`-jumatate;
- transfer `23,41`; retur `8,9,24`). Decrementat/incrementat in `do_adauga_articol`/`do_modifica`/
- `do_sterge` ca sa nu lase operatorul sa adauge mai mult decat vede pe ecran, in aceeasi sesiune.
- **Nu alimenteaza nicio decizie Oracle** — nu apare in niciun `Calculate Sum` in afara celor doua
- locuri de la Rolul A, si Oracle nu-l citeste niciodata direct. E un plafon UI, nu un registru de
- business.
-- **Corectie fata de raportul punctului 1**: pasul 5 de acolo (`s4_cautare_articole_server.md:417-424`)
- propune oprirea incarcarii in masa pe tipurile `23,41` (printre altele), presupunand ca ele n-au
- bookkeeping de pastrat — dar **au Rol B** (confirmat pe cod, sectiunea 1 de mai jos). Punctul 1 nu
- poate fi aplicat pe `23,41` fara ca punctul 2 sa acopere intai Rolul B pe aceste doua tipuri.
-- **Recomandare de proiectare** (detaliata la sectiunea 4): pentru Rolul A, inlocuieste
- `Select crsarticole / Calculate Sum(cantitate)` cu un apel Oracle nou, la acelasi moment din
- `do_scrie_factura` (dupa `do_scrie_articole()`, cand `VANZARI_DETALII_TEMP` e deja populat), care
- reface exact interogarea pe care `inchide_comanda`/`marcheaza_facturat` o repeta oricum. Pentru
- Rolul B, plafonul devine un apel Oracle la cerere (aceeasi interogare care alimenteaza azi
- `cursor_preturi`/`cursor_comanda`/`cursor_gestiune`, filtrata pe articol), nu o valoare tinuta in
- memorie — nu mai e nevoie de sincronizare manuala pentru ca nu mai exista o a doua copie.
-
----
-
-## 1. Inventar exact al scrierilor/citirilor de bookkeeping
-
-Verificat direct pe `COMUN\clase\ofacturare.vc2` (nu pe `.bak`), linii confirmate cu `vfp_symbols.ps1`.
-
-### 1.1 `do_adauga_articol` — scrierea la adaugarea unei linii (`:12813-13086`)
-
-Dupa ce linia e scrisa in `crsfactura`, la `:13034-13051`:
-
-```
-Select (lcCursor)
-lnRecno = Recno()
-Do Case
- Case gnScadereStoc = 1 And poDate.tip = 41 && aviz retur transfer catre subunitati lista pret
- Replace cantitate With cantitate + poArticol.cantitate For id_c = poArticol.id_c
- Go lnRecno
- Case (gnScadereStoc = 1 And poDate.tip = 23) Or Inlist(poDate.tip, 3, 4, 21, 25, 28, 42, 47)
- Replace cantitate With cantitate - poArticol.cantitate For id_c = poArticol.id_c
- Go lnRecno
- Case Inlist(poDate.tip, 8, 9, 24) && factura retur lei si valuta, aviz retur
- Replace cantitate With cantitate + poArticol.cantitate For id_c = poArticol.id_c
- Go lnRecno
- Case poArticol.gestionabil = 1 And gnScadereStoc = 1 And ;
- (Inlist(poDate.tip, 1, 22, 29) Or (poDate.tip = 2 And poArticol.opt_facturare = 0))
- Replace cantitate With IIF(cantitate - poArticol.cantitate > 0, cantitate - poArticol.cantitate, 0) For id_articol = poArticol.id_articol And gestionabil = 1
- Go lnRecno
-Endcase
-```
-
-`lcCursor` = `crsarticole1` daca `tlContract`, altfel `crsarticole` (`:12839-12845`).
-
-### 1.2 `do_sterge` — refacerea la stergerea unei linii (`:14608-14677`)
-
-```
-Select (lcCursor)
-lnRecNo = Recno()
-Do Case
- Case gnScadereStoc = 1 And poDate.tip = 41
- Select (lcCursor)
- Replace cantitate With cantitate - poArticol.cantitate For id_c = poArticol.id_c
- Case (gnScadereStoc = 1 And poDate.tip = 23) Or Inlist(poDate.tip,3,4,21,25,28,42,47)
- Select (lcCursor)
- Replace cantitate With cantitate + poArticol.cantitate For id_c = poArticol.id_c
- Case Inlist(poDate.tip,8,9,24)
- Replace cantitate With cantitate - poArticol.cantitate For id_c = poArticol.id_c
- Case poArticol.id_gestiune <> - 1000 And gnScadereStoc = 1 And ;
- (Inlist(poDate.tip,1,22,29) Or (poDate.tip = 2 And poArticol.opt_facturare = 0))
- Select (lcCursor)
- Replace cantitate With cantitate + poArticol.cantitate For id_articol = poArticol.id_articol And gestionabil = 1
-Endcase
-```
-
-`lcCursor` = `crsarticole1` daca `poArticol.opt_facturare <> 0`, altfel `crsarticole` (`:14615-14619`).
-**Exact inversul semnului fata de `do_adauga_articol`, pe aceleasi patru grupuri de tipuri** — simetrie
-confirmata, nu presupusa.
-
-### 1.3 `do_modifica` — ajustarea la schimbarea cantitatii pe o linie deja adaugata (`:13746-13914`)
-
-Doua interactiuni distincte cu registrul, in aceeasi metoda:
-
-**(a) Calculul plafonului inainte de a arata dialogul** (`:13775-13798`), comentat explicit in cod
-ca "plafonul de cantitate = stocul disponibil reconstituit din cursorul sursa; fara randul in cursor
-ramane cantitatea liniei" (`:13775`):
-```
-lnCantitateMax = poArticol.cantitate
-lcCursorStoc = Iif(poArticol.opt_facturare = 0, [crsarticole], [crsarticole1])
-...
-Locate For id_c = poArticol.id_c
-If Found()
- Do Case
- Case (gnScadereStoc = 1 And poDate.tip = 23) Or Inlist(poDate.tip, 4, 21, 28, 42, 47)
- lnCantitateMax = cantitate + poArticol.cantitate
- Case Inlist(poDate.tip, 8, 9, 24)
- lnCantitateMax = cantitate - poArticol.cantitate
- Endcase
-Endif
-```
-Aduna inapoi ce a consumat deja linia curenta, ca sa arate operatorului plafonul real (cat mai era
-disponibil **inainte** de aceasta linie), trimis ca parametru la `do_alege_stoc`/`frm_articol_factura`.
-
-**(b) Ajustarea delta dupa ce operatorul schimba cantitatea** (`:13887-13904`):
-```
-lnDeltaCantitate = poArticol.cantitate - lnCantitateVeche
-If lnDeltaCantitate <> 0 And Used(lcCursorStoc)
- Do Case
- Case (gnScadereStoc = 1 And poDate.tip = 23) Or Inlist(poDate.tip, 4, 21, 28, 42, 47)
- Replace cantitate With cantitate - lnDeltaCantitate For id_c = poArticol.id_c
- Case Inlist(poDate.tip, 8, 9, 24)
- Replace cantitate With cantitate + lnDeltaCantitate For id_c = poArticol.id_c
- Endcase
-Endif
-```
-
-**Gasit, nu presupus: `do_modifica` NU ajusteaza `crsarticole` pentru tipurile `1,22,29` si
-`2`-lista-jumatate** (grupul "gestionabil, plafon local" din `do_adauga_articol`/`do_sterge`) — doar
-pentru grupul comanda/aviz (`4,21,23,28,42,47`) si retur (`8,9,24`). E o asimetrie **preexistenta**
-in codul de azi (nu introdusa de S4): editarea cantitatii pe o linie de lista-de-preturi deja adaugata
-nu recalibreaza plafonul local. Nu e de reparat aici — doar de semnalat, ca varianta noua sa nu
-incerce sa reproduca o simetrie care nu exista azi.
-
-### 1.4 `do_adauga_tot` — enumerare, nu bookkeeping propriu (`:13169-13198`)
-
-```
-Select crsarticole
-Scan
- ...
- Thisform.do_adauga_articol(.T.)
- ...
-Endscan
-```
-
-**Nu scrie direct in `crsarticole`** — cheama `do_adauga_articol` pe fiecare rand, care face
-bookkeeping-ul de la 1.1. Rolul lui `crsarticole` aici e al treilea, distinct de Rolul A/B: **sursa
-de enumerare** ("ce randuri exista de adaugat"), necesara oricum pentru populare (S4 punctul 1), nu
-doar pentru bookkeeping.
-
-### 1.5 `do_scrie_factura` — citirea care alimenteaza decizia de inchidere (`:14301-14338`)
-
-Doua ramuri, singurele doua locuri din intregul fisier unde `Calculate Sum(cantitate)` ruleaza peste
-`crsarticole` (confirmat cu grep pe tot fisierul, nicio a treia aparitie):
-
-```
-Case poDate.Tip = 4
- Select crsarticole
- Calculate Sum(cantitate) To lnCantitateRamasa
- If lnCantitateRamasa > 0
- pnFacturaRetur = 7 - amessagebox("Doriti sa se inregistreze si avizul de retur?",4+32,"Confirmare")
- pnParametruAditional = 1
- Else
- pnFacturaRetur = 0
- pnParametruAditional = 0
- Endif
- ...
-Case Inlist(poDate.Tip,3,21,25,28,42,47)
- Select crsarticole
- Calculate Sum(cantitate) To lnCantitateRamasa
- If lnCantitateRamasa <> 0
- pnParametruAditional = 7 - amessagebox("Doriti sa se inchida comanda?",4+32,"Confirmare")
- Endif
- ...
-```
-
-`pnParametruAditional` default e `0` (`:14222`, setat inainte de `Do Case`). Pentru **orice alt tip**
-(inclusiv `41`, `23`, `2/6/26/52`, `45/48/49`), ramane `0` fara sa fie calculat din `crsarticole` deloc
-(exceptie: tip `48` il suprascrie cu `poDate.coeficient_k`, fara legatura cu inchiderea — `:14367-14369`).
-
-**Concluzie:** doar `4` si `Inlist(3,21,25,28,42,47)` sunt Rolul A. Restul tipurilor nu ating deloc
-aceasta parte a lui `do_scrie_factura` — inclusiv `41`/`23`, care au totusi bookkeeping Rol B activ la
-1.1-1.3.
-
----
-
-## 2. Semantica registrului azi
-
-### 2.1 Ce inseamna `cantitate` la incarcare, per grup
-
-Confirmat pe corpul cursoarelor Oracle (`ff_...PACK_FACTURARE.sql`):
-
-- **`cursor_comanda`** (`:2952-3171` per raportul punctului 1; verificat aici direct la sectiunea
- "aviz"/comanda a interogarii, `:3060-3081`): coloana `cantitate` e `A.CANTITATE - NVL(D.CANTITATE, 0)`
- unde `D` e `SUM(cantitate)` deja facturat din `VANZARI_DETALII` pe acelasi `id_comanda`
- (`:3060-3068`), filtrat `WHERE ... SIGN(A.CANTITATE) * (A.CANTITATE - NVL(D.CANTITATE, 0)) > 0`
- (`:3079`). **E deja "ramas de facturat", calculat live la deschidere** — nu cantitatea comandata
- bruta.
-- **`cursor_avize`** (`:3703-3874`): coloana `A.CANTITATE - NVL(D.CANTITATE, 0) AS CANTITATE`
- (analog la `:3118`), plus agregarea finala (`:3820-3872`) care scade `VANZARI_CANTITATI` deja
- consumat din `VANZARI_DETALII` (`WHERE A.CANTITATE <> NVL(B.CANTITATE, 0)`, `:3871`). Acelasi
- tipar: "ramas", nu cantitatea avizata bruta.
-- **Restul grupurilor (Rol B: `1,22,29,2`-lista, `23,41` transfer, `8,9,24` retur)**: `cantitate`
- vine din `cursor_preturi`/`cursor_gestiune`, care e **stoc disponibil** (`LEFT JOIN` pe `STOC`,
- raportul punctului 1 sectiunea 1.1/1.5), nu "ramas de facturat dintr-un document" — pentru ca aceste
- tipuri nu au un document sursa cu cantitati de urmarit (lista de preturi n-are document sursa;
- transferul/returul opereaza pe stoc, nu pe o comanda).
-
-### 2.2 Cine o scade si cand
-
-Vezi sectiunea 1: la fiecare `do_adauga_articol` (scade sau creste, dupa tip), la fiecare `do_sterge`
-(inversul), si la `do_modifica` doar pentru grupul Rol A + retur (2.1(b) de mai sus).
-
-### 2.3 Ce se intampla la adaugare / stergere / modificare cantitate — rezumat comportamental
-
-| Actiune | Rol A (comanda 3/21/25/28/42/47, aviz 4) | Rol B (lista gestionabila 1/22/29/2, transfer 23/41, retur 8/9/24) |
-|---|---|---|
-| Adauga linie | `crsarticole.cantitate` scade (creste la retur/41) cu cantitatea adaugata | idem, plafon local |
-| Sterge linie | reface exact simetric | reface exact simetric |
-| Modifica cantitate pe linie existenta | ajusteaza cu delta (23/4/21/28/42/47 si 8/9/24 explicit) | **nu ajusteaza** pe 1/22/29/2-lista (asimetrie preexistenta, 1.3) |
-| La scriere (`do_scrie_factura`) | **suma peste `crsarticole` decide `pnParametruAditional`** (inchidere) | **nu se suma niciodata** — nu alimenteaza nicio decizie Oracle |
-
----
-
-## 3. Regula de inchidere automata — exact, cu dovada Oracle
-
-### 3.1 Ce trimite VFP si ce face Oracle cu el
-
-`pnParametruAditional` merge la Oracle prin `scrie_factura_avize` (tip `4`) sau `scrie_factura2`
-(toate celelalte, inclusiv comanda). Ambele cheama in interior `finalizeaza_factura(...)`
-(`ff_...PACK_FACTURARE.sql:14770-14852`), care are un `CASE` unic pe `pack_facturare.ntip` (setat
-intern din tipul documentului, nu parametru separat):
-
-```sql
-CASE
- WHEN V_PARAMETRU_ADITIONAL = 1 AND pack_facturare.ntip IN (3, 21, 25, 28, 42, 47) THEN
- -- comanda: V_PARAMETRU_ADITIONAL este V_INCHIDERE_COMANDA
- pack_facturare.inchide_comanda();
- WHEN pack_facturare.ntip = 4 THEN
- -- aviz: V_PARAMETRU_ADITIONAL este V_VERIFICARE_FACTURAT
- pack_facturare.scrie_cantitati_vanzari_avize;
- pack_facturare.scrie_corespondente_vanzari(1);
- pack_facturare.marcheaza_facturat(V_PARAMETRU_ADITIONAL);
- WHEN pack_facturare.ntip = 24 THEN
- pack_facturare.scrie_corespondente_vanzari(2);
- pack_facturare.marcheaza_facturat(V_PARAMETRU_ADITIONAL);
- WHEN pack_facturare.ntip in (2, 6, 52) THEN
- pack_facturare.scrie_rate_factura(V_DATAORA);
- WHEN pack_facturare.ntip in (8, 9) THEN
- pack_facturare.scrie_corespondente_vanzari(3);
- ELSE
- dbms_output.put_line('---');
-END CASE;
-```
-(`:14818-14839`)
-
-**`41` si `23` nu apar deloc in acest `CASE`** — cad pe `ELSE`, fara nicio actiune de inchidere.
-Confirma pe cod ce arata si sectiunea 1.5: transferul intre subunitati nu are un "document sursa" de
-inchis, doar un plafon de stoc (Rol B). `2/6/26/52` (contract) intra pe ramura `scrie_rate_factura`,
-care scrie scadentarul de rate — **nu e o "inchidere" in sensul comanda/aviz**, e alta operatie.
-
-### 3.2 Comanda — `inchide_comanda()` (`:5769-5820`)
-
-**Ruleaza doar cand `V_PARAMETRU_ADITIONAL = 1`** — adica doar daca `crsarticole` a aratat cantitate
-ramasa nenula **si** operatorul a raspuns "Da" la "Doriti sa se inchida comanda?" (`ofacturare.vc2:14336-14337`).
-Cand ramane 0 (fara diferenta), `inchide_comanda()` **nu se cheama deloc** — pentru ca o comanda complet
-livrata se raporteaza deja "inchisa" prin simplul fapt ca interogarea de mai jos nu mai returneaza
-randuri, fara nicio actiune suplimentara.
-
-Ce face efectiv (`:5771-5818`): **insereaza un rand compensator** in `COMENZI_ELEMENTE`, cu
-`CANTITATE = ramas` (calculat live, independent de VFP, din `NVL(C.CANTITATE,0) + NVL(B.CANTITATE,0) -
-A.CANTITATE` unde `B` = deja facturat in aceasta tranzactie (`VANZARI_DETALII_TEMP`) si `C` = deja
-facturat istoric (`VANZARI`/`VANZARI_DETALII`)) — asta face ca o interogare ulterioara de tip
-`cursor_comanda` (aceeasi forma de `WHERE`, `SIGN(...) * (A.CANTITATE - NVL(D.CANTITATE,0)) > 0`) sa
-nu mai gaseasca randuri ramase, adica sa "inchida" comanda **prin recalcul, nu printr-un flag setat**.
-**Nu exista o coloana `INCHISA`/status persistat pe comanda** (cautare `INCHISA` in tot pachetul —
-zero potriviri) — starea "deschisa/inchisa" e intotdeauna derivata din suma `COMENZI_ELEMENTE` vs
-`VANZARI_DETALII`, nu citita dintr-un camp.
-
-**Important pentru paritate:** cantitatea trimisa de VFP (`pnParametruAditional`, un simplu `1`/`0`)
-**nu participa la calculul cantitatii inserate** — Oracle o recalculeaza singur din tabele reale.
-Rolul VFP e strict binar: "a fost cerut sa se forteze inchiderea?".
-
-### 3.3 Avize — `marcheaza_facturat(V_VERIFICARE)` (`:15381-15418`)
-
-```sql
-IF V_VERIFICARE = 0 THEN
- UPDATE VANZARI SET FACTURAT = 1, ID_UTILFACT = ...
- WHERE ID_VANZARE IN (SELECT id_vanzare_aviz ... WHERE id_vanzare_Fact = pack_facturare.nid_vanzare AND sters=0 AND tip<>3)
- AND FACTURAT = 0;
-ELSE
- UPDATE VANZARI SET FACTURAT = 1, ...
- WHERE ID_VANZARE IN (
- SELECT id_vanzare FROM (
- SELECT a.id_vanzare, SUM(a.cantitate - NVL(b.cantitate,0)) AS ramas
- FROM vanzari_detalii a LEFT JOIN (...VANZARI_CANTITATI...) b ON ...
- WHERE a.id_vanzare IN (...avizele referite de aceasta factura...)
- GROUP BY a.id_vanzare
- ) WHERE ramas = 0
- );
-END IF;
-```
-
-**Aici exista un flag real persistat: `VANZARI.FACTURAT`.** `V_VERIFICARE` (= `pnParametruAditional`
-trimis de VFP) alege intre doua moduri:
-- `V_VERIFICARE = 0` (VFP a vazut `lnCantitateRamasa = 0`, adica a crezut ca tot ce era in avizele
- referite s-a facturat): **marcheaza TOATE avizele referite ca facturate, fara re-verificare** —
- increde in calculul VFP.
-- `V_VERIFICARE = 1` (VFP a vazut ceva ramas): **recalculeaza per-aviz, din tabele reale**
- (`vanzari_detalii`/`vanzari_cantitati`), si marcheaza **doar** avizele individuale al caror
- `ramas = 0` — mai stric, pentru ca VFP nu mai e sigur.
-
-**Observatie relevanta pentru punctul 2 al plafonului de risc**: cand un singur `crsarticole` agrega
-mai multe avize (facturare din mai multe avize deodata), suma globala poate fi 0 chiar daca un aviz
-individual din grup mai are ramas si altul are exces care-l compenseaza — caz in care `V_VERIFICARE=0`
-ar marca **toate** ca facturate, inclusiv cel cu ramas real. **Comportament preexistent**, nu introdus
-de decuplare — dar varianta noua trebuie sa-l reproduca identic (aceeasi conditie de trigger: suma
-globala peste toate liniile din tranzactia curenta, nu per-document), nu sa-l "repare" din greseala.
-
-### 3.4 Cine altcineva verifica remainder — `scrie_cantitati_vanzari_avize` (`:15420-15479`)
-
-Ruleaza **necondiționat** pe ramura `tip=4`, indiferent de `V_VERIFICARE` — scrie in `VANZARI_CANTITATI`
-cate din cantitatile avizate au fost efectiv consumate de aceasta factura (mecanismul care alimenteaza
-`ramas` la sectiunea 3.3). Nu depinde de `crsarticole` — foloseste `VANZARI_DETALII_TEMP` (deja
-populat de `do_scrie_articole()`, apelat inaintea acestui `Do Case` din VFP, `:14264`) si tabele reale.
-**Confirma independenta totala de `crsarticole` a partii Oracle** — singurul lucru pe care Oracle il
-primeste de la VFP e semnalul binar `pnParametruAditional`.
-
----
-
-## 4. Proiectare — variante comparate
-
-### Varianta (a) — cursor propriu, minimal, decuplat de populare
-
-Un cursor separat (`crsregistru`), incarcat cu `id_c`/`id_articol` + cantitate ramasa, populat din
-aceeasi interogare care alimenteaza azi `crsarticole`, dar **independent** de campurile de populare
-(pret, TVA, valuta...) pe care S4 punctul 1 le muta pe cautare filtrata.
-
-**Ce se atinge:** aceleasi patru metode (`do_adauga_articol`, `do_sterge`, `do_modifica`,
-`do_scrie_factura`) — schimba doar numele cursorului tinta, logica ramane identica.
-**Ce se rupe:** nimic structural — e schimbarea minima de sintaxa.
-**Cost:** mic, dar **nu rezolva problema de fond**: tot exista o a doua copie a "cat a mai ramas",
-tinuta manual in memorie VFP, care trebuie sa ramana in sincron cu ce calculeaza Oracle la scriere
-(sectiunea 3). E acelasi risc de azi, doar cu un cursor mai ingust. **Nu e "sursa unica"** — e aceeasi
-sursa dubla, doar mai mica.
-
-### Varianta (b) — recalculul pe server la scriere, in loc de suma locala (RECOMANDATA pentru Rolul A)
-
-Inlocuieste cele doua `Select crsarticole / Calculate Sum(cantitate) To lnCantitateRamasa` din
-`do_scrie_factura` (`:14303-14304`, `:14334-14335`) cu un apel Oracle nou, facut **dupa**
-`Thisform.do_scrie_articole()` (`:14264`, care populeaza deja `VANZARI_DETALII_TEMP` cu exact ce e pe
-cale sa fie scris) si **inainte** de `Do Case` care alege `scrie_factura_avize`/`scrie_factura2`.
-
-Doua proceduri Oracle noi, minimale, care **reutilizeaza exact interogarea** pe care
-`inchide_comanda`/`marcheaza_facturat` o ruleaza oricum peste doua randuri mai jos in acelasi flux —
-nu o interogare noua, o extragere a celei existente intr-o forma care returneaza un numar in loc sa
-scrie:
-
-```sql
--- comanda: acelasi WHERE ca inchide_comanda (:5771-5818), dar SUM in loc de INSERT
-FUNCTION cantitate_ramasa_comanda(V_ID_COMANDA IN NUMBER) RETURN NUMBER IS
- V_RAMAS NUMBER;
-BEGIN
- SELECT NVL(SUM(SIGN(A.CANTITATE) *
- GREATEST(SIGN(A.CANTITATE) * (A.CANTITATE - NVL(B.CANTITATE,0) - NVL(C.CANTITATE,0)), 0)), 0)
- INTO V_RAMAS
- FROM COMENZI_ELEMENTE A
- LEFT JOIN (SELECT ID_ARTICOL, ID_POL, ID_VALUTA, PRET, SUM(CANTITATE) AS CANTITATE
- FROM VANZARI_DETALII_TEMP GROUP BY ID_ARTICOL, ID_POL, ID_VALUTA, PRET) B
- ON A.ID_ARTICOL = B.ID_ARTICOL AND A.ID_POL = B.ID_POL AND A.ID_VALUTA = B.ID_VALUTA AND A.PRET = B.PRET
- LEFT JOIN (... acelasi C ca in inchide_comanda, VANZARI/VANZARI_DETALII istoric ...) C ON ...
- WHERE A.STERS = 0 AND A.ID_COMANDA = V_ID_COMANDA;
- RETURN V_RAMAS;
-END;
-
--- avize: acelasi calcul ca in marcheaza_facturat(V_VERIFICARE=1), dar returnat, nu aplicat
-FUNCTION exista_ramas_avize(V_LISTAID IN VARCHAR2) RETURN NUMBER IS ...
-```
-
-**Ce se atinge:** `do_scrie_factura` (inlocuieste 4 linii VFP cu un apel Oracle + citire scalar), plus
-doua functii Oracle noi in `PACK_FACTURARE`, care **extrag** logica deja scrisa in `inchide_comanda`/
-`marcheaza_facturat`, nu o duplica din nimic. `do_adauga_tot`, `do_sterge`, `do_modifica` **raman
-neschimbate pentru Rolul A** — nu mai au ce sa faca, pentru ca nimic nu mai citeste suma lor.
-**Ce se rupe:** niciun comportament — recalculul Oracle e **mai precis** decat suma locala (vede
-concurenta: doi operatori facturand din aceeasi comanda simultan; `crsarticole` local nu vede
-modificari facute de alt utilizator dupa deschiderea formularului — bug latent de azi, pe care
-varianta (b) il elimina ca efect secundar, nu ca scop).
-**Cost:** doua functii Oracle noi (SQL, nu logica noua — extrase din proceduri existente), un apel
-suplimentar `goExecutor` in `do_scrie_factura`.
-**De ce e "sursa unica":** Oracle calculeaza "cat a ramas" o singura data, in doua locuri (recalcul
-inainte de scriere + recalcul in `inchide_comanda`/`marcheaza_facturat` la scriere), din **aceeasi
-interogare**, niciodata dintr-o copie VFP. Nu mai exista sincronizare de mentinut, pentru ca nu mai
-exista a doua stare.
-
-### Varianta (c) — plafon Rol B recalculat la cerere, nu tinut in memorie (RECOMANDATA pentru Rolul B)
-
-Pentru grupul Rol B (`1,22,29,2`-lista, `23,41`, `8,9,24`), plafonul din `do_modifica`
-(`lnCantitateMax`, sectiunea 1.3(a)) si decrementul din `do_adauga_articol`/`do_sterge` (sectiunea
-1.1/1.2) devin un apel Oracle facut **la fiecare adaugare/editare**, in loc de o valoare tinuta in
-`crsarticole` — interogare filtrata pe `id_articol`, aceeasi forma ca `cursor_preturi`/
-`cursor_gestiune` filtrate (deja proiectate la S4 punctul 1, sectiunea 4), minus stocul deja rezervat
-in sesiunea curenta (calculabil din `crsfactura` insusi, sumand liniile deja adaugate cu acelasi
-`id_articol` — cursor local, dar de linii **efectiv adaugate**, nu de "cat mai era", deci nu mai poate
-diverge de continutul real al facturii in curs).
-
-**Ce se atinge:** `do_adauga_articol` (:13034-13051 dispare, inlocuit cu un apel la cerere din
-`do_alege_stoc`, care oricum face verificare de stoc pe server — de confirmat la implementare daca
-verificarea existenta acopera deja acest plafon sau trebuie extinsa), `do_sterge` (:14640-14669
-Rol B dispare, ramane doar Rolul A), `do_modifica` (:13775-13798 plafonul se cere pe server, nu se
-reconstituie din cursor).
-**Ce se rupe:** **de verificat cu Marius** — plafonul Rol B azi e un avertisment soft (`do_alege_stoc`
-primeste `lnCantitateMax` ca parametru, dar verificarea reala de stoc la comitere ramane oricum in
-Oracle, la `adauga_articol_factura`/scriere; codul citit aici nu arata un blocaj hard bazat pe
-`crsarticole` — de confirmat explicit, nu presupus, ca UX-ul de azi (mesaj/limitare la alegerea
-cantitatii) nu depinde de faptul ca plafonul persista *in memorie* intre doua adaugari ale *aceluiasi*
-articol in aceeasi sesiune, ci doar de valoarea citita la momentul respectiv).
-**Cost:** mediu — mai multe interogari Oracle mici (una per adaugare/editare de linie gestionabila),
-in loc de aritmetica locala. Justificat de acelasi motiv ca varianta (b): elimina a doua copie.
-
-### Comparatie si recomandare finala
-
-| | (a) cursor propriu minimal | (b) recalcul server (Rol A) | (c) plafon la cerere (Rol B) |
-|---|---|---|---|
-| E "sursa unica"? | Nu — copie mai mica, tot manuala | **Da** | **Da** |
-| Risc de divergenta fata de Oracle | Identic cu azi | Eliminat (Oracle citeste Oracle) | Eliminat |
-| Cost implementare | Mic | Mic-mediu (2 functii Oracle) | Mediu (mai multe roundtrip-uri) |
-| Rezolva corectia sectiunii 0 (23/41 blocheaza punctul 1) | Nu direct | N/A (23/41 nu sunt Rol A) | **Da** |
-
-**Recomandare: (b) pentru Rolul A, (c) pentru Rolul B.** Impreuna elimina complet nevoia de a incarca
-`crsarticole` in masa pentru bookkeeping — incarcarea ramasa (daca ramane) e strict pentru
-**enumerare** la "adauga tot" (sectiunea 1.4), care e un scop diferit si mai ingust (nu mai trebuie sa
-tina sincron o cantitate, doar sa listeze randuri candidate o singura data, la deschidere).
-
----
-
-## 5. Cazul limita: adauga si sterge inainte de salvare
-
-**Azi:** `do_adauga_articol` decrementeaza `crsarticole`/`crsarticole1` (Rol A si/sau B, dupa tip);
-`do_sterge` reface exact simetric, inainte de orice salvare (sectiunile 1.1-1.2 sunt perechi
-simetrice pe fiecare grup de tipuri). Suma finala din `crsarticole` la momentul `do_scrie_factura`
-reflecta corect doar liniile **ramase** in `crsfactura`, indiferent cate au fost adaugate si sterse
-intre timp — pentru ca fiecare stergere anuleaza exact adaugarea corespunzatoare.
-
-**In varianta recomandata (b+c):** cazul limita devine **trivial**, nu doar acoperit — pentru ca nu
-mai exista o stare intermediara de sincronizat. Rolul A: `do_scrie_factura` calculeaza remainder-ul
-o singura data, la scriere, din `VANZARI_DETALII_TEMP` care contine **exact** liniile ramase in
-`crsfactura` la acel moment (populat de `do_scrie_articole()` chiar inainte, `Scan` peste `crsfactura`
-curent — sectiunea 4 varianta (b)) — liniile adaugate-si-sterse nu ajung niciodata in
-`VANZARI_DETALII_TEMP`, deci nu influenteaza calculul, fara nicio actiune suplimentara. Rolul B:
-plafonul la fiecare adaugare se cere din nou pe server, minus ce e deja in `crsfactura` in acel
-moment — o stergere anterioara pur si simplu nu mai apare in acea suma, fara "refacere" explicita.
-**Cazul limita nu mai e un caz special de tratat — e comportamentul implicit al oricarei citiri facute
-din starea curenta, in loc de dintr-un contor tinut manual.**
-
----
-
-## 6. Per tip de document
-
-| Tip(uri) | Rol azi | Ce se schimba in varianta recomandata |
-|---|---|---|
-| **Comanda** `3,21,25,28,42,47` | Rol A (inchidere automata) | `do_scrie_factura` cheama functia Oracle noua (4b) in loc de `Calculate Sum`; `do_adauga_tot`/`do_sterge` raman (enumerare + Rol B nu se aplica pe comanda insasi, doar pe articolele ei individuale daca sunt gestionabile — **de verificat**, comanda nu apare in niciuna din listele Rol B de la sectiunea 1, deci pare curatata deja) |
-| **Avize** `4` | Rol A (marcheaza_facturat) | idem, functia Oracle pentru avize (4b) |
-| **Contract** `2,6,26,52` | Jumatate `crsarticole` (delegat la `cursor_preturi`, per raportul punctului 1) e Rol B doar pentru `poDate.tip=2 And opt_facturare=0`; restul (`crsarticole1`, rate+articole `OPT_FACTURARE=3`) nu are bookkeeping in sectiunea 1 (needitat de cautare, ramane cum e azi, per raportul punctului 1 sectiunea 7) | Rolul B pe jumatatea `opt_facturare=0` trece pe varianta (c); `26,52` nu apar in niciuna din listele Rol B/A gasite in cod — **de verificat separat, posibil fara bookkeeping deloc pe aceste doua**, nesemnalat ca atare in codul citit aici |
-| **Transfer** `41` (standard); `23` (doar prototip, standard il trateaza ca lista de preturi) | Rol B pur (niciun Rol A — confirmat sectiunea 3.1, `41`/`23` cad pe `ELSE` in `finalizeaza_factura`) | Trece integral pe varianta (c); **aceasta e corectia care debloca pasul 5 al punctului 1** — fara ea, oprirea incarcarii in masa pe `23,41` (propusa acolo) ar sparge plafonul de stoc existent |
-| **Lista de preturi** `1,5,7,10,22,29` | Rol B doar pentru articole gestionabile (`1,22,29`; `5,7,10` nu apar in Do Case-urile Rol B — **fara bookkeeping**, confirmat pe cod) | `1,22,29` trec pe varianta (c); `5,7,10` nu au nimic de decuplat, deja curatate |
-| **Retur** `8,9,24` | Rol B (inversul directiei fata de restul) | Varianta (c), simetric |
-| **Restaurant `45`, K `48,49`** | Nu ating Rol A/B (in afara `Do Case`-urilor gasite; `45` explicit exclus la `poArticol.gestionabil=0 Or gnScadereStoc=0 Or poDate.tip=45` in ambele metode, deci ocoleste bookkeeping-ul indiferent de gestionabilitate) | Fara schimbare — deja fara bookkeeping de decuplat |
-
-**Tipuri semnalate ca neclare, de stabilit separat, nu presupuse aici:** `26` (aviz din contract) si
-`52` (contract in valuta/alt subtip) nu apar explicit in niciuna din listele Rol A/B din sectiunea 1 —
-codul citit in aceasta sesiune nu confirma nici prezenta, nici absenta bookkeeping-ului pe ele
-specific; tratamentul lor pare sa urmeze grupul `2,6` din `Inlist`-urile care le includ, dar niciun
-`Do Case` din sectiunea 1 nu le mentioneaza individual in afara de includerea in `Inlist(poDate.tip,
-2, 6, 52)` la `do_scrie_articole` (rate) — nu la bookkeeping-ul de `crsarticole`.
-
----
-
-## 7. Pasi de implementare, ordonati
-
-1. **Pas 1 — Oracle: extrage functiile de recalcul remainder** (`cantitate_ramasa_comanda`,
- `exista_ramas_avize`) din logica deja scrisa in `inchide_comanda`/`marcheaza_facturat`, fara sa
- modifice acele proceduri. *Gata cand:* apelate manual cu parametrii unei comenzi/unui grup de avize
- cunoscute, valoarea returnata coincide cu suma pe care `Calculate Sum(cantitate)` din VFP o
- calculeaza azi peste `crsarticole`, pe acelasi document, in aceeasi stare (comparatie directa,
- inainte de orice alta schimbare).
-2. **Pas 2 — VFP: `do_scrie_factura` cheama functiile noi in loc de `Calculate Sum`** (sectiunea 4b),
- pastrand identic restul logicii (`pnFacturaRetur`, mesajele de confirmare, `pnParametruAditional`).
- *Gata cand:* pe un document de comanda si unul de aviz, cu acelasi scenariu (facturare partiala),
- dialogul de confirmare apare in acelasi moment si cu acelasi rezultat ca inainte de Pas 2 — regresie
- manuala, comparatie inainte/dupa pe acelasi document.
-3. **Pas 3 — Oracle: functie de plafon Rol B filtrata pe articol**, reutilizand `WHERE`-ul din
- `cursor_preturi`/`cursor_gestiune` (deja proiectat la S4 punctul 1, sectiunea 4), minus ce e deja in
- `crsfactura` pentru acelasi articol. *Gata cand:* pe un articol gestionabil cunoscut, valoarea
- returnata coincide cu `crsarticole.cantitate` de azi, la aceeasi stare a sesiunii (inainte de orice
- adaugare).
-4. **Pas 4 — VFP: `do_adauga_articol`/`do_sterge`/`do_modifica` folosesc plafonul cerut pe server**
- pentru grupul Rol B, in loc de `Replace cantitate` pe `crsarticole` (sectiunea 4c). *Gata cand:*
- cazul limita de la sectiunea 5 (adauga-apoi-sterge inainte de salvare) produce acelasi plafon
- disponibil ca azi, verificat manual pe un articol cu stoc limitat.
-5. **Pas 5 — activarea pasului 5 al punctului 1 pe `23`/`41`** (oprirea incarcarii in masa), acum ca
- Pasul 4 a mutat Rolul B in afara lui `crsarticole`. *Gata cand:* deschiderea formularului pe tip
- `41` (si `23` pe prototip) nu mai executa `cursor_gestiune`/`cursor_preturi` la deschidere, dar
- adaugarea unui articol tot respecta plafonul de stoc (verificat manual).
-6. **Pas 6 — curatare: `crsarticole` ramane incarcat doar unde e nevoie de enumerare** (comanda, aviz,
- contract-rate — pentru "adauga tot" existent), fara bookkeeping legat de el. *Gata cand:* grep pe
- `ofacturare.vc2` pentru `Replace cantitate.*crsarticole` (in afara populare) nu mai gaseste
- potriviri in `do_adauga_articol`/`do_sterge`/`do_modifica`.
-7. **Pas 7 — verificare paritate finala** (sectiunea 8), pe toate tipurile cu document sursa.
-
-*Depinde de:* S4 punctul 1 (Pasii 1-4 din PROIECTAREA acelui punct trebuie sa existe, dar Pasii 1-4
-**de aici** pot fi facuti independent, inaintea sau in paralel cu populare — nu depind de cautarea
-filtrata, doar de `crsarticole`/`crsfactura` existente azi). Pasul 5 de aici depinde explicit de Pasul
-4 de aici (nu poate porni inaintea lui).
-
----
-
-## 8. Cum se verifica paritatea inchiderii automate
-
-**Comanda** (nu exista flag `INCHISA` persistat — cautat explicit in tot pachetul, zero potriviri;
-starea se deriva din `COMENZI_ELEMENTE` vs `VANZARI_DETALII`):
-
-```sql
--- inainte de facturare partiala + inchidere fortata (flux vechi vs nou, aceeasi comanda X)
-{call pack_facturare.cursor_comanda(V_DATA_CURS, V_TIP, 'X', V_ID_UTIL, :cursor)}
--- numara randurile ramase (trebuie sa fie 0 dupa inchidere fortata, identic pe ambele fluxuri)
-SELECT COUNT(*) FROM (...continutul cursorului de mai sus...);
-
--- verificare directa a compensatiei inserate de inchide_comanda
-SELECT ID_ARTICOL, ID_POL, CANTITATE FROM COMENZI_ELEMENTE
- WHERE ID_COMANDA = :X ORDER BY ID_COMANDA_ELEMENT DESC; -- randul nou trebuie sa fie identic pe ambele fluxuri (aceeasi cantitate compensatorie)
-```
-
-**Avize** (flag real: `VANZARI.FACTURAT`):
-
-```sql
-SELECT ID_VANZARE, FACTURAT, ID_UTILFACT FROM VANZARI
- WHERE ID_VANZARE IN (:lista_avize_test)
- ORDER BY ID_VANZARE;
--- rulat dupa fiecare flux (vechi, apoi nou, pe date de test resetate identic), FACTURAT trebuie sa coincida rand cu rand
-```
-
-**Protocol de comparatie**, aplicabil pe fiecare tip cu document sursa (comanda: alege una din
-`3,21,25,28,42,47`; avize: `4`):
-1. reseteaza datele de test la aceeasi stare (aceeasi comanda/aviz, aceleasi cantitati ramase);
-2. factureaza partial pe fluxul **vechi** (cod actual), noteaza rezultatul interogarilor de mai sus;
-3. reseteaza din nou la aceeasi stare initiala;
-4. factureaza identic (aceleasi linii, aceleasi cantitati) pe fluxul **nou** (dupa Pasii 1-2 din
- sectiunea 7), noteaza acelasi rezultat;
-5. compara — trebuie sa fie identic, inclusiv pe cazul limita de la sectiunea 5 (adauga-si-sterge
- inainte de salvare) si pe cazul avizelor multiple agregate intr-o singura factura (sectiunea 3.3,
- riscul de marcare in bloc).
-
-**Zero cazuri testate azi nu e dovada** (memorie de proiect) — protocolul de mai sus cere minim un
-caz per tip din lista, plus cazul limita, nu doar "a mers o data".
-
----
-
-## 9. Riscuri si ce ramane de decis de Marius
-
-- **Corectia sectiunii 0/6**: pasul 5 al proiectarii punctului 1 (`s4_cautare_articole_server.md:417-424`)
- presupune ca `23,41` n-au bookkeeping de pastrat — gasit aici ca au Rol B activ. **De confirmat cu
- Marius daca punctul 1 se re-deschide pentru aceasta corectie sau ramane cum e, cu mentiunea ca
- aplicarea pe `23,41` asteapta finalizarea punctului 2** (asa cum recomand la Pasul 5, sectiunea 7).
-- **Asimetria `do_modifica` fata de `do_adauga_articol`/`do_sterge`** (sectiunea 1.3, grupul
- `1,22,29,2`-lista nu se ajusteaza la editarea cantitatii unei linii existente) — **preexistenta**,
- nu introdusa de decuplare. De decis daca varianta noua (Rol B pe server, sectiunea 4c) trebuie sa
- reproduca exact aceasta asimetrie (plafonul nu se recalculeaza corect la editare pe aceste tipuri,
- ca azi) sau sa o corecteze ca efect secundar al recalcularii la cerere (care, prin natura ei, ar
- elimina automat asimetria — orice cerere de plafon citeste starea curenta, indiferent daca a fost
- o adaugare sau o editare). **Recomandare: lasat sa se corecteze de la sine** (comportament mai
- corect, cost zero suplimentar, dar semnaleaza explicit ca S4 schimba acest comportament punctual,
- nu doar "decupleaza" — de mentionat in changelog daca se alege aceasta cale).
-- **Riscul de concurenta multi-utilizator, semnalat ca beneficiu la sectiunea 4b, dar nediscutat cu
- Marius**: varianta recomandata face `crsarticole` local sa nu mai poata diverge de Oracle *la
- scriere*, dar tot poate divarge *in timpul editarii* (doi operatori pe aceeasi comanda, unul
- vede plafonul invechit pana la urmatoarea lui adaugare/editare). Nu e un risc nou introdus — e
- identic cu azi pe cursorul static incarcat o data la deschidere — dar varianta (c) il reduce (cere
- plafonul proaspat la fiecare adaugare, nu o singura data la deschidere), fara sa-l elimine complet
- (ramane fereastra intre "am cerut plafonul" si "am scris linia"). De mentionat ca imbunatatire, nu
- garantie.
-- **Cont Rol B pe contract `26,52`**: nu s-a gasit dovada nici de prezenta, nici de absenta bookkeeping
- pe aceste doua tipuri in codul citit (sectiunea 6) — de verificat separat inainte de a le include in
- Pasul 3/4 al implementarii, nu de presupus ca urmeaza grupul `2,6`.
-- **Functiile Oracle noi (Pas 1, sectiunea 7) sunt o extragere, nu o duplicare** — dar tot inseamna cod
- PL/SQL nou in `PACK_FACTURARE`, care trebuie revizuit separat de cineva familiar cu pachetul
- (schema exacta a `JOIN`-urilor din `inchide_comanda`, reprodusa aici din citire, nu din executie
- reala pe Oracle — verificarea Pasului 1 din sectiunea 7 e obligatorie inainte de a continua).
-
-## Handoff
-
-Cercetare incheiata in aceasta sesiune. Toate cele 9 puncte cerute sunt acoperite, cu citate
-`fisier:linie` verificate direct pe fisierele reale (`ofacturare.vc2`, nu `.bak`; corpul
-`PACK_FACTURARE.sql`, nu spec-ul comentat). Descoperirea centrala (Rol A vs Rol B, si corectia asupra
-pasului 5 al punctului 1 pentru `23`/`41`) nu era vizibila din raportul punctului 1 — acela trata
-`crsarticole` ca un singur registru omogen; aici s-a aratat ca sunt doua mecanisme cu scopuri
-diferite, unul (Rol A) recalculat oricum de Oracle la scriere si deci usor de mutat pe server fara
-pierdere de paritate, celalalt (Rol B) un plafon UI care nu alimenteaza nicio decizie de business.
-
-Niciun fisier de cod atins, niciun `git_sync.ps1`/`txt2vcx.ps1` rulat, nicio scriere pe Oracle (doar
-`Read`/`Select-String`/`grep` pe fisiere de pe disc).
diff --git a/docs/cercetare/s4_puncte_deschise.md b/docs/cercetare/s4_puncte_deschise.md
deleted file mode 100644
index 7faacd5..0000000
--- a/docs/cercetare/s4_puncte_deschise.md
+++ /dev/null
@@ -1,246 +0,0 @@
-# Cercetare — doua puncte deschise inainte de implementarea S4
-
-Investigatie READ-ONLY, doua intrebari inchise din `docs\plan_13_unificare_formular_facturare.md`,
-`#### S4`, sectiunea "De inchis inainte de implementare" (`:2092-2095`). Fara editari de cod, fara
-`git_sync.ps1`/`txt2vcx.ps1`, fara commit, fara scriere pe Oracle (numai `SELECT`).
-
-Status: **GATA**. Ambele intrebari au raspuns confirmat pe cod, cu `fisier:linie`. Amandoua
-raspunsurile de baza confirma "nu schimba nimic", dar fiecare are o rezerva concreta, nu triviala,
-de pus in proiectarea S4 (nu doar de bifat).
-
-Sursa Oracle: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`
-(17217 linii — liniile citate mai jos sunt verificate direct pe acest fisier, corpul pachetului).
-Sursa VFP: `COMUN\clase\ofacturare.vc2`, `COMUN\programe\ofacturare.prg` (perimetrul `frm_facturare_articole`
-/ `factureaza`; `frm_facturare_articole2` / `factureaza2` citite doar pentru comparatie, nu atinse).
-
----
-
-## Intrebarea 1 — `id_jtva_coloana` lipseste din `cursor_preturi`?
-
-### 1.1 Ce e si cine o consuma
-
-`id_jtva_coloana` identifica randul din `JTVA_COLOANE` (explicatia/coloana de TVA folosita la
-raportare si SAFT) asociat unei linii de factura. E scris pe fiecare linie in `VANZARI_DETALII_TEMP`
-(Oracle, prin `adauga_articol_factura`) si citit inapoi de UI-ul VFP pentru dialogul de "explicatie
-TVA" (`Cb_explicatie_Tva`, `frm_articol_factura`).
-
-### 1.2 Chiar lipseste din `cursor_preturi`? — confirmat pe SQL
-
-Toate cele **cinci ramuri** ale `cursor_preturi` (`WHEN V_TIP = 45`, `WHEN V_TIP IN (1,2)`,
-`WHEN V_TIP IN (5,6,10,52)`, `WHEN V_TIP = 7`, `ELSE` aviz — corpul la
-`ff_...PACK_FACTURARE.sql:2138-2644`) au liste de coloane complete verificate direct — **niciuna nu
-returneaza `id_jtva_coloana`** (`:2163-2221`, `:2268-2329`, `:2394-2427`, `:2470-2504`, `:2545-2603`).
-`cursor_facturare` e un `REF CURSOR` slab tipat (`:28`), deci lista de coloane a fiecarei ramuri e
-literal ce se vede in `SELECT`, fara camp implicit.
-
-Acelasi lucru e adevarat si pentru **`cursor_gestiune`** (`:4158-4347`, coloanele la `:4207-4343`) —
-relevant pentru intrebarea 2, tipul 41. `cursor_contract` (`:2646-2950`) delega `V_CURSOR` la
-`cursor_preturi` (deci mosteneste lipsa), iar `V_CURSOR2` (rate + articole `OPT_FACTURARE=3`,
-`:2718-2938`) **de asemenea nu are `id_jtva_coloana`** in niciuna din cele doua ramuri `UNION ALL`.
-
-Prin contrast, **`cursor_avize`** (`:3703-3874`) **are** `A.ID_JTVA_COLOANA` explicit (`:3748`,
-plus `GROUP BY`-urile de la `:3781`, `:3804`, `:3822`, `:3843`) si `cursor_comanda` (`:2952-3171`)
-**nu are**, pe niciuna din cele doua ramuri (factura/aviz, `:2994-3170`). Deci impartirea reala e:
-*are* — doar `cursor_avize`; *nu are* — `cursor_preturi`, `cursor_gestiune`, `cursor_contract`
-(ambele cursoare), `cursor_comanda`.
-
-### 1.3 E completat in alt pas, sau ramane gol? — DA, e completat, printr-un mecanism in doi pasi
-
-Pasul 1 — **valoare implicita, nu `NULL`**. `do_initializeaza_articol`
-(`ofacturare.vc2:13681-13683`, identic la `:17896-17897` pe prototip):
-```
-If Type('toArticol.id_jtva_coloana') = 'U'
- AddProperty(toArticol,'id_jtva_coloana',0)
-Endif
-```
-Daca `Scatter Name poArticol` dintr-un cursor fara coloana `id_jtva_coloana` produce un obiect fara
-acea proprietate (`Type(...) = 'U'`), se adauga cu valoarea **`0`** (numeric, nu `NULL`).
-
-Pasul 2 — **derivare reala din `proc_tvav`, neconditionata**. `frm_articol_factura.Init`
-(`ofacturare.vc2:2344-2371`) suprascrie *intotdeauna* `id_jtva_coloana`, indiferent de ce a venit din
-cursor:
-```
-Select jtva_coloane
-If !Isnull(poArticol.proc_tvav)
- Set Filter To cota_tva = poArticol.proc_tvav * 100 - 100
- ...
- poArticol.id_jtva_coloana = id_jtva_coloana
-Else
- ...
- poArticol.proc_tvav = (cota_tva + 100)/100
- poArticol.id_jtva_coloana = id_jtva_coloana
-EndIf
-```
-`proc_tvav` **este** returnat de toate cele cinci ramuri ale `cursor_preturi` (coloana comuna,
-confirmata la 1.2), deci lookup-ul are mereu ce derivea, indiferent daca `id_jtva_coloana` a lipsit
-din cursorul sursa.
-
-Acest `Init` ruleaza pentru **orice** linie adaugata prin `do_adauga_articol`
-(`ofacturare.vc2:12813-13167`), pe ambele ramuri ale `Do Case` de la `:12870-12896`:
-- articol negestionabil / `gnScadereStoc=0` / restaurant (`tip=45`) →
- `Createobject("frm_articol_factura", ...)` direct (`:12873`);
-- articol gestionabil (`Otherwise`, `:12881-12895`) → `do_alege_stoc` →
- `Createobject("frm_articol_gest_factura", ...)` (`:13353`/`:13361`/`:13375`) — clasa care
- **mosteneste** `frm_articol_factura` (`vfp_symbols -Class`: `frm_articol_gest_factura ->
- frm_articol_factura -> _frmbase -> _form`) si al carei `Init` (`:3986-3989`) cheama
- `DoDefault(tnCantitate,tlAscunde)` — deci ruleaza acelasi `Init` de la 2315-2371, cu aceeasi
- derivare.
-
-**Confirmare ca derivarea chiar functioneaza si nu doar exista in cod:** `do_alege_stoc`
-(`:13330-13340`) avea, intr-o versiune anterioara (comentata, `v 2.2.18`), un scurtcircuit care
-seta direct `id_jtva_coloana` fara sa mai arate formularul cand exista o singura optiune de TVA;
-azi acel scurtcircuit e dezactivat si se creeaza intotdeauna obiectul `frm_articol_gest_factura`
-(deci `Init` ruleaza mereu, nu doar in cazuri rare).
-
-Safety-net-ul `Case Empty(poArticol.id_jtva_coloana)` din `inainte_de_do_termin`
-(`:2205-2208`, mostenit si de `frm_articol_gest_factura`) e o verificare reziduala pentru cazul in
-care nici `proc_tvav` n-are match in `jtva_coloane` — nu dovada ca `id_jtva_coloana` ramane gol azi
-pe fluxul normal.
-
-### 1.4 Concluzia care conteaza — cu o rezerva reala, nu ipotetica
-
-**Pe fluxul de azi (`do_adauga_articol`), lipsa lui `id_jtva_coloana` din `cursor_preturi`/
-`cursor_gestiune` NU e un bug** — e completat corect, de doua ori (default 0, apoi derivat real din
-`proc_tvav`), pe ambele ramuri (gestionabil/negestionabil), inainte ca linia sa ajunga in
-`crsfactura` (`Gather ... id_jtva_coloana ...`, `:12945-12950`/`:12992-12995`) si, de acolo, in
-Oracle (`do_scrie_articole` → `adauga_articol_factura(...)`, `Alltrim(Str(poArt.id_jtva_coloana))`,
-`:14085`).
-
-**Rezerva: raspunsul "filtrarea nu schimba nimic" e adevarat DOAR daca implementarea S4 pastreaza
-trecerea prin `do_adauga_articol`/`frm_articol_factura.Init` pentru linia aleasa.** Cercetarea
-anterioara (`docs\cercetare\s4_cautare_articole_server.md`, sectiunea 5) arata ca **singurul exemplu
-real existent de cautare-pe-server** (`combosql`, `grd_factura.cCodMat.cboCodmat.LostFocus`,
-`ofacturare.vc2:19288-19306`) **nu trece prin `do_adauga_articol` deloc** — face `REPLACE` direct in
-`crsFactura`:
-```
-REPLACE codmat WITH crsCodMat.codmat, denumire WITH crsCodmat.denumire, id_articol WITH crsCodmat.id_articol IN crsFactura
-```
-Acelasi tipar identic pe coloana `cDenumire` (`:19312-19317`). Daca S4 extinde acest `REPLACE` cu
-restul campurilor din cursorul filtrat — asa cum recomanda raportul anterior la sectiunea 5, punctul
-4 ("sa extinda REPLACE-ul... cu restul campurilor") — **`id_jtva_coloana` nu mai trece prin niciun
-`do_initializeaza_articol`/`frm_articol_factura.Init`**, pentru ca acel `REPLACE` nu creeaza obiectul
-`poArticol` si nu instantiaza formularul. Cursorul filtrat tot n-are `id_jtva_coloana` (varianta
-filtrata a `cursor_preturi` pastreaza aceeasi lista de coloane — vezi
-`s4_cautare_articole_server.md:220`), deci randul din `crsFactura` ar ramane cu valoarea implicita
-de camp (`Append Blank`, nu exista un `REPLACE` explicit pe acea coloana) — **fara nicio derivare din
-`proc_tvav`**.
-
-La scriere, `adauga_articol_factura` (Oracle) cauta `ID_JTVA_COLOANA = V_ID_JTVA_COLOANA` in
-`JTVA_COLOANE` pe ramura `ELSE` a `CASE`-ului sau (`ff_...PACK_FACTURARE.sql:5187-5198` — ramura care
-se aplica exact tipurilor de lista de preturi 1/5/7/10/22/29, tipurile de transfer 23/45/48/49 si
-altele care nu intra in ramurile speciale comanda/aviz/restaurant/contract-cu-pret-fix) si, daca nu
-gaseste o potrivire, **arunca `RAISE_APPLICATION_ERROR(-20000, 'Nu a fost gasita cota de TVA!
-(FACT-013 : ...)')`**. O valoare implicita de camp (tipic `0`, posibil `NULL` dupa `Append Blank`,
-de verificat pe structura reala a `crsfactura`) ar produce fie acest -20000, fie (daca exista un rand
-`JTVA_COLOANE.ID_JTVA_COLOANA=0`) o cota de TVA gresita scrisa tacut — amandoua ar fi un **bug nou,
-introdus de S4**, nu unul preexistent.
-
-**Recomandare concreta pentru proiectarea S4 (nu doar constatare):** varianta filtrata a cautarii
-(oricare ar fi mecanismul concret — `combosql` extins sau altceva) trebuie sa continue sa treaca prin
-`do_adauga_articol`/`frm_articol_factura.Init` pentru linia aleasa (sau sa reproduca explicit
-derivarea din `proc_tvav` daca se alege un `REPLACE` direct), nu doar sa extinda `REPLACE`-ul de azi
-cu campurile brute din cursor. De pus explicit ca cerinta in proiectarea S4, nu ca detaliu care se
-rezolva de la sine.
-
----
-
-## Intrebarea 2 — `cursor_gestiune` (tipurile 23/41) fara buton "adauga tot"?
-
-### 2.1 Vizibilitatea butonului pe cod — confirmata
-
-`but_urmator_tot1` are **`Visible = .F.` la design-time**
-(`ofacturare.vc2:11257-11266`, `ADD OBJECT 'But_urmator_tot1' AS but_urmator_tot WITH ... Visible =
-.F. ...`). Devine vizibil doar prin `This.but_urmator_tot1.Visible = .T.` explicit, in 8 locuri din
-`Do Case poDate.tip` din `Init` (`:15108-15248`):
-
-| Tip | Vizibil? | Linia care il seteaza |
-|---|---|---|
-| `eProforma=1` | da | `:15113` |
-| `lCopiere` | da | `:15120` |
-| `1,5,7,10` (lista de preturi) | **nu** (fara linie) | — |
-| `2,6` (contract) | **nu** | — |
-| `3` (comanda) | da | `:15150` |
-| `4` (avize) | da | `:15166` |
-| `21,28,42,47` (aviz din comanda) | da | `:15177` |
-| `22,29` (aviz din lista de preturi) | **nu** | — |
-| **`23`** (transfer subunitati) | **nu** — are propriul `Case` (`:15187-15195`), dar niciun `Visible=.T.` in el | — |
-| **`41`** (retur transfer) | **nu** — are propriul `Case` (`:15197-15205`), dar niciun `Visible=.T.` in el | — |
-| `25` (transfer din comanda) | da | `:15215` |
-| `26` (aviz din contract) | **nu** | — |
-| `8,9` (retur) | da | `:15240` |
-| `24` (aviz retur) | da | `:15245` |
-
-**Confirmat: 23 si 41 au fiecare `Case` propriu in `Do Case`** (nu lipsesc din el, spre deosebire de
-tipul 52, verificat separat intr-o cercetare anterioara ca "nu intra in niciun `Case`") — dar niciunul
-din cele doua `Case`-uri nu seteaza `Visible = .T.`, deci butonul ramane la valoarea implicita
-ascunsa. Concluzie identica cu lista de preturi (1/5/7/10): "adauga tot" e ascuns azi, nu doar
-"neconfirmat".
-
-### 2.2 Exista alt mecanism de adaugare in masa pe 23/41?
-
-**Nu unul dedicat — dar exista mecanismul de baza, "adauga rand cu rand", disponibil pe orice tip.**
-`But_urmator1` (singular, nu "tot") e `ADD OBJECT`-at neconditionat in definitia clasei
-(`ofacturare.vc2:11237`), fara vreun `Visible=.F.` la design-time si fara sa fie atins de `Do Case`
-de la 15108-15248 (acolo se atinge doar `but_urmator2`, aferent `grd_contracte`/contract, scos prin
-`RemoveObject` pentru tipurile non-contract, `:15322-15323` — nu are legatura cu 23/41). Lantul e
-`But_urmator1.Click` → `do_urmator()` → `Thisform.do_adauga_articol()` (`:14715`) — exact metoda cu
-derivarea de TVA confirmata la intrebarea 1. Deci pe 23/41, ca si pe lista de preturi, operatorul
-adauga **o linie o data**, prin acelasi buton/metoda folosit si azi pe tipurile de lista de preturi —
-nu exista un "adauga tot" separat de recreat, pentru ca nu exista nici azi.
-
-### 2.3 Cine mai foloseste `cursor_gestiune` — CORECTIE fata de premisa din plan
-
-Rutarea reala e in `ofacturare.prg`, procedura `factureaza` (formularul **standard**,
-`frm_facturare_articole` — cel lansat implicit), `Do Case` de la `:266-308`:
-
-```
-Case Inlist(tnTip, 1, 22, 5, 29, 7, 10, 23) && lista de preturi -> cursor_preturi (:279-282)
-Case Inlist(tnTip, 2, 26, 6, 52) && contract -> cursor_contract (:283-290)
-Case Inlist(tnTip, 3, 21, 25, 28, 42, 47) && comenzi -> cursor_comanda (:292-293)
-Case tnTip = 4 && din avize -> cursor_avize (:294-295)
-Case Inlist(tnTip, 41) && transfer/retur -> cursor_gestiune (:296-298)
-Case tnTip = 30 -> cursor_aviz_nir (:299-300)
-Case tnTip = 27 -> cursor_lucrare (:302-304)
-Case Inlist(tnTip, 8, 9, 24) -> cursor_retur (:306-307)
-```
-plus, mai sus in acelasi `Do Case` (`:271-278`): `Case Inlist(tnTip, 48, 49)` → **`cursor_articole_k`**
-(procedura complet diferita, nu una din cele cinci) si `Case tnTip = 45` → **`cursor_preturi`**.
-
-**Pe formularul standard: doar tipul 41 foloseste `cursor_gestiune`.** Tipul **23 foloseste de fapt
-`cursor_preturi`**, grupat direct cu tipurile de lista de preturi (1,22,5,29,7,10) — asta explica de
-ce, la 2.1, tipul 23 se comporta identic cu lista de preturi (acelasi cursor sursa). Tipurile **45 si
-48/49 nu ating deloc `cursor_gestiune`**: 45 → `cursor_preturi`, 48/49 → `cursor_articole_k` (iese
-din perimetrul celor cinci cursoare din S4). Premisa din plan ("`cursor_gestiune` — tipurile 23/41")
-si mentiunea "45, 48, 49" (`s4_cautare_articole_server.md:344`, tabelul de vizibilitate) **descriu
-corect vizibilitatea butonului** (toate aceste tipuri au "adauga tot" ascuns), dar **nu si sursa lor
-de cursor** — nu toate trec prin `cursor_gestiune`.
-
-**Pe formularul prototip** (`frm_facturare_articole2`/`factureaza2`, accesibil live doar cu optiunea
-`gnFacturareNou=1` **si** alegerea explicita a operatorului la un dialog de confirmare,
-`ofacturare.prg:88-93` — deci reachable in productie, nu cod mort, dar opt-in), rutarea **difera**:
-`Case Inlist(tnTip, 23, 41)` (`ofacturare.prg:776-778`) cheama **impreuna** `cursor_gestiune` pentru
-**ambele** tipuri. Pe acest formular, premisa din plan e exacta. Divergenta intre cele doua formulare
-(23 pe `cursor_preturi` in cel standard, pe `cursor_gestiune` in prototip) nu pare intentionata — nu
-exista niciun comentariu care s-o justifice — dar e in afara perimetrului acestei cercetari (read-only,
-fara editare) si nu afecteaza concluzia de mai jos, valabila pe oricare din cei doi cursori (niciunul
-nu are `id_jtva_coloana`, ambii sunt tratati identic de `do_adauga_articol`).
-
-### 2.4 Concluzia care conteaza
-
-**Dupa S4, pe tipurile 23/41 nu se pierde nimic functional.** "Adauga tot" e deja absent azi pe
-ambele (confirmat pe cod, 2.1), iar adaugarea se face deja rand-cu-rand prin acelasi mecanism folosit
-si pe lista de preturi (`but_urmator1`/`do_urmator`/`do_adauga_articol`, 2.2) — mecanism pe care S4 nu
-il atinge (S4 schimba doar sursa cursorului incarcat la deschidere, nu calea de adaugare a unei linii
-individuale). Aceeasi rezerva de la intrebarea 1 se aplica identic aici: valabil doar daca varianta
-filtrata a cautarii trece prin `do_adauga_articol`, nu daca reproduce `REPLACE`-ul direct din
-`combosql`.
-
----
-
-## Handoff
-
-Nu e necesara predare — ambele intrebari sunt inchise, cu dovada pe cod. Rezervele de la 1.4 si 2.4
-(derivarea `id_jtva_coloana` trebuie sa treaca prin `do_adauga_articol`/`frm_articol_factura.Init`,
-nu prin `REPLACE` direct tip `combosql`) sunt de dus mai departe in proiectarea S4, nu doar de
-arhivat aici. Corectia de la 2.3 (doar tipul 41, nu si 23, foloseste `cursor_gestiune` pe formularul
-standard) merita reflectata daca planul S4 mai citeaza undeva "cursor_gestiune (23/41)" ca sursa unica.
diff --git a/docs/cercetare/s4b_bara_butoane_meniu.md b/docs/cercetare/s4b_bara_butoane_meniu.md
deleted file mode 100644
index 34543d2..0000000
--- a/docs/cercetare/s4b_bara_butoane_meniu.md
+++ /dev/null
@@ -1,606 +0,0 @@
-# S4b — Bara de butoane si meniul de adaugare
-
-Proiectare pe cod, READ-ONLY (fara editari, fara `git_sync.ps1`/`txt2vcx.ps1`, fara commit), pentru
-povestea **S4b** din `docs\plan_13_unificare_formular_facturare.md:1890-1899` (textul decis in
-sectiunea J, `:911-1101`). Nu s-a atins `COMUN\clase\ofacturare_comun.vc2` si
-`COMUN\programe\ofacturare_editare.prg` (perimetrul #6) — doar citite, cand au aparut in cautari.
-
-## Verdict (esenta, 10 randuri)
-
-Cele trei bucati din decizia 13 sunt implementabile fara cod nou major, dar cu **trei corectii fata
-de textul din plan**, toate in favoarea utilizatorului: (1) golul de contract nu e doar
-`but_urmator_tot1.Visible` lipsa pe tip 2/6/26 — pe **tip 52 formularul nu intra deloc in ramura
-lui**, `Do Case` nu are niciun `Case` care sa-l prinda, deci pierde si titlul, si eliminarea coloanei
-`cSerie`, nu doar butonul "tot"; (2) tiparul RORIS (`frm_tranzit`, dialog bespoke) **nu e cel mai
-ieftin de refolosit** — suita are deja, folosit chiar in acest formular pentru retur
-(`do_cauta_facturi`), un mecanism generic de selectie multipla cu bifare, `cauta_alfa(...,
-tnTipReturn=1)`, mai aproape de cerinta („dialog modal cu coloana de bifat si criterii de cautare")
-decat un formular nou; (3) „unitatea de selectie e rata" pe contract **nu e valabil pentru toate
-contractele** — cursorul `crsarticole1` are doua ramuri disjuncte, `OPT_FACTURARE=3` (articole reale)
-si `OPT_FACTURARE IN (1,2)` (rate de scadentar), iar un contract e mereu pe una singura; eticheta
-„Alege ratele de facturat…" e corecta doar pe ramura a doua. Echivalenta „tot" = „alege total" tine
-azi pe o singura rutina comuna, `do_adauga_articol`, dar `do_adauga_tot` **nu parcurge `crsarticole1`
-deloc** — pe contract, „adauga tot" ar trebui sa fie scris, nu doar facut vizibil. Detaliile, cu
-`fisier:linie`, mai jos.
-
----
-
-## 1. Inventarul butoanelor de azi
-
-### 1.1 `frm_facturare_articole` (formularul de compunere in productie, `ofacturare.vc2:10968-15739`)
-
-Grid sursa (comanda/lista preturi) = `grd_articole` (`RecordSource=crsarticole`,
-`ofacturare.vc2:11570`). Grid sursa-contract = `grd_contracte` (`RecordSource=crsarticole1`,
-`:11891`). Grid destinatie (linii factura) = `grd_factura` (`RecordSource=crsfactura`, `:12263`).
-
-| Control | Clasa | Caption/Picture | L/T/W/H | ToolTipText | `fisier:linie` |
-|---|---|---|---|---|---|
-| `But_modifica1` | `but_modifica` | (fara caption) `modific_sus.bmp` | 773/61/30/27 | "Modificare (CTRL+M)" | `:11192` |
-| `But_sterge1` | `but_sterge` | (fara caption) `sterg_sus.bmp` | 811/61/30/27 | "Stergere (CTRL+D)" | `:11229` |
-| `But_renunt1` | `but_renunt` | (fara caption) `renunt_sus.bmp` | 792/1/30/27 | "Renuntare (ESC)" | `:11202` |
-| `But_reset1` | `but_reset` | (fara caption) `reset_sus.bmp` | 303/295/30/27 | "Reseteaza" | `:11213` |
-| `But_urmator1` | `but_urmator`, `caction=do_urmator` | `urmator1.bmp` | 343/348/30/27 | "Verificare" | `:11237` |
-| `But_urmator2` | `but_urmator`, `caction=do_urmator2` | `urmator1.bmp` | 343/143/30/27 | "Verificare" | `:11247` |
-| **`But_urmator_tot1`** | `but_urmator_tot`, `caction=do_adauga_tot` | `urmator1_tot.bmp`, **fara Caption, fara ToolTipText** (clasa insasi nu are niciuna din ele — `cmd_butoane.vc2:414-425`) | 343/378/30/27, `Visible=.F.` implicit | — | `:11257` |
-| `But_retur` | `but_retur`, `caction=do_retur` | `retur1.bmp`, `Visible=.F.` implicit | 343/407/30/27 | "Retur" | `:11221` |
-
-Niciun buton "linie noua" (`but_nou`) — o linie se adauga alegand un rand din `grd_articole` /
-`grd_contracte` si apeland `do_adauga_articol` (dublu-click / Enter, mecanism de grid standard, nu
-citit exhaustiv aici), nu prin `APPEND BLANK` pe `crsfactura`. "Detalii linie" nu exista ca buton
-separat — `But_modifica1` **e** azi echivalentul: deschide `frm_articol_factura` pe randul curent din
-`crsfactura` (`do_modifica`, `:13746-13914`), reface plafonul de cantitate din cursorul sursa
-(`crsarticole` sau `crsarticole1`, ales prin `poArticol.opt_facturare`, `:13778`) si reconstruieste
-proprietatile de discount/pret in valuta.
-
-**"Adauga tot" — `But_urmator_tot1.Click -> do_adauga_tot`** (`:13169-13198`):
-
-```
-PROCEDURE do_adauga_tot
- If Used('crsarticole') And Reccount('crsarticole') > 0
- Select crsarticole
- Scan
- ...
- Thisform.do_adauga_articol(.T.) && tlContract = omis => .F. implicit
- ...
- Endscan
- Else
- aMessageBox("Nu exista articole de adaugat!", 48, "Atentie")
- Endif
-ENDPROC
-```
-
-**Parcurge exclusiv `crsarticole`.** Nu exista nicio ramura care sa parcurga `crsarticole1` — deci
-chiar daca s-ar face vizibil pe tip 2/6/26/52, "adauga tot" **nu ar aduce nimic** pe un contract al
-carui `grd_contracte`/`crsarticole1` are randuri (rate sau articole de contract), pentru ca butonul
-citeste doar cursorul celalalt. E un gol de **cod**, nu doar de vizibilitate — vezi sectiunea 5.
-
-**Conventia de clase de butoane** (confirmat, `inventar_controale_formulare.md`): clasa de baza
-`buton` (`_cmd_base.vc2:16`) are `Caption=""` implicit — butoanele sunt doar-imagine 30x27px prin
-design. `but_nou` (`cmd_butoane.vc2:214-227`, `caption=do_adauga`, `ToolTipText="Adaugare
-(CTRL+N)"`) si `but_sterge` (`:354-366`, `caption=inainte_de_do_sterge`, tot fara Caption propriu la
-nivel de clasa) au deja `ToolTipText`, dar niciodata `Caption` — "eticheta, nu iconita muta" ceruta de
-decizia 13 e o schimbare reala, nu o simpla refolosire a clasei: fie se seteaza `Caption` pe instanta
-(clasa `buton` are proprietatea, pur si simplu nefolosita azi), fie se creeaza o varianta de clasa cu
-`Caption` implicit.
-
-### 1.2 `frm_facturare_articole2` (prototip, `ofacturare.vc2:15741-19355`)
-
-Arhitectura diferita: **un singur grid** `grd_factura` cu editare inline prin combo-uri in celule
-(`cCodMat.cboCodmat`, `cDenumire.cCboDenumire`) — nu exista `grd_articole`/`crsarticole` separat.
-
-| Control | Clasa | Caption/Picture | L/T/W/H | ToolTipText | `fisier:linie` |
-|---|---|---|---|---|---|
-| **`But_nou1`** | `but_nou` (caption suprascris pe instanta, vezi mai jos) | `nou_sus.bmp` | 719/175/30/27 | "Adaugare (CTRL+N)" | `:15936` |
-| `But_sterge1` | `but_sterge` | `sterg_sus.bmp` | 747/175/30/27 | "Stergere (CTRL+D)" | `:15955` |
-| `But_renunt1` | `but_renunt` | `renunt_sus.bmp` | 716/1/30/27 | "Renuntare (ESC)" | `:15944` |
-
-**Sunt deja unde trebuie**: `Top=175`, gridul la `Top=204` (`:15936`, `:15955`) — **deasupra
-tabelului**, exact pozitionarea ceruta de decizia 13.
-
-**`But_nou1.Click -> do_adauga`** (`:17118-17122`, override propriu pe instanta, nu `caction`
-mostenit de la clasa `but_nou`):
-
-```
-PROCEDURE do_adauga
- Select crsFactura
- APPEND BLANK
- this.grd_factura.SetFocus()
-ENDPROC
-```
-
-Adauga direct un rand gol si da focus in grid — **nu** cheama `do_adauga_articol`, nu verifica stoc,
-nu deschide niciun dialog. Completarea articolului se face **dupa**, prin editare inline in celule
-(`cboCodmat`/`cCboDenumire`) — acesta e tiparul care se leaga direct de S4 (cautare pe server, vezi
-sectiunea 6), nu de meniul de adaugare in masa.
-
-Nu exista `But_modifica`/`detalii linie` in acest prototip — editarea se face inline, in celula.
-
-### 1.3 Tabel comparativ
-
-| | `frm_facturare_articole` (productie) | `frm_facturare_articole2` (prototip) |
-|---|---|---|
-| Pozitia butoanelor de linie | lateral, intre cele doua griduri (`Left=773+`) | deasupra gridului (`Top=175`, gridul la `Top=204`) — cerinta decizie 13 |
-| "Linie noua" | nu exista — se alege dintr-un grid sursa | `But_nou1` -> `APPEND BLANK` + focus |
-| "Sterge linie" | `But_sterge1`, lateral | `But_sterge1`, deasupra |
-| "Detalii linie" | `But_modifica1` -> `frm_articol_factura` (dialog complet) | nu exista — editare inline |
-| Sursa de articole | 2 griduri separate, `crsarticole`/`crsarticole1` | niciunul — combo pe cod/denumire in celula |
-| Caption pe butoane | fara, peste tot (doar iconite) | fara, peste tot (doar iconite) — nici prototipul nu rezolva "eticheta" |
-
-Concluzie pentru implementare: **pozitionarea** se ia din prototip, **comportamentul de adaugare in
-masa** (`do_adauga_tot`/dialoage de alegere) se ia din formularul de productie (prototipul nu are deloc
-aceasta logica — n-a fost construit pentru documente cu sursa), iar **eticheta pe buton** nu exista
-azi in niciunul din cele doua, e de adaugat explicit in ambele cazuri.
-
----
-
-## 2. `xmenu()` — contract si exemple
-
-**Definitie**: `COMUN\programe\proceduri_comune.prg:755-822` (identica, byte-cu-byte in structura, cu
-`COMUN\programe\oproceduri_comune.prg:1550-1617` — a doua e cea incarcata efectiv, SET PROCEDURE
-ADDITIVE peste prima, dar comportamentul e acelasi).
-
-```
-Procedure XMENU
- Lparameters TCITEMS, TNBAR
- && TCITEMS = optiuni separate prin ";" ; "\-" = separator vizual (bara, nu optiune selectabila,
- && nu se trece prin ALLTRIM); "\ 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.
-
-**ROAFACTURARE are deja, in productie, in acelasi `frm_facturare_articole` care e subiectul acestei
-povesti, mecanismul cerut** — `cauta_alfa()` (`COMUN\programe\cauta_alfa.prg:16-260`), functia de
-cautare generica folosita de zeci de `do_cauta_*` din toata suita. Are deja tot ce cere decizia 13:
-
-- **coloana de bifat**: cand `tnTipReturn=1`, `cauta_alfa` adauga singura o coloana `ales` peste
- cursorul de rezultate (`cauta_alfa.prg:124`: `Select *, 0 As ales From &lcCursort ... Into Cursor
- &lcCursor`) si titlul devine explicit "Alegeti ... (mouse-click pe numar sau apasati SPACE)"
- (`oproceduri_facturare.prg:2104`);
-- **criterii de cautare**: parametrul `tcStringCriterii` deschide `cauta_alfa_form_plus`, varianta cu
- bara de criterii (`cauta_alfa.prg:22`); fara el, cautarea alfa/browse standard tot filtreaza
- interactiv pe coloanele afisate;
-- **populare aditiva, fara scriere in baza**: returul (`tnTipReturn=1`) e un XML cu randurile bifate,
- convertit local prin `Xmltocursor(...)` (exemplu direct, `ofacturare.vc2:9196`) — nimic nu ajunge la
- Oracle in acest pas;
-- **e deja folosit in acest exact formular**, pentru un caz de "alege documentul sursa": vezi 4.2.
-
-**Recomandare de proiectare**: dialoagele "Alege..." din meniul S4b se construiesc pe reteta
-`cauta_alfa(..., tnTipReturn=1)`, cu `tcselect`/`tcfiltru` diferite pe sursa (comanda/contract/avize/
-retur), **nu** pe un formular nou stilizat dupa `frm_tranzit`. Ramane de portat din RORIS doar
-**ideea**, nu codul: buton unic condiționat, metoda de intrare unica, populare aditiva — toate trei
-deja adevarate si pentru `cauta_alfa`.
-
-### 4.2 Precedentul direct: retur multi-factura
-
-`frm_date_factura.do_cauta_facturi` (`ofacturare.vc2:9173-9212`) foloseste deja exact acest tipar,
-pentru cazul "alege mai multe facturi sursa de retur":
-
-```
-lcXMLFacturi = caut_facturi_multiple_client(poDate.id_client, poDate.in_valuta, poDate.id_valuta, .T.)
-If !Empty(lcXMLFacturi) and gnButon = 1
- Xmltocursor(lcXMLFacturi, "crsFacturiTemp")
- ...
- poDate.listaid = cursor2lista("crsFacturiTemp", "id_vanzare", ",")
-```
-
-si `caut_facturi_multiple_client` (`oproceduri_facturare.prg:2091-2121`) cheama direct
-`cauta_alfa(..., lnTipReturn = Iif(tlFacturiMultiple, 1, 0))`. **Important pentru sectiunea 9**: acest
-pas ruleaza azi la **antet** (`frm_date_factura`), inainte ca formularul de articole (si deci bara de
-butoane S4b) sa existe — `poDate.listaid` e fixat o singura data, cursorul `crsarticole` se incarca
-o singura data din el (`cursor_retur_document`, cu `V_LISTAID`). Optiunea "Adauga tot din facturile
-alese" din meniul S4b **poate** refolosi direct `do_adauga_tot`/`crsarticole` asa cum e azi (sursa e
-deja bounded). O optiune noua "Alege facturile de returnat…" **la nivelul barei de butoane** ar insemna
-insa a permite schimbarea setului de facturi sursa **dupa** ce formularul de articole s-a deschis —
-azi nu exista acest flux (odata setat, `poDate.listaid` nu se rescrie din articole). E o decizie de
-proiectare noua, nu o simpla mutare a codului existent (vezi 9.3).
-
-### 4.3 Ce cursor-sursa pe fiecare tip, si ce inseamna "linie" acolo
-
-| Sursa | Cursor(oare) populat(e) la intrarea in `factureaza`/`factureaza2` | Ce e o "linie" pentru dialogul de alegere | `fisier:linie` |
-|---|---|---|---|
-| **comanda** (3, 21, 25, 28, 42, 47) | `crsarticole` <- `pack_facturare.cursor_comanda` | un articol de pe `COMENZI_ELEMENTE`, cu `id_pol` mostenit direct de pe linia comenzii | `ofacturare.prg:292-293` |
-| **contract, `OPT_FACTURARE=3`** (2,6,26,52) | `crsarticole1` <- `pack_facturare.cursor_contract`, ramura `CTR_ARTICOLE` | un articol al contractului, `id_pol` derivat prin `CTR_ARTICOLE.ID_POL_ART -> CRM_POLITICI_PRET_ART` | `ff_...COMUN_PACK_FACTURARE.sql:2752-2836` |
-| **contract, `OPT_FACTURARE IN (1,2)`** (2,6,26,52) | `crsarticole1` <- acelasi cursor, ramura `CTR_SCADENTAR` (`UNION ALL`) | o **rata** de scadentar (`ID_RATA`, `NR_RATA`, `DATA_RATA`, `DATA_SCADENTA`, `DEN_RATA`); `id_articol` e **NULL**, `cantitate` e mereu 1, `gestionabil=0` | `ff_...COMUN_PACK_FACTURARE.sql:2836-2924` |
-| **contract, oricare din cele doua** — cautare libera | `crsarticole` <- acelasi apel, dar cu `pack_facturare.cursor_preturi` legat in interior | lista de preturi normala a operatorului (nu e "libera de politica", vezi `idpol_comanda_contract.md` E.3) | `ff_...COMUN_PACK_FACTURARE.sql:2940-2948` |
-| **avize** (4) | `crsarticole` <- `pack_facturare.cursor_avize` | un rand de pe avizul sursa | `ofacturare.prg:294-295` |
-| **retur** (8, 9, 24) | `crsarticole` <- `pack_facturare.cursor_retur_document`, filtrat pe `V_LISTAID` (facturile alese la antet, 4.2) | un articol al facturii/facturilor deja alese; **nicio coloana `id_vanzare`/`id_vanzare_det` in cursor** — legatura cu factura sursa se pierde inainte sa ajunga in VFP (`docs\cercetare\legatura_linie_retur.md:8-20`) | `ff_...COMUN_PACK_FACTURARE.sql:3949-4062` |
-
-**Pe contract, `crsarticole1` e populat printr-un singur `UNION ALL`, dar cele doua ramuri sunt
-disjuncte pe `OPT_FACTURARE`**: pentru un contract cu `OPT_FACTURARE=3`, `WHERE A.OPT_FACTURARE = 3`
-elimina ramura de rate; pentru `OPT_FACTURARE IN (1,2)`, `WHERE ... IN (1,2)` elimina ramura de
-articole. **Un contract nu produce niciodata ambele tipuri de rand in acelasi `crsarticole1`.** Deci
-eticheta din meniu ("Adauga tot din contract" vs. "Adauga toate ratele") **trebuie sa depinda de
-`crsarticole1.opt_facturare`** (coloana exista in cursor, `:2751,2893` — poate fi citita din primul
-rand dupa incarcare), nu poate fi un text static ca in tabelul din plan.
-
-**Daca `crsarticole1` iese gol** (contract fara articole/rate configurate), formularul de azi
-**elimina complet** `grd_contracte`/`But_urmator2` si redistribuie inaltimea catre `grd_articole`
-(`ofacturare.vc2:15294-15324`, `If !Used('crsarticole1') ... Thisform.RemoveObject('grd_contracte')`)
-— documentul se comporta ca o factura "libera" din lista de preturi. Meniul S4b trebuie sa verifice
-aceeasi conditie inainte sa ofere "Adauga tot din contract"/"Alege ratele…": daca cursorul nu exista
-sau e gol, optiunea nu apare deloc (nu apare goala).
-
-### 4.4 Populare aditiva si "nicio scriere pana la salvare"
-
-Deja adevarat prin constructie, pentru toata familia `do_adauga_articol`: fiecare rand ales (fie prin
-`do_adauga_tot`, fie prin rezultatul unui `cauta_alfa`) trece prin **`Thisform.do_adauga_articol(...)`**,
-care termina cu `Insert Into crsfactura(...)` (cursor local, `.T. Buffering`) — niciun apel Oracle in
-acest pas (Oracle e atins abia la salvarea documentului, `finalizeaza_factura`/`scrie_factura2`, in
-afara acestei povesti). Un dialog nou de alegere trebuie doar sa **produca lista de randuri bifate**
-(cursor XML din `cauta_alfa`) si sa **cheme aceeasi rutina** rand cu rand — vezi sectiunea 5, e
-punctul care garanteaza si echivalenta cu "tot".
-
-### 4.5 Zero rezultate — mesaj, nu tacere
-
-RORIS nu spune nimic la zero rezultate (`import_roris_roaacnpro.md`, punctul 5: butonul "pare ca nu
-face nimic"). `cauta_alfa` insasi nu are un mesaj dedicat de "zero rezultate" (e un browse generic —
-daca cursorul de rezultate e gol, grila apare goala, fara alt semnal, cf. structurii ei standard).
-**Reteta pentru S4b**: verificarea "zero rezultate" se face **inainte** de a deschide `cauta_alfa`
-(similar cu `do_cauta_facturi`, care verifica intai `Empty(poDate.id_client)` inainte de a cauta),
-printr-un `SELECT COUNT(*)` (sau verificare pe cursorul deja incarcat, `Reccount(...)=0`) urmat de
-`AMESSAGEBOX` care spune **de ce**: "Contractul nu are rate de facturat neincasate" / "Comanda nu are
-articole ramase de facturat" / etc., in loc sa lase dialogul sa se deschida gol. Exact tiparul deja
-folosit de `do_adauga_tot` insusi pe ramura fara date (`:13195-13197`,
-`"Nu exista articole de adaugat!"`) — se extinde acelasi obicei la dialogul de alegere.
-
----
-
-## 5. Echivalenta „tot" vs. „alege"
-
-**Garantia structurala exista, dar e incompleta azi.** Toate cele trei cai de populare a
-`crsfactura` — `do_adauga_tot` (SCAN + apel), un viitor dialog de alegere (bifare + apel pe fiecare
-rand bifat), si adaugarea manuala rand cu rand — converg spre **aceeasi rutina**,
-`Thisform.do_adauga_articol(tlImplicit, tlContract, tlRetur)` (`ofacturare.vc2:12813-...`). Cata vreme
-toate trei cheama exact aceasta rutina, cu acelasi cursor sursa pozitionat pe randul corect, rezultatul
-per linie in `crsfactura` e identic prin constructie — nu exista o a doua cale de `INSERT` in
-`crsfactura` in afara acestei rutine (confirmat prin cautarea `Insert Into crsfactura` — singurul alt
-loc e ramura specifica `tip=30`/aviz din NIR, `ofacturare.prg:357-376`, care nu intra in perimetrul
-S4b).
-
-**Ce lipseste, concret, ca sa fie adevarat si pe contract**: `do_adauga_tot` (`:13169-13198`) parcurge
-**doar `crsarticole`**. Pentru ca "Adauga tot din contract" / "Adauga toate ratele" sa functioneze,
-`do_adauga_tot` are nevoie de o ramura noua (sau un al doilea parametru `tlContract`, simetric cu
-`do_adauga_articol`) care sa faca `SCAN` peste `crsarticole1` si sa cheme
-`Thisform.do_adauga_articol(.T., .T.)`. Fara aceasta completare, "tot" pe contract fie nu exista, fie
-(daca cineva ar face butonul vizibil fara sa atinga metoda) ar aduce tacut liniile gresite din
-`crsarticole` (lista de preturi) in loc de `crsarticole1` (articolele/ratele contractului) — o eroare
-mai grava decat lipsa vizibilitatii, pentru ca n-ar da nicio eroare, doar rezultat gresit.
-
-**Alegerea selectiva** trebuie sa respecte aceeasi regula: dupa ce `cauta_alfa` intoarce XML-ul cu
-randurile bifate, bucla care le proceseaza trebuie sa pozitioneze cursorul sursa (`crsarticole` sau
-`crsarticole1`, dupa caz) pe `id_c`-ul corespunzator inainte de fiecare apel `do_adauga_articol`, **nu**
-sa reconstruiasca linia din campurile XML direct — altfel cele doua cai ("tot" vs. "alege") ar avea
-doua implementari diferite ale "ce inseamna sa adaug randul X", exact riscul pe care criteriul de gata
-din plan il exclude explicit ("rezultatul in `crsfactura` e identic pe cele doua cai cand selectia e
-totala").
-
-**Pe comanda/avize/retur, criteriul e deja adevarat prin constructie** — `do_adauga_tot` foloseste azi
-`crsarticole`, care e cursorul lor unic; singurul de completat e contractul (cele doua cazuri de mai
-sus).
-
----
-
-## 6. Interactiunea cu S4 (cautarea articolelor pe server)
-
-Decizia din S4 (`plan_13...md:1879-1888`) e explicita: `crsarticole` **nu se mai incarca in masa**
-pentru facturarea libera (lista de preturi/nomenclator), inlocuita cu `combosql` pe cod/denumire care
-completeaza randul pe loc — **dar** "se pastreaza adauga tot pentru tipurile care au document sursa
-(comanda, aviz, contract) — acolo setul e marginit si incarcarea lui e legitima". Consecinta directa
-pentru meniul S4b:
-
-- **Optiunile "Cauta in lista de preturi…" si "Alege din nomenclator…"** (constante peste tot, cf.
- deciziilor 16/18/20) **nu deschid un dialog de tip `cauta_alfa`** — ele sunt fatada meniului pentru
- mecanismul S4: `combosql` pe o singura linie, populata pe loc, fara incarcare in masa. In termeni de
- UI, alegerea uneia din aceste doua optiuni echivaleaza cu ce face azi `But_nou1.do_adauga` din
- prototip (`APPEND BLANK` + focus pe celula de cod/denumire) — deci **"linie noua" (sectiunea 1) si
- aceste doua optiuni de meniu ajung la acelasi gest UI**, doar ca "linie noua" il porneste direct
- (fara meniu), iar cele doua optiuni de meniu il pornesc din context (dupa ce operatorul a vazut si
- restul optiunilor sursei). Nu sunt cai de cod diferite — sunt doua puncte de intrare in acelasi
- `APPEND BLANK` + editare inline.
-- **Toate optiunile "Adauga tot din X…" / "Alege X…"** (comanda, contract, avize, retur) opereaza pe
- cursoarele bounded (`crsarticole`/`crsarticole1`) pe care **S4 le pastreaza neschimbate** — pentru
- aceste tipuri, nimic din mecanismul de cautare pe server nu se aplica; secțiunile 3-5 de mai sus
- raman valabile ca atare.
-- **Punct de atingere real intre cele doua povesti**: campul `id_pol` pe randul adaugat prin
- `combosql` (S4, cautare din nomenclator liber) — subiectul blocajului `FACT-024` documentat pe larg
- in plan (J-ter/J-quater) si in `idpol_comanda_contract.md`. S4b **nu rezolva** acest blocaj (e
- decizia de produs deschisa la J-quater, intre reteta in 4 pasi / nota pe antet / nota pe antet ca
- fallback) — doar il mosteneste: optiunea "Alege din nomenclator…" din meniul S4b va ajunge la aceeasi
- eroare `FACT-024` la salvare, indiferent de cum arata butonul, pana cand acea decizie separata se ia.
- De mentionat explicit in criteriul de gata al S4b, ca sa nu se creada ca butonul rezolva problema.
-
----
-
-## 7. Ordinea de executie in pasi
-
-1. **Bara de linie (`but_nou`, `but_sterge`, "detalii linie")**, mutata deasupra gridului, cu
- `Caption` explicit pe fiecare instanta (clasele `but_nou`/`but_sterge` au deja `ToolTipText`, nu au
- niciodata `Caption` — de setat pe instanta, nu de asteptat de la clasa).
- *Verificabil*: cele trei butoane sunt vizibile deasupra gridului de linii, fiecare cu text vizibil
- (nu doar iconita), pe orice tip de document deschis.
-2. **Corectarea `Do Case` din `Init`** (`ofacturare.vc2:15109-15248`): adauga `52` la ramura
- `Inlist(poDate.tip, 2, 6)` (linia 15129) astfel incat sa primeasca titlu, eliminare `cSerie`, si sa
- fie tratat identic cu 2/6 in tot restul metodei — corecteaza golul mai mare decat cel semnalat in
- plan (sectiunea 3 de mai sus). Adauga `26` la lista tipurilor care primesc `but_urmator_tot1.Visible
- = .T.` candva in pasul 3, nu aici (26 ramane azi cu titlu corect, doar fara butonul "tot").
- *Verificabil*: un document nou de tip 52 arata acelasi titlu si acelasi grid (fara `cSerie`) ca un
- document de tip 2/6.
-3. **Extinderea `do_adauga_tot`** cu ramura pe `crsarticole1` (parametru sau ramura separata dupa
- `poDate.tip`/`crsarticole1.opt_facturare`), plus vizibilitatea butonului/optiunii pe 2/6/26/52 —
- **cei doi pasi impreuna**, nu separat (vizibilitate fara continut ar aduce un buton mut; continut
- fara vizibilitate nu s-ar vedea niciodata).
- *Verificabil*: pe un contract cu `OPT_FACTURARE=3` si articole configurate, "adauga tot" produce in
- `crsfactura` exact liniile din `crsarticole1`; pe un contract cu `OPT_FACTURARE IN (1,2)`, produce
- cate o linie per rata neincasata.
-4. **Butonul unic "Adauga articole" cu `xmenu()`**, inlocuind `But_urmator_tot1` (fara caption) si
- orice buton separat de alegere — construit dinamic dupa tabelul din sectiunea 3, cu eticheta pe
- ramura de contract aleasa in functie de `crsarticole1.opt_facturare` (sectiunea 4.3).
- *Verificabil*: pe fiecare sursa, meniul deschis contine exact optiunile din tabelul sectiunii 3, in
- ordinea specificata, iar alegerea `ESC` (`xmenu()` intoarce 0) nu declanseaza nimic.
-5. **Dialogul de alegere selectiva**, pe reteta `cauta_alfa(..., tnTipReturn=1)` (sectiunea 4),
- cu mesaj explicit la zero rezultate (4.5) si populare prin `do_adauga_articol` rand cu rand (5) —
- cate o instantiere per sursa (comanda/contract-articole/contract-rate/avize/retur-linii), cu
- `tcselect`/`tcfiltru` proprii.
- *Verificabil*: pe fiecare sursa, bifarea a N randuri din M disponibile adauga exact acele N randuri
- in `crsfactura`, cu aceleasi valori ca daca ar fi fost adaugate individual; bifarea tuturor produce
- acelasi rezultat ca "adauga tot" (criteriul de gata al plan-ului, rescris verificabil).
- *Depinde de*: pasul 3 (aceeasi rutina `do_adauga_articol` trebuie sa functioneze deja pe
- `crsarticole1` inainte ca dialogul de alegere sa se poata baza pe ea).
-6. **Reconcilierea cu selectia de facturi la antet** (sectiunea 4.2, 9.3) — decizie separata,
- nu blocanta pentru pasii 1-5: daca "Alege facturile de returnat…" ramane doar la antet (cum e azi)
- sau devine posibila si din bara de butoane.
-
-*Gata cand (rescris)*: pe fiecare din cele sase surse (lista de preturi, contract-articole,
-contract-rate, comanda, avize, retur), meniul "Adauga articole" ofera exact optiunile tabelate in
-sectiunea 3; pentru fiecare sursa cu "tot"/"alege" ambele prezente, o selectie totala prin dialogul de
-alegere produce in `crsfactura` acelasi set de randuri (aceleasi valori, nu doar acelasi numar) ca
-"adauga tot"; zero rezultate in orice dialog de alegere produce un mesaj care spune sursa si motivul,
-nu un dialog gol; tip 52 se comporta identic cu tip 2/6 in titlu si structura de grid.
-
----
-
-## 8. Ce NU se poate testa headless
-
-- **Continutul si comportamentul meniului `xmenu()`** — `Activate Screen` + `Define Popup ... Bar` e
- UI nativa Windows/VFP (shortcut popup la pozitia mouse-ului); nu exista API de citire a itemilor unui
- popup activ prin automatizare headless. Verificarea "meniul contine optiunile N" se poate face doar
- **indirect**, citind stringul `lcMeniu` construit inainte de apelul `xmenu()` (verificabil headless,
- ca text), nu popup-ul afisat efectiv.
-- **Coloanele griduri (`grd_articole`, `grd_contracte`, `grd_factura`, si viitorul grid al dialogului
- de alegere)** — capcana deja cunoscuta si confirmata pe acest proiect: sub `-A -T`
- (rulare headless) `ColumnCount=0` si `RecordSource` raman artefacte, coloanele nu se materializeaza.
- Exista un harness UI **vizibil** (nu headless) care le citeste corect — orice verificare vizuala a
- meniului/dialogului de alegere trebuie sa treaca prin acel harness, nu prin rulare `-A -T`.
-- **`cauta_alfa`/`cauta_alfa_form_plus`** — dialog modal cu `.Show(1)`, blocheaza thread-ul UI pana la
- interactiune; testarea automata ar necesita fie injectare de input (interzisa pe aceasta masina,
- partajata cu Marius — vezi memoria `masina-partajata-fara-input-real`), fie apelarea directa a
- functiilor Oracle/cursor din spatele dialogului, ocolind UI-ul (verifica *datele*, nu *dialogul*).
-- **`AMESSAGEBOX` la zero rezultate** — verificabil ca text al mesajului in cod (string literal), nu ca
- aparitie reala pe ecran, din acelasi motiv.
-- **Pozitionarea vizuala "deasupra gridului"** (`Top`/`Height` relative) — se poate verifica numeric
- (comparand `Top`-ul butoanelor cu `Top`-ul gridului in `.vc2`), dar nu si "arata bine"/aliniere
- vizuala — necesita captura de ecran prin harness-ul UI vizibil.
-
-Ce **se poate** verifica headless, direct: continutul cursoarelor (`crsarticole`, `crsarticole1`,
-`crsfactura`) dupa apelul rutinelor de adaugare, apelate direct (nu prin click) cu parametri de test;
-stringul `lcMeniu` construit inainte de `xmenu()`; valorile `Visible`/`Caption`/`ToolTipText` setate pe
-obiectele din `.vc2` (proprietati statice, nu comportament de runtime).
-
----
-
-## 9. Riscuri, capcane de UX, si ce ramane de decis de Marius
-
-### 9.1 Regulile de formulare/griduri (`COMUN\docs\reguli_lucru.md`, punctul 7)
-
-Aplicabile direct aici (citite, respectate in proiectarea de mai sus):
-- **`GO` pe `Recno()`** — orice bucla de tip `do_adauga_tot`/dialog de alegere care itereaza cursorul
- sursa (`crsarticole`/`crsarticole1`) trebuie sa retina si sa refaca pozitia (`Recno()`) dupa fiecare
- apel `do_adauga_articol`, exact cum face deja `do_adauga_tot` azi (`lnNrInregistrare = Recno()` ...
- `Go lnNrInregistrare`, `:13175,13185,13193`) — pastrat si in ramura noua pe `crsarticole1`.
-- **UX formulare/griduri** — butoanele fara `Caption` sunt azi conforme cu restul suitei (toate
- butoanele suita sunt icon-only); a le adauga `Caption` e o schimbare vizibila la nivelul intregii
- bare, nu doar a celor trei butoane noi — de discutat daca `But_renunt1`/`But_reset1` raman mute langa
- butoane cu text (inconsistenta vizuala posibila, nu doar tehnica).
-
-### 9.2 Contractul are doua meniuri, nu unul (sectiunea 4.3)
-
-Tabelul din plan (J) trateaza "contract" ca o singura sursa cu un singur set de optiuni. Pe cod, un
-contract e **fie** OPT_FACTURARE=3 (articole), **fie** 1/2 (rate) — niciodata ambele. Eticheta
-"Alege ratele de facturat…" din decizia explicita a lui Marius e corecta doar pe ramura a doua; pe
-prima, echivalentul e "Alege articolele din contract…". **De decis**: se pastreaza o singura eticheta
-generica ("Alege din contract…") care acopera ambele cazuri fara sa distinga in text, sau se
-diferentiaza explicit (mai clar pentru operator, dar mai mult cod de verificare a lui
-`crsarticole1.opt_facturare` inainte de a construi meniul)?
-
-### 9.3 "Alege facturile de returnat…" — la antet sau la bara de butoane?
-
-Azi (sectiunea 4.2), selectia facturilor sursa pentru retur se face **o singura data**, la deschiderea
-formularului de antet (`frm_date_factura.do_cauta_facturi`), inainte ca formularul de articole sa
-existe. Meniul S4b, asa cum e cerut de decizia 13, ar pune "Alege facturile de returnat…" **in bara de
-butoane a formularului de articole** — adica dupa ce `poDate.listaid` a fost deja fixat. Doua optiuni,
-de decis de Marius:
-1. Optiunea din meniul S4b **nu schimba** setul de facturi sursa — e doar un rascolitor spre inapoi,
- catre acelasi dialog de la antet, dar utilizatorul trebuie sa iasa din pasul de articole ca sa-l
- foloseasca (comportament posibil confuz: optiunea apare in meniul de articole, dar actioneaza pe alt
- ecran).
-2. Se adauga un mecanism nou: alegerea de facturi suplimentare **din formularul de articole**, care
- extinde `poDate.listaid` si reincarca aditiv `crsarticole` (`cursor_retur_document` apelat a doua
- oara, cu filtru pe facturile noi, `INSERT INTO crsarticole` in loc de `SELECT INTO`) — cere cod nou
- in VFP, dar nu in `pack_facturare` (procedura Oracle ramane aceeasi, doar apelata de mai multe ori).
-
-"Alege liniile de returnat…" (per articol, din facturile deja alese) e diferita si **nu are conflict**
-cu fluxul de azi — e un dialog de alegere clasic peste `crsarticole`, ca pe comanda/avize.
-
-### 9.4 `id_pol` pe rata de contract — `NULL` prin constructie, dar validat corect
-
-Rata de scadentar (`crsarticole1`, ramura `OPT_FACTURARE IN (1,2)`) are **`id_pol` NULL** prin
-constructia SQL insasi (`NULL AS ID_POL`, `:2840`) — dar asta nu ajunge niciodata la `FACT-024`,
-pentru ca ratele nu trec prin `contabilizeaza_articol`, ci prin `contabilizeaza_rata` (functie separata
-in `pack_facturare`, `idpol_comanda_contract.md` §0c), care citeste nota din `CONTRACTE.ID_NOTA`. **De
-verificat inainte de implementare**: `do_adauga_articol`/`do_scrie_articole` scriu randul de rata in
-`crsfactura` cu ce anume in coloana `id_pol` (probabil `NULL`, mostenit din `poArticol`) — daca
-salvarea foloseste ramura corecta (`contabilizeaza_rata`, nu `contabilizeaza_articol`) pe baza altui
-semnal decat `id_pol` (probabil `id_ctr`/`opt_facturare` pe linie), nu pe baza lui `id_pol` fiind gol.
-Nu s-a verificat cine alege intre cele doua functii la salvare — e in afara perimetrului S4b (tine de
-scriere, nu de bara de butoane), dar merita un pointer explicit ca sa nu se presupuna gresit ca "rata
-fara `id_pol`" e acelasi caz cu "articol din nomenclator fara `id_pol`" (J-quater) — sunt cai de cod
-diferite, cu tratament diferit.
-
-### 9.5 Ce ramane strict de decis de Marius
-
-1. Eticheta pe contract (9.2) — generica sau diferentiata pe `OPT_FACTURARE`.
-2. Fluxul "Alege facturile de returnat…" (9.3) — raman la antet sau se adauga incarcare aditiva.
-3. Daca `But_renunt1`/`But_reset1` primesc si ele `Caption`, pentru consistenta vizuala cu bara nou-
- etichetata, sau raman icon-only (9.1).
-4. Ordinea si formularea exacta a optiunilor in `xmenu()` per sursa (tabelul din sectiunea 3 e o
- propunere, nu o decizie finala de text).
-
----
-
-## Handoff
-
-Cercetare incheiata, fara nicio problema de context intalnita in aceasta runda — nu a fost necesara
-predarea. Toate cele noua sectiuni cerute de brief sunt completate mai sus, cu `fisier:linie` verificat
-direct pe fisierele text reale (nu `.bak`), plus SQL-ul din `PACK_FACTURARE` exportat curent
-(`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`). Nicio editare de
-cod, niciun `git_sync.ps1`/`txt2vcx.ps1`, niciun commit.
diff --git a/docs/cercetare/s4c_discount_in_grid.md b/docs/cercetare/s4c_discount_in_grid.md
deleted file mode 100644
index 522dd36..0000000
--- a/docs/cercetare/s4c_discount_in_grid.md
+++ /dev/null
@@ -1,489 +0,0 @@
-# S4c — Discountul pe linie, mutat din dialog in grid — proiectare implementabila
-
-Cercetare + proiectare READ-ONLY pentru `docs\plan_13_unificare_formular_facturare.md`, `#### S4c`
-(`:2156-2190`). Nu s-a modificat niciun fisier, nu s-a rulat `git_sync.ps1`/`txt2vcx.ps1`, nu s-a dat
-commit, nu s-a scris nimic pe Oracle (numai `SELECT`, niciunul rulat de fapt — toata cercetarea a
-fost pe cod VFP). Nu s-a atins `COMUN\clase\ofacturare_comun.vc2` si `COMUN\programe\ofacturare_editare.prg`.
-
-**Surse de adevar deja stabilite, citate ca atare** (nu se re-verifica aici):
-`docs\cercetare\discount_in_rapoarte_si_efactura.md` (verdictul principal — niciun raport/eFactura nu
-tipareste discountul, dar amandoua citesc `valdiminuatftva`/`discountftva` din cursorul de tiparire),
-`docs\cercetare\discount_verificare2.md` (structura reala a coloanelor din `grd_factura` si a
-`VANZARI_DETALII`). **`docs\cercetare\discount_pe_articol.md` NU e citat ca sursa** — task-ul mi-a
-semnalat ca are doua afirmatii gresite, corectate deja in `discount_verificare2.md` sectiunea finala
-("Ce era gresit in afirmatiile de mai sus").
-
-## Verdict (10 randuri)
-
-S4c e implementabila cu cod nou moderat, nu cu redesign. Contractul de calcul exista deja, complet si
-reciproc, in `frm_articol_factura.do_calculeaza_discount` (`ofacturare.vc2:1874-1976`) si
-`frm_articol_factura.do_calculeaza_totaluri` (`:2068-2179`, delegand la functia partajata
-`calculeaza_totaluri()` din `oproceduri_facturare.prg:2258-2381`) — aceasta din urma **e deja scrisa
-generic, pe orice obiect cu proprietatile potrivite**, deci se poate rula direct pe un rand din
-`crsfactura` (via `Scatter`/`Gather Name`), fara sa mai treaca prin dialog. Tiparul de eveniment
-pentru coloane editabile de grid **exista deja in acelasi fisier**, pe alt formular din aceeasi
-familie de clase (`frm_avizare_lucrare.grd_articole.cCantitate/cPret.Text1.LostFocus`,
-`:6549-6562`) — `LostFocus` care cheama `Thisform.do_calculeaza_totaluri()`, nu `InteractiveChange`.
-**Capcana reala e alta decat pare din titlul poveste**: exista **doua cai de scriere independente**
-catre destinatii diferite, si doar una e azi corect legata. `do_scrie_articole` trimite spre Oracle
-(`pack_facturare.adauga_articol_factura`, `ofacturare.vc2:14081-14083`) discountul citit **direct
-din `discountftva`/`discountctva`/`vdiscountftva`/`vdiscountctva`** — deci `VANZARI_DETALII.DISCOUNT_UNITAR`
-**e mereu corect**, indiferent de bug, pentru ca aceste campuri sunt chiar campurile editate in grid.
-Riscul e strict local, in sesiunea VFP curenta: `prelucreaza_factura` (apelata pentru tiparire/eFactura,
-`ofacturare.prg:1887`) construieste cursorul de tiparire **din acelasi `crsfactura` deja in memorie**,
-citind `valdiminuatftva`/`valdiminuatctva`/`vvaldiminuatftva`/`vvaldiminuatctva` — campuri **agregate**
-(pret-discount)*cantitate, care **nu se recalculeaza singure** cand se editeaza discountul brut. Deci
-Oracle poate avea `DISCOUNT_UNITAR` corect si totusi factura tiparita/eFactura sa arate valoarea veche,
-in aceeasi sesiune, pana la reincarcare. Solutia: coloanele noi de discount trebuie sa scrie, pe
-`LostFocus`, atat campurile brute cat si campurile agregate — vezi sectiunea 4.
-
----
-
-## 1. Lantul complet al campurilor de discount, cu `fisier:linie`
-
-### 1.1 Structura cursorului local `crsfactura`
-
-Definit in `creeaza_facturacrs` (`COMUN\programe\ofacturare_comun.prg:1779-1782`):
-```
-1779 valdiscountctva N(20,max(gnPc,4)),valdiminuatftva N(20,max(gnPc,4)),valdiminuattva N(20,max(gnPc,4)),valdiminuatctva N(20,max(gnPc,4)),proc_Tvav N(20,4),cu_tva N(1), lot C(20) null, serie c(100) Null,;
-1782 vvaldiscountctva N(20,max(gnPVal,4)),vvaldiminuatftva N(20,max(gnPVal,4)),vvaldiminuattva N(20,max(gnPVal,4)),vvaldiminuatctva N(20,max(gnPVal,4)),id_set_fact N(20) Null,explicatie M Null,;
-```
-(`discountftva`, `discountctva`, `vdiscountftva`, `vdiscountctva`, `valdiscountftva`, `valdiscountctva`,
-`vvaldiscountftva`, `vvaldiscountctva` sunt definite pe liniile adiacente, aceeasi procedura —
-nu recitate individual, tiparul `N(20,...)` e identic).
-
-**Nomenclatura confirmata pe cod** (nu doar dedusa din nume) — opt campuri distincte, trei niveluri:
-| Camp | Nivel | Moneda | Cu/fara TVA | Sens |
-|---|---|---|---|---|
-| `discountftva` | pe unitate | lei | fara TVA | discount unitar, sursa in lei |
-| `discountctva` | pe unitate | lei | cu TVA | discount unitar, derivat |
-| `vdiscountftva` | pe unitate | valuta | fara TVA | discount unitar, sursa in valuta |
-| `vdiscountctva` | pe unitate | valuta | cu TVA | discount unitar, derivat |
-| `valdiscountftva`/`valdiscountctva` | pe linie (x cantitate) | lei | ambele | discount agregat lei |
-| `vvaldiscountftva`/`vvaldiscountctva` | pe linie (x cantitate) | valuta | ambele | discount agregat valuta |
-| `valdiminuatftva`/`valdiminuatctva` | pe linie (x cantitate) | lei | ambele | **valoare neta** (pret-discount)*cant — cea tiparita/eFactura |
-| `vvaldiminuatftva`/`vvaldiminuatctva` | pe linie (x cantitate) | valuta | ambele | valoare neta in valuta |
-
-### 1.2 De la tastare la `crsfactura` — calea de azi (prin dialog)
-
-1. Operator tasteaza in dialogul `frm_articol_factura` (`ofacturare.vc2:1108-2659`), pe unul din 3
- perechi de campuri: `Clb_procent_discount.Text_simplu1` (`InteractiveChange`, `:2646`),
- `Clb_discount_unitar.tx_suma_nat`/`tx_suma_val` (`Valid`, `:2614/:2620`),
- `Clb_discountctva.tx_suma_nat`/`tx_suma_val` (`Valid`, `:2602/:2608`).
-2. Toate cheama `Thisform.do_calculeaza_discount(valoare, tip)` — **`frm_articol_factura`**
- (`:1874-1976`, contract detaliat in sectiunea 2) — scrie in `poArticol`:
- `discount_unitar`, `discount_unitar_val`, `discount_unitar_ctva`, `discount_unitar_ctva_val`.
-3. `do_calculeaza_discount` cheama la final `Thisform.do_calculeaza_totaluri()` (`:1974`,
- `frm_articol_factura`, `:2068-2179`) care delega la **`calculeaza_totaluri(poArticol)`**
- (`oproceduri_facturare.prg:2258-2381`, functie globala) — aceasta scrie in `poArticol`:
- `valdiminuatftva`, `valdiminuattva`, `valdiminuatctva`, `vvaldiminuatftva`, `vvaldiminuattva`,
- `vvaldiminuatctva`, plus `valdiscountftva/ctva`, `vvaldiscountftva/ctva`, `valftva/ctva/tva` etc.
-4. La inchiderea dialogului, `do_adauga_articol` (`ofacturare.vc2:12813-13167`) scrie **tot obiectul
- deja calculat** in `crsfactura`, in doua pasi:
- - `Gather Name poArticol Fields Like ... valdiminuatftva, valdiminuattva, valdiminuatctva,
- vvaldiminuatftva, vvaldiminuattva, vvaldiminuatctva ...` (`:12945-12950`) — campurile agregate,
- **deja calculate de `calculeaza_totaluri`**, nu recalculate aici.
- - `Replace ... 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)` (`:12952-12957`) — campurile pe
- unitate, separat, pentru ca nu sunt in lista `Gather` (doar variantele `val*` agregate sunt).
-5. `do_modifica` (`:13746-13914`, editarea unei linii existente) urmeaza acelasi tipar —
- `Gather`/`Replace` cu aceleasi campuri (`:13837-13881`), dupa ce redeschide dialogul pe rand.
-6. **Cale suplimentara, deja existenta, cu bug documentat**: pe factura in valuta, coloana
- `cVdiscountftva` (`ControlSource="vdiscountftva"`, `ofacturare.vc2:12340-12345`) e editabila
- direct in grid, **fara niciun handler** — scrie `vdiscountftva` direct in `crsfactura` prin
- binding-ul standard de grid, dar **nu recalculeaza** `vvaldiminuatftva`/`vvaldiminuatctva`
- (confirmat cautat explicit, `discount_verificare2.md` punctul 3).
-
-### 1.3 De la `crsfactura` la Oracle (`VANZARI_DETALII.DISCOUNT_UNITAR`)
-
-`do_scrie_articole` (`ofacturare.vc2:13916-...`), la finalizarea facturii, trimite spre
-`pack_facturare.adauga_articol_factura` un singur parametru de discount, ales **direct din campurile
-pe unitate** ale randului curent din `crsfactura` (`:14081-14083`):
-```
-14081 IIF(poArt.cu_tva = 0,;
-14082 Iif(poArt.tip_valuta = 0,Alltrim(Str(poArt.discountftva,18,gnPPretV)),Alltrim(Str(poArt.vdiscountftva,18,gnPVal))), ;
-14083 IIF(poArt.tip_valuta = 0,Alltrim(Str(poArt.discountctva,18,gnPPretV)),Alltrim(Str(poArt.vdiscountctva,18,gnPVal))))
-```
-**Nu foloseste `valdiminuatftva`.** Deci Oracle primeste intotdeauna valoarea curenta din
-`discountftva`/`discountctva`/`vdiscountftva`/`vdiscountctva` — cele patru campuri pe care coloanele
-noi de grid le-ar edita direct. `VANZARI_DETALII.DISCOUNT_UNITAR NUMBER(22,6)` e singura coloana
-Oracle de discount (confirmat `discount_verificare2.md` punctul 4) — nu exista coloana de procent pe
-Oracle.
-
-### 1.4 Inapoi, pentru tiparire/eFactura — `crsfacttemp`
-
-`prelucreaza_factura` (`ofacturare_comun.prg:1055-1059`, apelata din `ofacturare.prg:1887`) **NU
-reincarca din Oracle** — primeste ca parametru **acelasi `crsfactura`** deja in memorie (cel scris la
-pasii 1.2/1.3), si construieste cursorul de tiparire prin agregare SQL locala:
-```
-1182 Sum(cantitate) As cantitate,pretftva-discountftva As pretftva,;
-1186 Sum(valdiminuatftva) As valftva,Sum(valdiminuattva) As valtva,;
-```
-(`ofacturare_comun.prg:1182-1186`, cazul comun `discount_evidentiat=0`). eFactura foloseste **acelasi
-cursor de iesire** (`xmlefactura.prg:231`, `LineExtensionAmount = valftva`, `PriceAmount = pretftva`,
-`xmlefactura.prg:935-937`, `:1043-1046`).
-
-**Consecinta directa**: `pretftva-discountftva` de la 1182 citeste `discountftva` (mereu proaspat,
-pentru ca e campul editat direct), dar `Sum(valdiminuatftva)` de la 1186 citeste campul **agregat**,
-care ramane vechi daca nu a fost recalculat explicit dupa editare. Rezultat: **randul tiparit poate
-avea `pretftva` corect (net, recalculat corect din `discountftva`) dar `valftva` (valoarea liniei)
-gresit** — o discrepanta pret x cantitate ≠ valoare, vizibila chiar pe hartie, nu doar o valoare
-veche uniforma. Asta e mai grav decat "arata vechi" — arata **inconsistent**.
-
----
-
-## 2. Contractul `frm_articol_factura.do_calculeaza_discount` (`ofacturare.vc2:1874-1976`)
-
-**Semnatura**: `Lparameters tnValoare, tnTip` — `tnTip`: `1` = s-a modificat procentul, `2` =
-discount in lei (fara TVA daca `preturi_cu_tva=0`, cu TVA altfel), `3` = discount in valuta.
-
-**Ramura principala** — `If poArticol.preturi_cu_tva = 0` (pretul de referinta e fara TVA, cazul
-uzual): sursa de adevar e `discount_unitar`(_val).
-- `tnTip=1` (procent -> valoare): daca `tip_valuta=0`,
- `discount_unitar = Round(pretftva * procent/100, gnPPretV)`, apoi **procentul se re-normalizeaza**
- din valoarea rotunjita (`:1888-1889`) — nu se pastreaza procentul brut tastat, ci cel rezultat din
- rotunjire. Daca `tip_valuta=1`: `discount_unitar_val` se calculeaza intai (`gnPVal`), apoi
- `discount_unitar = Round(discount_unitar_val * Curs / multiplicator, gnPPretV)`.
-- `tnTip=2` (lei -> procent): `discount_unitar = tnValoare` direct, procentul se deriva
- (`Round(discount_unitar/pretftva*100, 2)`).
-- `tnTip=3` (valuta -> procent + lei): `discount_unitar_val = tnValoare`, procentul deriva din
- valuta, apoi `discount_unitar = Round(discount_unitar_val * Curs / multiplicator, gnPPretV)`.
-- **Dupa `Do Case`, neconditionat**: `discount_unitar_ctva = discount_unitar + Round(discount_unitar
- * (proc_tvav-1), gnPPretV)` (`:1913-1914`) — varianta cu TVA e **mereu derivata** din cea fara TVA
- in aceasta ramura, niciodata sursa.
-- Daca `tip_valuta=1`, simetric: `discount_unitar_ctva_val` derivat din `discount_unitar_val`.
-
-**Ramura alternativa** — `Else` (`preturi_cu_tva=1`, pretul de referinta e cu TVA): rolurile se
-inverseaza complet — `discount_unitar_ctva`(_val) e sursa (calculata direct din `tnValoare`/`pretctva`
-in cele 3 cazuri, simetric cu ramura de mai sus), iar `discount_unitar`(_val) **fara TVA** e derivat
-la final (`:1958`, `Round(discount_unitar_ctva / proc_tvav, gnPPretV)`).
-
-**Rotunjiri**: `gnPPretV` pentru valorile unitare in lei, `gnPVal` pentru cele in valuta, `2` fix
-pentru procent — niciodata `gnPc` (precizia de linie/document) in aceasta metoda.
-
-**La final, neconditionat** (`:1972-1974`): `Thisform.clb_tva_discount.Refresh()`,
-`Thisform.clb_pret_diminuat.Refresh()`, **`Thisform.do_calculeaza_totaluri()`** — deci orice apel
-recalculeaza si campurile agregate de linie, nu doar cele pe unitate.
-
-**In valuta, ce ramane needitat de aceasta metoda**: campurile agregate (`valdiminuatftva` etc.) NU
-sunt scrise aici — `do_calculeaza_totaluri` (sectiunea urmatoare) le calculeaza separat din
-`discount_unitar`/`cantitate`.
-
----
-
-## 3. Starea de azi in grid — tabel
-
-| Coloana | `ControlSource` | Formular | `ReadOnly` | Editabil azi | Recalculeaza la editare |
-|---|---|---|---|---|---|
-| `Column5`/`cDiscountCTva` | `discountctva` | `frm_facturare_articole` (productie), `:12311-12317` | `.T.` explicit | Nu | — |
-| `Column9`/`cVdiscountftva` | `vdiscountftva` | `frm_facturare_articole`, `:12340-12345` | nesetat (implicit `.F.`) | **Da, pe factura in valuta** | **Nu** — niciun `Valid`/`LostFocus`/`InteractiveChange` propriu, cautat explicit in `10968-15739` |
-| `Column5`/`cDiscountCTva` | `discountctva` | `frm_facturare_articole2` (prototip, neinstantiat in productie) | `.F.` explicit, `:16657` | Da (prototip) | Nesigur — prototip, nu s-a cautat handler dedicat |
-| `Column9`/`cVdiscountftva` | `vdiscountftva` | `frm_facturare_articole2` | `.F.` explicit, `:16688` | Da (prototip) | idem |
-| `Column14`/`procdisc` | `procdisc` | `frm_facturare_articole2` numai, `:16721` | nesetat | scaffold, fara scriere | **Nu are corespondent Oracle, nu are `Gather`/`Replace` nicaieri in fisier** (`discount_verificare2.md` sectiunea 5) |
-
-**Excludere pe valuta** (`ofacturare.vc2:15269-15278`, in `frm_facturare_articole.Init`): cand
-`poDate.in_valuta = 0` se elimina `cVpretFtva`, `cVdiscountftva`, `cVvaldiminuatftva`; cand
-`in_valuta <> 0` se elimina `cPretFtva`, `cDiscountctva` (si simetricele lor). Deci azi, pe orice
-factura, **doar una din cele doua coloane de discount e vizibila** — cea in lei, needitabila, sau cea
-in valuta, editabila-dar-fara-recalcul. Nu exista azi nicio coloana de **procent** de discount in
-`grd_factura` in productie (doar `discountctva`/`vdiscountftva`, valori, nu procent) — pentru procent,
-azi operatorul trebuie sa deschida dialogul.
-
----
-
-## 4. Proiectarea
-
-### 4.1 Ce coloane se adauga/deschid
-
-Nu se sterge nimic din `crsfactura` (modelul de date ramane neschimbat, conform cerintei). Se
-lucreaza cu campurile deja existente:
-
-- **Coloana procent discount** (noua in grid, in ambele monede) — `ControlSource` pe un camp
- calculat, nu direct pe un camp Oracle (nu exista coloana Oracle de procent) — vezi 4.4 pentru
- optiunea recomandata.
-- **`cDiscountCTva`** (`discountctva`, lei): `Column5.ReadOnly` trece din `.T.` in `.F.` — devine
- editabila, simetric cu ce azi doar prototipul `frm_facturare_articole2` face.
-- **`cVdiscountftva`** (`vdiscountftva`, valuta): ramane editabila ca azi, dar castiga handler-ul
- care azi lipseste.
-
-Se pastreaza `RemoveObject` pe valuta (`:15269-15278`) neschimbat — excluderea reciproca deja
-implementeaza cerinta "se pastreaza excluderea pe `in_valuta`".
-
-### 4.2 Pe ce eveniment se cableaza calculul reciproc
-
-**Recomandare: `Text1.LostFocus`, dupa tiparul deja folosit in acest fisier pentru coloane
-editabile de grid** — `frm_avizare_lucrare.grd_articole.cCantitate.Text1.LostFocus` si
-`.cPret.Text1.LostFocus` (`ofacturare.vc2:6549-6562`), ambele in aceeasi clasa de baza de grid
-(`_grdrow`, `_grd_base.vc2:445`) folosita si de `grd_factura`. Motivele, nu teoretice ci din cod:
-- **`InteractiveChange` fireste pe fiecare tasta** — ar recalcula la fiecare caracter tastat intr-un
- numar cu zecimale (comportament vazut la coloana `procent` in dialog, `:2646`, dar acolo controlul
- e un camp simplu de dialog, nu o celula de grid cu re-randare de coloane vecine la fiecare tasta —
- in grid ar fi vizibil costisitor si ar zgaltai focusul).
- `Valid`-urile din dialog (`:2602-2624`) folosesc explicit un guard `<> nSumaNatOld`/`nSumaValOld`
- ca sa nu recalculeze cand valoarea nu s-a schimbat efectiv — semnaleaza ca autorii au evitat
- deliberat recalculul pe fiecare tasta chiar si la `Valid`.
-- **`LostFocus` e tiparul deja validat pentru grid-uri de articole in acest fisier**, pe doua coloane
- numerice diferite (cantitate, pret), amandoua cu acelasi tip de nevoie (schimbarea unei valori
- declanseaza recalculul liniei si al totalului documentului).
-- Grid-ul VFP nu are `Valid` pe coloana insasi in mod uzual folosit aici — handlerele existente sunt
- pe `.Text1.LostFocus`, deci noile handlere trebuie sa fie
- `grd_factura.cDiscountCTva.Text1.LostFocus` si `grd_factura.cVdiscountftva.Text1.LostFocus`
- (plus coloana noua de procent, daca implementata ca `Text1` editabil).
-
-### 4.3 Rutina de recalcul — reutilizare, nu reimplementare
-
-`calculeaza_totaluri()` (`oproceduri_facturare.prg:2258-2381`) **e deja generica**: primeste orice
-obiect (`toArticol`) cu proprietatile `preturi_cu_tva`/`discount_unitar`/`pretftva`/`cantitate`/...
-(le adauga singura, prin `AddProperty`, daca lipsesc — `:2264-2272`, mapand numele de camp
-`crsfactura`-stil, `discountftva`/`vdiscountftva`, pe numele `poArticol`-stil,
-`discount_unitar`/`discount_unitar_val`) si scrie inapoi campurile agregate. **Poate rula direct pe
-un `Scatter Name` al randului curent din `crsfactura`**, fara sa deschida dialogul:
-```
-Select crsfactura
-Scatter Name loArt Memo
-loArt = calculeaza_totaluri(loArt)
-Gather Name loArt Memo
-```
-Aceasta acopera pasul "recalculeaza campurile agregate din discountul unitar deja stabilit"
-(`valdiminuatftva`, `valdiminuatctva`, `vvaldiminuatftva`, `vvaldiminuatctva`,
-`valdiscountftva/ctva`, `vvaldiscountftva/ctva`), **exact campurile care azi raman vechi**
-(sectiunea 1.4).
-
-**Ce `calculeaza_totaluri()` NU face**: conversia reciproca procent<->valoare — aceea e logica din
-`do_calculeaza_discount` (sectiunea 2), care azi scrie in `poArticol` si actualizeaza controale de
-dialog (`Thisform.clb_*.Refresh()`) care nu exista in grid. **Recomandare**: se extrage o functie noua,
-fara referinte la `Thisform.clb_*` (partea de calcul pur, liniile `:1878-1970` minus liniile de
-`Refresh`), reutilizabila atat din dialog (daca dialogul de articol individual mai exista undeva —
-nu la S4c, dialogul dispare) cat si din handler-ul de grid — parametrizata pe rand
-(`toArticol`/`Scatter Name`) in loc de `poArticol` global. Aceasta functie noua intra la fel ca
-`calculeaza_totaluri()`, in `oproceduri_facturare.prg`, ca sa fie apelabila din handler-ul de coloana
-fara sa depinda de `poArticol`-ul dialogului disparut.
-
-### 4.4 Coloana de procent — implementare recomandata
-
-Nu exista coloana Oracle de procent (sectiunea 1.3) si nici coloana persistenta pe `crsfactura`
-pentru asta (spre deosebire de `discountftva` etc, care sunt in `creeaza_facturacrs`). Doua optiuni:
-1. **Adauga camp calculat, needitabil, alaturi de coloana editabila de valoare** — afiseaza procentul
- derivat (`Round(discountftva/pretftva*100,2)`), needitabil direct — evita sa se mai adauge o
- coloana Oracle noua si o cale de editare in plus (mai putin cod nou, mai putina suprafata de bug).
-2. **Adauga coloana editabila de procent, needitabila-pe-model** — ca in `frm_articol_factura`
- (`Clb_procent_discount`), scrie tot in `discountftva`/`discountctva`/`vdiscountftva`/`vdiscountctva`
- prin acelasi calcul reciproc, dar camp de UI, nu de Oracle. Mai aproape de comportamentul de azi
- din dialog (operatorul poate tasta fie procentul, fie valoarea), dar cere si al treilea handler de
- `LostFocus` si inca un camp de lucru in cursorul local (`AddProperty` la `do_initializeaza_articol`,
- dupa tiparul `id_jtva_coloana`/`valdiminuatftva`, `:13666-13681`).
-
-Cerinta din plan ("cele doua campuri de discount ale lui — procent si valoare unitara — devin coloane
-in grid") cere explicit **ambele campuri editabile** — deci optiunea 2 e cea care respecta litera
-cerintei; optiunea 1 e o simplificare de discutat cu Marius (vezi sectiunea 10).
-
-### 4.5 Unde se cheama exact recalculul, pas cu pas (handler propus)
-
-Pentru coloana `cDiscountCTva` (`discountctva`, lei, `tip=2` in nomenclatura `do_calculeaza_discount`):
-```
-PROCEDURE grd_factura.cDiscountCTva.Text1.LostFocus
- Select crsfactura
- Scatter Name loArt Memo
- * recalcul reciproc procent<->valoare, tip=2 -- functia noua din 4.3, nu do_calculeaza_discount
- loArt = recalc_discount_linie(loArt, This.Value, 2) && scrie discountftva/discountctva(_val)
- loArt = calculeaza_totaluri(loArt) && scrie valdiminuat*/vvaldiminuat*
- Gather Name loArt Memo
- Thisform.do_calculeaza_totaluri() && resumeaza totalurile documentului
-ENDPROC
-```
-Simetric pentru `cVdiscountftva` (`tip=3`) si pentru coloana de procent, daca implementata editabil
-(`tip=1`). Guard-ul `<> valoare veche` (ca la `Valid`-urile din dialog, `:2602-2624`) se pastreaza ca
-sa nu se recalculeze la simplu tab-through fara modificare.
-
----
-
-## 5. Interactiunea cu discountul din politica de pret
-
-**Azi**: `do_initializeaza_articol` (`ofacturare.vc2:13618` si urm.) preia
-`toArticol.discount_unitar = Nvl(toArticol.discount_unitar, 0)` (`:13630`) **din `crsarticole`**
-(cursorul de stoc/oferta, populat inainte de deschiderea dialogului — sursa SQL exacta, in afara
-`ofacturare.vc2`, ramasa necercetata si in raportul precedent). Daca politica de pret a populat deja
-un discount, acela apare **preincarcat** in campurile dialogului (`Clb_discount_unitar` etc.),
-operatorul il poate suprascrie tastand — suprascrierea intra prin acelasi `do_calculeaza_discount`
-ca orice alta tastare, fara distinctie intre "valoare din politica" si "valoare tastata manual".
-
-**Dupa S4c**: nu se schimba nimic in mecanismul de preincarcare — `do_adauga_articol` inca scrie
-`discountftva`/`discountctva`/`vdiscountftva`/`vdiscountctva` in `crsfactura` la adaugarea liniei
-(sectiunea 1.2, pasul 4), inainte ca operatorul sa apuce sa editeze coloana de grid. Valoarea din
-politica **ramane vizibila in celula**, exact ca azi in dialog, iar editarea manuala in grid o
-suprascrie la fel — singura diferenta e ca suprascrierea se intampla acum pe `LostFocus` de celula,
-nu pe `Valid` de camp de dialog. **Nu exista azi o distinctie de tip "flag discount din politica vs.
-discount manual"** in `crsfactura` (nu am gasit un camp `discount_din_politica` sau similar) — deci
-S4c nu pierde nicio informatie care exista deja, dar nici nu castiga vreo trasabilitate noua.
-
----
-
-## 6. Refacerea totalurilor documentului
-
-Totalurile documentului (`Thisform.nbazaron`, `ntotalron`, `ndiscron`, variantele `*val`) se
-recalculeaza in `frm_facturare_articole.do_calculeaza_totaluri` (`ofacturare.vc2:13423-13520`) —
-**re-sumeaza direct din `crsfactura`** (si `crsfacturaset` daca exista), citind exact campurile
-agregate din sectiunea 1.1/1.4:
-```
-13456 Select Sum(Nvl(valdiminuatctva,0)) As Total,Sum(Nvl(valdiminuatftva,0)) As Baza,;
-13457 Sum(Nvl(valdiminuattva,0)) As Tva,;
-13458 Sum(Nvl(valdiscountftva,0)) As discount From crsfactura Into Cursor crstotalurifact
-```
-Simetric pentru valuta (`vvaldiminuat*`) mai jos in aceeasi procedura. **Consecinta directa pentru
-proiectare**: daca handler-ul de coloana (sectiunea 4.5) actualizeaza corect `valdiminuatftva`/
-`valdiminuatctva`/`vvaldiminuatftva`/`vvaldiminuatctva`/`valdiscountftva`/`vvaldiscountftva` pe randul
-editat **inainte** de a chema `Thisform.do_calculeaza_totaluri()`, totalurile documentului se refac
-automat, corect, din acelasi mecanism care azi refece totalurile la adaugare/stergere de linie
-(`do_adauga_articol:13160`, `do_sterge:14676`) — **nu trebuie cod nou pentru pasul de resumare**, doar
-apelul, la finalul handler-ului de coloana. `Thisform.do_calculeaza_totaluri` e deja legat prin
-`Bindevent` de `actualizeaza_total_mod` (`:15265`) — orice apel al lui declanseaza si actualizarea de
-ecran a etichetelor de total, fara cablaj suplimentar.
-
----
-
-## 7. Pasi de implementare, ordonati, cu criteriu de "gata"
-
-1. **Extrage functia de calcul reciproc** din `frm_articol_factura.do_calculeaza_discount`
- (`:1874-1976`), fara liniile de `Thisform.clb_*`/`Thisform.nprocent`, ca functie noua in
- `oproceduri_facturare.prg`, parametrizata pe obiect + valoare + tip (semnatura similara cu
- `calculeaza_totaluri(toArticol)`).
- *Gata cand*: pentru fiecare din cele 3 `tnTip` si ambele ramuri `preturi_cu_tva`, functia noua
- produce exact aceleasi `discount_unitar`/`discount_unitar_ctva`/`_val` ca metoda originala, testat
- pe acelasi set de intrari (procent, lei, valuta) — comparatie directa, nu doar citire de cod.
-2. **Deschide `Column5`/`cDiscountCTva` la editare** (`ReadOnly = .F.`,
- `ofacturare.vc2:12311-12317`), pastrand `RemoveObject` pe valuta neschimbat.
- *Gata cand*: pe factura in lei, celula de discount unitar cu TVA e editabila din grid (nu doar
- afisata).
-3. **Adauga handler `Text1.LostFocus` pe `cDiscountCTva` si pe `cVdiscountftva`**, dupa modelul din
- sectiunea 4.5: recalcul reciproc (pasul 1) + `calculeaza_totaluri()` (deja existent,
- `oproceduri_facturare.prg:2258`) + `Gather` + `Thisform.do_calculeaza_totaluri()`.
- *Gata cand*: editarea oricareia din cele doua coloane schimba, in acelasi moment, si
- `discountftva`/`discountctva`/`vdiscountftva`/`vdiscountctva` **si**
- `valdiminuatftva`/`valdiminuatctva`/`vvaldiminuatftva`/`vvaldiminuatctva` pe randul curent,
- verificat prin `Browse`/inspectie cursor, nu doar pe ecran.
-4. **Adauga coloana de procent** (decizie 4.4 de confirmat cu Marius — recomandare: optiunea 2,
- editabila, ca sa respecte litera cerintei din plan), cu acelasi handler, `tip=1`.
- *Gata cand*: tastarea unui procent produce aceeasi valoare de discount ca tastarea valorii
- echivalente, pe ambele monede.
-5. **Verifica totalurile documentului** dupa editare in grid — nu ar trebui sa fie nevoie de cod nou
- (sectiunea 6), doar de apelul din pasul 3.
- *Gata cand*: dupa editarea discountului pe o linie, `Thisform.nbazaron`/`ntotalron` (si variantele
- `val`) se schimba imediat, fara sa fie nevoie de o alta actiune (adaugare/stergere de linie) care
- sa le forteze.
-6. **Verifica scrierea in Oracle** (`do_scrie_articole`, `:14081-14083`) — nu ar trebui sa fie nevoie
- de nicio schimbare, pentru ca citeste deja campurile pe unitate direct (sectiunea 1.3).
- *Gata cand*: `VANZARI_DETALII.DISCOUNT_UNITAR` dupa salvare = valoarea tastata in grid, pe o
- factura testata cu discount editat exclusiv din grid (fara sa fi trecut prin dialog, care oricum
- dispare la unificare).
-7. **Verifica tiparirea si eFactura** — cea mai importanta proba, cea ceruta explicit de plan.
- *Gata cand*: vezi sectiunea 8.
-
----
-
-## 8. Cum se verifica — concret
-
-**Pasii**, pe o factura de test (lei si separat valuta):
-1. Adauga o linie in grid (fara discount).
-2. Editeaza direct in grid coloana de discount (valoare, apoi pe alt rand procent) — verifica pe
- ecran ca celelalte coloane afisate (`cPretFtva`/`cVpretftva`, `cValdiminuatctva`/`cVvaldiminuatftva`
- daca ramase vizibile) se actualizeaza imediat.
-3. **Interogheaza direct cursorul** (nu doar ecranul) — din Command Window/breakpoint, pe randul
- editat: `? discountftva, discountctva, vdiscountftva, vdiscountctva, valdiminuatftva,
- valdiminuatctva, vvaldiminuatftva, vvaldiminuatctva` — toate opt trebuie sa reflecte editarea, nu
- doar cele patru "brute".
-4. **Finalizeaza factura** (`do_scrie_articole`) si interogheaza Oracle (schema `MARIUSM_AUTO`,
- conventia din `COMUN\docs\scripturi-migrare-db.md:36-40`, prin `goExecutor`, doar `SELECT`):
- ```sql
- SELECT discount_unitar FROM vanzari_detalii WHERE id_vanzare = :id_factura AND id_articol = :id_articol;
- ```
- trebuie sa fie egal cu valoarea tastata in grid.
-5. **Retipareste factura** (nu doar priveste pe ecranul de compunere — deschide efectiv raportul,
- `factura.fr2` sau echivalentul in lei/valuta) si verifica pe pagina tiparita ca `pretftva`/`valftva`
- pe linia editata reflecta discountul nou (pretul unitar net si valoarea liniei trebuie sa fie
- consistente intre ele: `valftva = pretftva * cantitate`, altfel exact bug-ul din sectiunea 1.4).
-6. **Genereaza XML-ul de eFactura** pentru aceeasi factura si verifica in fisier
- `cbc:LineExtensionAmount`/`cbc:PriceAmount` pe linia editata — trebuie sa corespunda cu pretul net
- nou, nu cu cel dinaintea editarii.
-7. Repeta 1-6 pe **factura in valuta**, ca sa acoperi ramura `vdiscountftva`/`vvaldiminuatftva`
- (ramura azi cu bug-ul confirmat).
-
----
-
-## 9. Ce nu se poate testa headless
-
-- **Editarea propriu-zisa a celulei de grid** (tastare in `Text1` al unei coloane, tab/enter pentru
- `LostFocus`) — headless-ul VFP (`-A -T`) nu materializeaza interactiunea de tastatura intr-un grid;
- cf. `docs\cercetare\...grid-coloane-nu-se-materializeaza-headless` (memorie de proiect) — coloanele
- de grid sunt artefacte needitabile sub `-A -T`; verificarea reala a comportamentului UI cere
- harness-ul cu UI vizibil sau un test manual asistat.
-- **Tiparirea efectiva a raportului** (`.frx`) — generarea unui PDF/preview real, nu doar constructia
- cursorului `crsfacttemp` in memorie, cere motorul de raportare VFP, care nu ruleaza util headless
- pentru verificare vizuala (se poate verifica campurile cursorului sursa, dar nu pagina tiparita).
-- **Trimiterea efectiva catre ANAF** (SPV) — se poate genera si inspecta XML-ul local, dar validarea
- reala (acceptare/respingere) cere mediul de test ANAF, in afara acestei sarcini.
-- **Comportamentul focus/tab-order al noilor coloane** in grid (ordinea de tab intre celule, daca
- `LostFocus` se declanseaza corect la navigare cu tastatura vs. mouse) — cere sesiune interactiva.
-
----
-
-## 10. Riscuri si ce ramane de decis de Marius
-
-- **Coloana de procent — editabila sau doar afisata** (sectiunea 4.4). Recomandare: editabila
- (optiunea 2), pentru ca respecta litera deciziei din plan ("cele doua campuri... devin coloane"), dar
- costa un handler si un camp de lucru in plus. Daca simplitatea conteaza mai mult decat paritatea cu
- dialogul vechi, optiunea 1 (doar afisaj) reduce suprafata de cod fara sa piarda functionalitate reala
- (operatorul tot poate obtine orice discount tastand valoarea).
-- **Riscul de rotunjire in lant**: `do_calculeaza_discount` are cel putin 3 rotunjiri succesive pe
- drumul procent->valoare->procent (sectiunea 2) — comportament deja existent, nu introdus de S4c, dar
- mutarea in grid (editare mai frecventa, rand cu rand, fara sa mai treaca prin "confirmare" de
- dialog) ar putea face vizibile discrepante mici de rotunjire care azi treceau neobservate. Nu e un
- motiv sa se schimbe rotunjirile (ar strica alte fluxuri), doar un risc de UX de semnalat.
- **Zero cazuri gasite in cod care sa demonstreze deja o problema** — semnalat preventiv, nu confirmat.
-- **`Gather`/`Scatter` pe rand cu campuri MEMO**: `do_adauga_articol` foloseste `Gather ... MEMO`
- (`:12945-12950`) — handler-ul nou de coloana (sectiunea 4.5) trebuie sa faca la fel
- (`Scatter Name ... Memo` / `Gather Name ... Memo`), altfel campul `explicatie` (M) s-ar putea goli
- la fiecare editare de discount — **de verificat explicit la implementare**, nu doar presupus.
- Recomand un test dedicat: editeaza discountul pe o linie cu `explicatie` populata, verifica ca
- `explicatie` ramane neschimbata dupa `LostFocus`.
-- **Coloana `procdisc` din prototip** (`frm_facturare_articole2`, `:16721`) — scaffold mort, fara
- scriere (sectiunea 3). Recomandare: nu se reutilizeaza ca atare pentru coloana noua de procent —
- se porneste curat, cu functia noua din sectiunea 4.3, nu cu acest camp neconectat.
-- **Formularul `frm_facturare_articole2`** ramane prototip separat, ne-instantiat in productie — S4c
- nu are nevoie sa il atinga, dar daca exista intentia sa devina formularul unificat, coloanele lui
- de discount (deja editabile, `:16657`/`:16688`) ar trebui auditate separat pentru acelasi bug de
- recalcul (nu verificat aici — in afara perimetrului cerut).
-
----
-
-## 11. Punct deschis din S1 — `_checkbox1` vs `chkDetaliat`
-
-Nu apartine povestii S4c (nu am gasit nicio legatura cu discountul pe linie sau `grd_factura`), dar
-am dat peste ambele controale pe cale laterala, in `frm_alte_date` (`ferestre_cere_date.vc2`), asa ca
-inchid ieftin: **sunt doua controale distincte, nu o duplicare de nume**.
-- `_checkbox1` e un control generic (mostenit din clasa de baza), folosit in `frm_alte_date.Init`
- (`ferestre_cere_date.vc2:3188-3202`) doar ca **reper de layout** — pozitia lui determina inaltimea
- ferestrei si offset-ul altor controale, fara logica de business proprie vizibila in acest formular.
-- `chkDetaliat` e un checkbox cu nume propriu, legat de fluxul de incasare (`actualizeaza_tipincasare`,
- `:2728-2853`) — vizibil doar cand `opt_incasat` indica un anumit tip de incasare (POS/detaliat),
- ascuns/zero altfel; pe ramura `Else` a lui `Init` (`:3187-3205`, cand alt tip de context nu implica
- incasare deloc) e **eliminat explicit** din formular (`Thisform.RemoveObject('chkDetaliat')`,
- `:3201`), spre deosebire de `_checkbox1`, care ramane (e folosit chiar pe linia urmatoare pentru
- calculul inaltimii finale, `:3202`).
-
-**Concluzie**: nu e o inconsecventa de cod, sunt doua controale cu roluri diferite pe acelasi
-formular — punctul se poate inchide ca "nu e bug", cu rezerva ca n-am cercetat *de ce* `chkDetaliat`
-exista ca si `checkbox` separat de `opt_incasat` (ce reprezinta exact "detaliat") — nu era in
-perimetrul S4c si nu am aprofundat.
-
----
-
-## Necunoscute ramase (mostenite din rapoartele-sursa, nu re-investigate aici)
-
-- Interogarea SQL exacta care populeaza `crsarticole` cu discountul din politica de pret
- (`CRM_POLITICI_PRET_ART`) — cod in afara `ofacturare.vc2`, netrasat (mostenit din
- `discount_verificare2.md`, sectiunea "Necunoscute ramase").
-- Valorile implicite ale flag-urilor `gnEFACTURA_XML_DISC_PLISTA_LINIE`/`_ART` (mostenit din
- `discount_in_rapoarte_si_efactura.md`).
-- Comportamentul `crsfacturafinalaval` (varianta valuta a cursorului final de tiparire) — presupus
- simetric cu varianta lei, nu reverificat linie cu linie separat pentru S4c.
diff --git a/docs/cercetare/s4d_zi_curs_reactiv.md b/docs/cercetare/s4d_zi_curs_reactiv.md
deleted file mode 100644
index 848b15e..0000000
--- a/docs/cercetare/s4d_zi_curs_reactiv.md
+++ /dev/null
@@ -1,429 +0,0 @@
-# Proiectare S4d — Data cursului valutar, numai cand are sens (reactiv)
-
-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`, `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
-`git_sync.ps1`/`txt2vcx.ps1`, nicio scriere pe Oracle.
-
----
-
-## Verdict (rezumat)
-
-Regula reactiva se poate implementa fara sa strice nimic din ce e deja demonstrat sigur: implicitul
-`poDate.zi_curs` ramane neconditionat (nu se schimba), iar cheia reactivitatii e un camp deja prezent
-in cursorul de grid — `crsfactura.tip_valuta` — verificabil cu exact acelasi tipar SQL folosit deja in
-cod (`ofacturare.prg:1656`, `:1730`: `Select Distinct ... From crsfactura Where tip_valuta = 1`).
-Formularul-prototip `frm_facturare_articole2` are deja, azi, un `Clb_zi_curs` propriu, editabil, legat
-la `poDate.zi_curs` (`ofacturare.vc2:16285-16305`) — nu trebuie inventat un control nou, ci reevaluata
-vizibilitatea celui care exista deja. Mesajul Oracle `-20005` **contine deja** data si numele valutei
-lipsa (`STRINGAGG` peste toate valutele fara curs) — decizia 42 nu schimba *continutul* mesajului, ii
-schimba **domeniul**: il restrange de la "toate valutele din listele de preturi ale utilizatorului" la
-"valuta articolului cautat", dar **doar pe varianta filtrata a cautarii** (S4 punctul 1); pe caile cu
-document sursa (comanda/aviz/contract) incarcarea in masa ramane neconditionata. Plan sectiunea M
-(`:2635-2638`) cere explicit ca la aceasta eroare campul sa **revina vizibil** — asta intra ca pas de
-implementare, nu ca optiune. Bug-ul #16 **nu e in perimetrul S4d** — e deja cercetat si legat de S2
-(bucla de reincercare din `ofacturare.prg`), cu verdict separat in `s3_portare_antet.md`; S4d doar
-**confirma** ca noua arhitectura (antet persistent, nu recreat) ii inlatura mecanismul, daca S2/S3 nu
-recreeaza formularul la eroare.
-
----
-
-## 1. Inventarul controalelor de valuta si curs (`fisier:linie`)
-
-Patru definitii `Clb_zi_curs` in tot `ofacturare.vc2` (control compus `clb_tx_data`, camp text legat
-la `poDate.zi_curs`), confirmate exhaustiv (`grep "ADD OBJECT 'Clb_zi_curs'"`):
-
-| Formular | Definitie | Eliminat azi? | Validare la Termina | Sincronizare cu data |
-|---|---|---|---|---|
-| `frm_date_aviz` | `ofacturare.vc2:6727-6740` | Niciodata | Nu exista (fara `inainte_de_do_termin` care sa o ceara) | `Clb_dataact...LostFocus` (`:7603-7604`), `Clb_dataireg...LostFocus` (`:7610-7611`) — `Thisform.clb_zi_curs.Refresh()`, neconditionat |
-| `frm_date_aviz_lucrare` | `:7787-7801` | Niciodata | **Neconditionata**: `:8076` `Case Empty(Nvl(poDate.zi_curs,{}))` -> `:8078 This.clb_zi_curs.SetFocus()`, `plReturn=.F.` | `:8186-8187`, `:8193-8194`, neconditionat |
-| `frm_date_factura` | `:8701-8714` | **Doar** tip 8/9 (retur), `Init` `:9717-9722` (`RemoveObject`) | Conditionata: `:9484` `Case poDate.in_valuta=1 And Empty(...) And Type('thisform.clb_zi_curs.visible')<>'U'` -> `:9488 SetFocus` | `:9805-9808`, `:9824-9827`, ambele cu garda `Type(...)<>'U'` |
-| `frm_facturare_articole2` (prototip) | `:16285-16305`, camp text legat la `poDate.zi_curs` (`TEXT_SIMPLU1.ControlSource`) | **Niciodata** — `Init` (`:18988-19080`) nu contine niciun `RemoveObject('clb_zi_curs')` | Nu exista (formularul de articole nu are `inainte_de_do_termin` propriu de tip antet) | `Clb_dataact.TEXT_SIMPLU1.LostFocus` (`:19219-19222`) — acelasi tipar cu garda `Type(...)<>'U'` |
-
-Alte controale de valuta/curs, relevante ca sa nu fie confundate cu `clb_zi_curs`:
-
-- **`Ct_clb_valuta`** (selector de valuta document) — eliminat pe `frm_date_factura` cand
- `poDate.in_valuta=0` (`:9725-9728`), **neconditionat de tip**. Confirma ca "ascunde cand nu are sens"
- e deja un tipar folosit in aceeasi metoda, la doar 3 linii distanta de blocul retur — dovada directa
- ca autorul stia sa faca exact acest lucru, doar nu l-a aplicat si campului de curs.
-- **`lb_cursuri` + `grd_cursuri`** (eticheta si grid read-only "Curs valutar (data)") —
- `frm_facturare_articole.Init` (`:15092-15100`) si `frm_facturare_articole2.Init` (`:19000-19012`):
- ```
- ofacturare.vc2:19000-19012
- If !Used('crscursuri') Or Reccount('crscursuri') = 0
- Thisform.RemoveObject('lb_cursuri')
- Thisform.RemoveObject('grd_cursuri')
- Else
- If !Empty(Nvl(poDate.zi_curs, {}))
- Thisform.lb_cursuri.Caption = "Curs valutar " + Iif(!Inlist(poDate.tip, 8, 9), "(" + Dtoc(poDate.zi_curs) + ")", "")
- ...
- ```
- Acesta e **cel mai apropiat precedent de "arata/ascunde in functie de continut"** din codul existent
- — dar evalueaza `crscursuri` (cursurile incarcate pentru toate valutele din listele de preturi ale
- utilizatorului), **o singura data, la `Init`**, inainte ca userul sa fi adaugat vreo linie pe grid.
- **Nu e reactiv** la adaugare/stergere de articole — e evaluat o singura data pe un cursor diferit de
- `crsfactura`. Nu se poate copia ca atare pentru S4d; poate fi reutilizat doar ca **idiom** (verificare
- `Reccount(...) > 0` care decide `RemoveObject`/reafisare), mutat pe alt cursor si alt eveniment
- (punctul 2).
-- **`poArticol.tip_valuta`** — proprietate a politicii de pret a articolului (nu a documentului),
- populata la `do_initializeaza_articol`/cautare, citita masiv in calculul de pret/discount
- (`ofacturare.vc2:1857-2288`, `frm_articol_factura`). Cand articolul e adaugat pe grid, valoarea
- ajunge in coloana `crsfactura.tip_valuta` (vezi punctul 2) — acesta e semnalul pe care se construieste
- conditia reactiva, nu `poArticol` (obiect temporar, mort dupa `Release`).
-
-**Cine citeste `poDate.zi_curs` dupa formular** (relevant ca sa nu se rupa nimic la ascundere) — deja
-documentat exhaustiv in `zi_curs_validare.md` §4 si `valuta_si_curs.md` §4: cursoarele de articole
-(`cursor_preturi`/`cursor_articole_k`/`cursor_gestiune`/`cursor_lucrare`, `ofacturare.prg:266-308`),
-eticheta `lb_cursuri`, si validarile de mai sus. Nimic din acest tabel se schimba prin S4d.
-
----
-
-## 2. Conditia reactiva, exact
-
-**Camp folosit:** `crsfactura.tip_valuta` (N(1)), definit la creearea cursorului de grid,
-`creeaza_facturacrs` (`COMUN\programe\ofacturare_comun.prg:1776`), populat la fiecare linie adaugata
-prin `do_adauga_articol` (coloana e in lista de `Insert`/`Scatter`, `ofacturare.vc2:12950`,
-`:17258` pentru `frm_facturare_articole2`) direct din `poArticol.tip_valuta`.
-
-**Verificare, cu exact acelasi tipar deja folosit in productie** (nu inventat):
-
-```
-ofacturare.prg:1656, :1730 [listeaza_ofacturare]
-Select Distinct nume_val, Curs, multiplicator From crsfactura Where tip_valuta = 1
-```
-
-Pentru S4d, verificarea de vizibilitate se reduce la:
-
-```foxpro
-lVizibil = !Inlist(poDate.tip, 8, 9) And ;
- (poDate.in_valuta = 1 Or (Used('crsfactura') And Reccount('crsfactura', 1) > 0) )
-```
-
-unde `Reccount('crsfactura', 1)` inseamna "exista macar un rand cu `tip_valuta=1`" — in practica se
-scrie ca `Calculate Cnt() To lnLinii For tip_valuta=1` sau `Select Count(*) From crsfactura Where
-tip_valuta=1 Into Array laCnt`, ca sa nu depinda de pozitia recordului curent din grid.
-
-**Cand se reevalueaza — pe evenimentul deja existent de recalcul, nu pe un timer nou.** Atat
-`do_adauga_articol` (`:17124-17393`) cat si `do_sterge` (`:18619-18704`) se termina cu apelul
-**`Thisform.do_calculeaza_totaluri()`** (`:17360`, `:18687`) — acesta e deja punctul unic prin care
-formularul "stie" ca s-a schimbat compozitia liniilor (totaluri, discount pe articole etc). E locul
-natural unde se adauga si reevaluarea `clb_zi_curs`: dupa fiecare adaugare de linie **si** dupa fiecare
-stergere, `do_calculeaza_totaluri` (sau un apel adaugat imediat dupa el in cele doua metode) reface
-`lVizibil` de mai sus si seteaza `Thisform.clb_zi_curs.Visible = lVizibil`.
-
-**Modificarea unei linii existente** (schimbare cantitate/pret pe o linie deja adaugata) nu schimba
-`tip_valuta` — acesta e o proprietate a politicii de pret, fixata la adaugare, nu editabila pe grid.
-Deci nu exista eveniment suplimentar de "editare linie" care sa afecteze conditia — doar adaugare si
-stergere pot muta numarul de linii cu `tip_valuta=1` de la 0 la >0 sau invers. (Verificat: nu exista
-`do_modifica` separat pe `frm_facturare_articole2` in indexul de simboluri — editarea unei linii merge
-prin acelasi `do_adauga_articol`/dialog, care oricum recheama `do_calculeaza_totaluri`.)
-
-**De ce nu `poDate.in_valuta`-style (o singura evaluare la Init):** documentul poate incepe fara nicio
-linie in valuta si poate primi una la mijlocul sesiunii de facturare — exact cazul pe care unificarea
-il face posibil de rezolvat (azi antetul se inchide inainte sa existe `crsfactura`). Evaluarea trebuie
-sa fie pe eveniment, nu pe `Init`.
-
----
-
-## 3. Trecerea inapoi — ultimul articol in valuta e sters
-
-**Recomandare: ascunde din nou (simetric), dar NU goli `poDate.zi_curs`.**
-
-Argumente pe tiparul deja folosit, nu pe teorie:
-
-- `lb_cursuri`/`grd_cursuri` (punctul 1) folosesc deja idiomul "vizibil doar cand `Reccount(...) > 0`"
- — o conditie booleana simpla, reevaluabila oricand fara efecte laterale, pentru ca `RemoveObject`/
- re-adaugare (sau `Visible=`) nu ating proprietatea de date din spate (`poDate.zi_curs`). Simetria
- (ascunde la 0, arata la >0) e deja tratata ca stare normala pentru acel control, nu ca o exceptie de
- construit.
-- `poDate.zi_curs` **nu se goleste niciodata** in tot codul existent (confirmat exhaustiv in
- `zi_curs_validare.md` §5-6) — nici la `RemoveObject` (tip 8/9), nici la ascunderea `lb_cursuri`. Deci
- ascunderea campului de curs cand ultima linie in valuta dispare **nu pierde valoarea**: daca userul
- adauga din nou o linie in valuta in aceeasi sesiune, campul reapare cu **aceeasi data** pe care o avea
- inainte de ascundere (fie cea introdusa manual, fie implicitul de la `Init`), nu resetata la azi.
-- Alternativa ("ramane vizibil o data aratat") ar introduce un tip nou de stare per-sesiune
- (`lFostVizibilCandva`) fara niciun precedent in cod si fara beneficiu clar — userul care sterge
- singura linie in valuta de pe o factura in lei nu mai are, de fapt, niciun motiv sa vada/editeze
- cursul; a lasa campul vizibil ar fi exact inconsistenta pe care decizia 15 vrea sa o elimine.
-
-**Exceptie de la simetrie, ceruta de plan (sectiunea M, `:2635-2638`):** cand vine eroarea Oracle
-`-20005` cu campul ascuns, campul **trebuie adus inapoi vizibil**, indiferent de `Reccount`-ul curent —
-vezi punctul 5. Acesta e singurul caz in care regula reactiva simetrica se suspenda explicit.
-
----
-
-## 4. Interactiunea cu `in_valuta` la nivel de document
-
-`poDate.in_valuta` e stabilit o singura data, in `Init`, exclusiv din `tnTip`/`tnIdSet`
-(`ofacturare_comun.prg:248-250`, confirmat exhaustiv in `valuta_si_curs.md` §1) — **nu exista cale de
-cod care sa-l schimbe dupa Init**, iar controlul de alegere a valutei (`Ct_clb_valuta`) e chiar
-eliminat din formular cand `in_valuta=0` (`ofacturare.vc2:9725-9728`), deci operatorul nu are de unde
-sa-l aleaga manual. Prin urmare **intrebarea "ce se intampla daca operatorul schimba valuta documentului
-dupa ce a adaugat linii" nu se poate pune in arhitectura actuala** — nu exista control care sa permita
-acea schimbare. Documentul e in valuta sau nu inca de la alegerea tipului (`tnTip`), inainte ca vreo
-linie sa existe.
-
-Pentru S4d, consecinta e simpla: `poDate.in_valuta=1` e o conditie **statica** pe toata durata sesiunii
-de facturare — cand e adevarata, `clb_zi_curs` ramane vizibil necontenit (ca azi), indiferent de ce se
-intampla pe grid; conditia reactiva descrisa la punctul 2 conteaza **doar** pentru ramura
-`in_valuta=0`. Nu exista tranzitie `in_valuta 0->1` sau `1->0` de tratat.
-
----
-
-## 5. Mesajul de eroare `-20005`
-
-### 5.1 Unde se ridica azi
-
-`pack_facturare.verifica_cursuri_valute` (Oracle, `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16247-16274`):
-
-```sql
-16268 IF V_NUME_VALUTE IS NOT NULL THEN
-16269 RAISE_APPLICATION_ERROR(-20005,
-16270 'Nu este setat cursul din data de ' ||
-16271 to_char(V_DATA_CURS, 'DD/MM/YYYY') ||
-16272 ' pentru ' || V_NUME_VALUTE || '!');
-16273 END IF;
-```
-
-`V_NUME_VALUTE` e un `STRINGAGG` (`:16252-16266`) peste **toate** valutele din
-`FACT_VPRETURI_UTILIZATOR` ale utilizatorului curent care nu au curs valabil la `V_DATA_CURS` — exclude
-doar moneda nationala. **Mesajul contine deja data si numele valutei/valutelor** — nu e un cod generic.
-Apelata neconditionat din `cursor_preturi` (`:2153`), si delegat din `cursor_contract` (jumatatea
-`crsarticole`, `s4_cautare_articole_server.md:83-85`).
-
-### 5.2 Traseul pana la operator, azi
-
-```
-ofacturare.prg:313-317 (identic ofacturare.prg:828-832, factureaza2)
-If lnSucces < 0
- AMESSAGEBOX(goExecutor.oPrelucrareEroare(), 16, "Eroare")
- If goExecutor.nEroare = 20005
- vizualizeaza_curs(poDate.zi_curs)
- ENDIF
-```
-
-`goExecutor.oPrelucrareEroare()` (`COMUN\programe\oproceduri_comune.prg:626-639`) extrage **textul
-brut** dintre `ORA-20xxx:` si urmatorul `ORA` din mesajul Oracle — pentru erori in intervalul
-20000-20999 (cazul de aici), operatorul vede **exact** textul PL/SQL de mai sus, netrunchiat, nemodificat.
-Deci raspunsul la "mesajul spune care valuta si ce zi lipsesc" e: **da, deja o face**, azi, inainte de
-orice modificare S4d.
-
-### 5.3 Ce schimba decizia 42
-
-Decizia 42 (plan `:512-516`) **nu schimba textul** mesajului — schimba **domeniul de valute verificate**,
-si **doar pe varianta filtrata a cautarii** (S4 punctul 1, `cursor_preturi` chemat per-articol-cautat,
-nu la incarcarea in masa). Azi (fara decizia 42), pe orice apel al lui `cursor_preturi`,
-`V_NUME_VALUTE` poate include valute complet nelegate de articolul pe care userul tocmai il cauta —
-de exemplu userul cauta un articol in RON, dar mesajul ii spune ca lipseste cursul pentru EUR, pentru
-ca EUR apare undeva in politicile lui de pret. Dupa decizia 42, pe cautarea filtrata, verificarea se
-restrange la valuta randului adus — deci mesajul (acelasi format text) va numi, natural, **doar
-valuta relevanta pentru cautarea curenta**, nu un agregat strain.
-
-**Rezerva importanta, de citit impreuna cu S4d:** decizia 42 se aplica explicit "pe varianta filtrata
-a cursoarelor" — adica pe calea noua de cautare per-articol introdusa de S4 punctul 1, folosita azi
-doar pe **ramura de lista de preturi** (`s4_cautare_articole_server.md:68-69`: "S4 se aplica curat doar
-pe ramurile de lista de preturi"). Pe **comanda / aviz / contract**, incarcarea in masa a articolelor
-(bookkeeping obligatoriu, `crsarticole` citit si scris de `do_adauga_tot`/`do_sterge`/`do_scrie_factura`)
-**ramane neschimbata**, deci `verifica_cursuri_valute` tot ruleaza neconditionat (toate valutele din
-politicile utilizatorului), la incarcarea initiala a grilei — nu doar pe articolul cautat. **Pe aceste
-tipuri, mesajul poate inca numi o valuta care n-are legatura cu documentul curent**, indiferent de
-decizia 42 — asta ramane o diferenta reala fata de "campul e ascuns pentru ca documentul nu are nevoie
-de curs", si intra la riscuri (punctul 10).
-
-### 5.4 Ce se schimba prin S4d — nu textul, ci vizibilitatea campului dupa eroare
-
-Cerinta explicita din plan, sectiunea M (`:2635-2638`):
-
-> Ascunderea datei de curs poate lasa un document fara curs corectabil [...] utilizatorul nu mai are
-> unde sa corecteze data daca i-am ascuns campul. **Regula din M trebuie sa aduca inapoi campul in
-> exact acest caz.**
-
-Implementare propusa, la punctul de interceptare deja existent:
-
-```foxpro
-* ofacturare.prg:313-317 (si simetric la :828-832)
-If lnSucces < 0
- AMESSAGEBOX(goExecutor.oPrelucrareEroare(), 16, "Eroare")
- If goExecutor.nEroare = 20005
- If Type('thisform.clb_zi_curs.visible')<>'U' And !thisform.clb_zi_curs.Visible
- thisform.clb_zi_curs.Visible = .T. && aduce campul inapoi, indiferent de conditia reactiva
- Endif
- vizualizeaza_curs(poDate.zi_curs)
- ENDIF
-```
-
-Nota: `thisform` aici nu e formularul de antet (deja inchis la acest punct in arhitectura veche) — e
-motivul pentru care acest fix e legat de rezultatul S3/S2 asupra bug-ului #16 (punctul 6): daca
-antetul unificat ramane deschis/persistent (nu recreat), `thisform.clb_zi_curs` exista si poate fi
-readus vizibil direct; daca arhitectura tot recreaza un formular nou dupa eroare, readucerea vizibila
-trebuie facuta in `Init`-ul noii instante, verificand acelasi semnal (`goExecutor.nEroare=20005` din
-iteratia anterioara, sau un flag explicit propagat).
-
-**Textul mesajului propus de pastrat neschimbat** (deja corect): *"Nu este setat cursul din data de
-DD/MM/YYYY pentru !"*. Nu se propune inlocuirea lui — se propune doar sa nu mai fie surprinzator
-faptul ca operatorul nu are unde sa corecteze, prin readucerea campului.
-
----
-
-## 6. Verificarea daca #16 dispare
-
-**Ce e #16:** `COMUN\docs\todos.txt:45` — "la revenire din formularul de curs valutar, focusul revine
-[...] pe TIP DOCUMENT, si la iesire din serie se regenereaza numar act". Citat si in plan
-`:1926-1927`, `:2665-2668`.
-
-**Deja cercetat, cu verdict**, in `docs\cercetare\s3_portare_antet.md` §6 (runda 9), **inainte** de
-aceasta sesiune — S4d nu redeschide cercetarea, o **confirma si o leaga** de domeniul propriu (eroarea
-`-20005`, singurul declansator relevant pentru S4d):
-
-- **#16 nu e un bug de focus.** E o bucla de reincercare (`ofacturare.prg:174-571`, `Do While
- lnRaspuns=6`) care trateaza **orice** esec Oracle la incarcarea cursorului de articole ca pe un "DA,
- utilizatorul vrea alt document" — `lnRaspuns` nu se reseteaza pe ramura de eroare
- (`ofacturare.prg:555-564`, in `Else`, niciodata atinsa cand `lnSucces<0`), deci bucla externa reintra
- automat si **recreeaza formularul de antet de la zero** (`Createobject`, `:230`). `Init`-ul noii
- instante seteaza focus neconditionat pe `ct_clb_fdoc` (`:9788-9793`) — asta e "focusul care revine pe
- tip document" — si `LostFocus`-ul care urmeaza cheama neconditionat `clb_serie_act`, care aloca un
- numar nou (`serii_numere.vc2:122-127`) — asta e "regenerarea numarului".
-- **Cauza reala e in `ofacturare.prg` (bucla de emitere, cod comun suitei), nu in formularul de antet.**
- `s3_portare_antet.md:337-350` e explicit: portarea antetului (S3) NU rezolva automat #16 — arhitectura
- unificata (un singur `Init` persistent, antetul nu mai e un obiect separat distrus/recreat de apelant)
- **are sansa reala** sa-l elimine ca efect secundar, **dar numai daca implementarea nu recreaza
- formularul intreg la reincercare dupa o eroare Oracle** — ceea ce reproduce bugul identic, doar mutat.
- Verdictul e legat explicit de **S2**, nu de S3/S4d: bucla traieste in procedura de emitere, nu in
- formular.
-
-**Raspunsul specific S4d, cerut de plan** ("Verifica in acelasi timp daca #16 dispare — vezi M"):
-**da, S4d confirma exact scenariul care declanseaza #16** — eroarea `-20005` de la
-`verifica_cursuri_valute` e unul dintre cazurile `lnSucces<0` care intra pe ramura problematica a
-buclei (`vizualizeaza_curs(poDate.zi_curs)` la `:315`, chiar linia care deschide `frm_curs`, exact
-recuperarea citata in reclamatia originala). Deci daca S2/S3 rezolva #16 (antet persistent, fara
-recreare), **S4d beneficiaza direct** — dupa `-20005`, userul revine in acelasi antet unificat
-(nu unul nou), campul `clb_zi_curs` readus vizibil (punctul 5.4) ramane exact acolo unde a fost adus
-inapoi, fara sarituri de focus si fara renumerotare. Daca S2/S3 NU rezolva #16 (recreare inca prezenta),
-S4d **nu il agraveaza si nu il repara** — comportamentul ramane identic cu azi pe acest punct, dar
-readucerea campului vizibil (5.4) trebuie facuta in `Init`-ul noii instante, nu presupusa mostenita.
-
-**Concluzie:** #16 **nu e in perimetrul de implementare al S4d** (e S2, per plan `:1944`), dar S4d
-**depinde de rezultatul lui** pentru UX-ul complet al recuperarii de eroare (5.4) — de marcat explicit
-ca dependenta la implementare, nu de reinvestigat.
-
----
-
-## 7. Pasi de implementare, ordonati
-
-Fiecare pas lasa suita functionala; calea veche (`frm_date_factura`/`frm_facturare_articole2` cum sunt
-azi) nu se sterge in etapa I.
-
-1. **Adauga functia de evaluare a conditiei reactive** pe formularul unificat (metoda noua, de ex.
- `do_actualizeaza_vizibilitate_curs`), care calculeaza `lVizibil` conform formulei din punctul 2 si
- seteaza `Visible` pe controlul `clb_zi_curs` mostenit din prototipul `frm_facturare_articole2`
- (`ofacturare.vc2:16285-16305`) — **nu un control nou**, cel existent, ale carui evenimente de
- sincronizare (`Clb_dataact...LostFocus`, `:19219-19222`) raman neschimbate (deja garda pe
- `Type(...)<>'U'`, deci tolereaza si eliminare, nu doar `Visible=.F.`).
- *Gata cand:* metoda exista, se poate apela manual (fara UI), si intoarce `.T.`/`.F.` corect pe cele
- patru combinatii din punctul 8 (tip retur / nu, `in_valuta` 0/1, cu/fara linie `tip_valuta=1`).
-2. **Cheama metoda din pasul 1 la sfarsitul `do_adauga_articol` si `do_sterge`**, imediat dupa (sau in)
- `Thisform.do_calculeaza_totaluri()` (`:17360`, `:18687` in prototip — liniile echivalente in
- formularul unificat, dupa portarea din S3/S4).
- *Gata cand:* adaugarea unei linii cu `tip_valuta=1` pe o factura in lei fara alte linii de acest fel
- face campul vizibil imediat, fara Refresh manual; stergerea ultimei asemenea linii il ascunde din nou
- (simetric, punctul 3), fara sa goleasca `poDate.zi_curs`.
-3. **Verifica initializarea la deschiderea formularului** (cazul `in_valuta=1` sau document reincarcat
- cu linii deja existente, ex. la editare factura emisa) — `Init`-ul unificat trebuie sa apeleze aceeasi
- metoda o data, dupa ce `crsfactura` e populat, nu doar sa se bazeze pe evenimentele de adaugare/
- stergere (care nu ruleaza la incarcarea initiala a unui document existent).
- *Gata cand:* deschiderea unei facturi existente (in lei, cu linii in valuta deja salvate) arata
- campul corect de la primul `Show()`, fara sa fie nevoie de o adaugare/stergere care sa-l declanseze.
-4. **Elimina campul neconditionat pe retur (tip 8/9)**, ca azi — verifica ca formula din pasul 1 include
- deja `!Inlist(poDate.tip,8,9)` inaintea oricarei alte conditii, ca sa nu-l readuca vizibil din greseala
- printr-o linie in valuta pe un retur (desi returul nu foloseste `zi_curs`, vezi `zi_curs_validare.md`
- §4c/§6 — comportamentul trebuie sa ramana identic azi, nu doar "fara efect").
- *Gata cand:* pe orice tip 8/9, campul e absent indiferent de continutul grilei.
-5. **Readu campul vizibil la eroarea `-20005`** (punctul 5.4) — modifica ramura `goExecutor.nEroare=20005`
- din bucla de emitere (`ofacturare.prg:313-317`/`:828-832`, sau echivalentul ei in noua arhitectura
- integrata cu formularul unificat, cf. S3 pasul 6) ca sa forteze `Visible=.T.` pe `clb_zi_curs` inainte
- de a deschide `frm_curs`.
- *Gata cand:* pe o factura in lei cu campul ascuns, o eroare `-20005` simulata (curs lipsa de test)
- face campul vizibil imediat dupa mesaj, inainte sau odata cu deschiderea `frm_curs`.
-6. **Coordoneaza cu decizia 42 (S4 punctul 1)**: cand acea poveste implementeaza restrangerea
- `verifica_cursuri_valute` la valuta articolului cautat, verifica ca textul afisat prin
- `oPrelucrareEroare()` (punctul 5.1-5.2, neschimbat) tot numeste corect valuta si data — nu necesita
- modificare pe partea VFP, doar confirmare ca noul parametru Oracle e transmis corect din calea de
- cautare filtrata.
- *Gata cand:* pe cautarea filtrata (dupa decizia 42), mesajul `-20005` numeste doar valuta cautata, nu
- un agregat.
-7. **Regresie pe formularul vechi**: confirma ca niciuna din modificarile 1-6 nu atinge
- `frm_date_factura`/`frm_facturare_articole` (calea veche, ramasa in productie) — toate modificarile
- se fac pe clasele formularului unificat / prototip, nu pe cele originale.
- *Gata cand:* `svn diff`/`git diff` arata modificari doar in clasele noii cai.
-
----
-
-## 8. Cum se verifica
-
-Pe probele din plan (`:2243-2246`), plus cazurile suplimentare care rezulta din punctele 2-6:
-
-1. **Factura in lei, fara articole in valuta** — `clb_zi_curs` nu apare la deschidere; documentul se
- emite corect (acelasi rezultat `VANZARI`/`ACT`/`RUL` ca azi, criteriul din S3 §7).
-2. **Aceeasi factura, dupa adaugarea unui articol cu pret in valuta** — campul apare imediat, cu data
- implicita deja completata (data documentului, de la `Init`/`Reset`, nemodificata).
-3. **Stergerea articolului din pasul 2** (singurul cu `tip_valuta=1`) — campul dispare din nou; valoarea
- din `poDate.zi_curs` ramane cea introdusa/implicita (verificabil citind proprietatea direct, nu doar
- vizual).
-4. **Readaugarea unui alt articol in valuta, in aceeasi sesiune** — campul reapare cu **aceeasi** data
- ca la pasul 2, nu resetata.
-5. **Factura in valuta (`in_valuta=1`)** — campul apare mereu, indiferent de continutul grilei, exact ca
- azi (fara regresie pe cazul deja functional).
-6. **Retur (tip 8/9)** — campul absent indiferent de linii; document salvat corect (cf. precedent deja
- existent).
-7. **`-20005` cu campul ascuns** (factura in lei, curs de test lipsa pentru o valuta din politicile
- utilizatorului) — mesajul numeste valuta si data lipsa (deja azi); campul devine vizibil dupa eroare.
-8. **Editare factura emisa** (cf. #6, formular deja in lucru separat) — deschiderea unei facturi in lei
- cu linii in valuta deja salvate arata campul corect de la primul `Show()` (pasul 3 de implementare).
-9. **Dupa decizia 42** — cautarea filtrata a unui articol cu curs lipsa arata mesaj cu o singura valuta
- (a articolului cautat), nu un agregat.
-
----
-
-## 9. Ce nu se poate testa headless
-
-- **Focusul si secventa reala `SetFocus`/`LostFocus`/`Visible=`** pe controale UI reale — capcana deja
- cunoscuta (`grid-coloane-nu-se-materializeaza-headless`, memorie de proiect): sub harness `-A -T`,
- proprietatile de grid/vizibilitate nu se materializeaza identic cu UI vizibil. Verificarea
- vizibilitatii reactive (punctele 2-3) trebuie facuta fie prin verificare directa a proprietatii
- `.Visible` dupa apelul metodei (fara `Show()`), fie cu `vfp_ui_harness.ps1`, UI vizibil.
-- **Eroarea Oracle `-20005` reprodusa real** — necesita fie date de test cu un curs lipsa garantat pe o
- fereastra de date controlata (manipulare de date, nu de UI), fie mock pe `goExecutor` care simuleaza
- `nEroare=20005` fara conexiune reala — niciuna verificata ca exista deja in suita de teste.
-- **Deschiderea modala a `frm_curs`** (`vizualizeaza_curs`) — `Show(1)` modal, aceeasi limitare generala
- a testarii headless pe formulare modale.
-- **Bug #16 propriu-zis** (secventa reala de focus dupa recreare de formular) — deja marcat netestabil
- headless in `s3_portare_antet.md` §8; S4d nu adauga o cale noua de testare, doar depinde de acelasi
- rezultat.
-
----
-
-## 10. Riscuri si de decis de Marius
-
-1. **Incarcarea in masa pe comanda/aviz/contract ramane neconditionata dupa decizia 42** (punctul 5.3).
- Pe aceste tipuri, `-20005` poate inca numi o valuta nelegata de documentul curent, chiar daca `S4d`
- ascunde corect campul pe baza continutului grilei. **Recomandare:** de discutat daca extinderea
- restrangerii decizia-42-style merita si pe incarcarea in masa (poveste separata, posibil in S4 sau
- intr-o continuare a deciziei 42), sau se accepta ca diferenta cunoscuta, documentata aici.
-2. **Cine seteaza `Visible=.T.` la `-20005` cand antetul ar fi fost recreat** (daca #16 nu se rezolva
- complet in S2/S3 pana la implementarea S4d) — punctul 5.4/6 presupune `thisform` = acelasi formular
- persistent; daca arhitectura finala tot recreaza o instanta, logica trebuie mutata in `Init`, cu un
- semnal explicit propagat (ex. proprietate `poDate.lCursLipsa` sau echivalent) ca sa stie noua instanta
- sa arate campul. **Recomandare:** de tratat ca parte a pasului 6 din `s3_portare_antet.md` (integrarea
- buclei de emitere), nu izolat in S4d.
-3. **`frm_date_aviz`/`frm_date_aviz_lucrare` (tipurile 27, 30) nu intra in perimetrul imediat** — daca
- formularul unificat le preia mai tarziu, validarea neconditionata de la `:8076` trebuie aliniata la
- aceeasi regula reactiva (azi ramane necondiționata, per `zi_curs_validare.md` §6). **Recomandare:** nu
- se atinge acum; se trateaza cand/daca acele tipuri intra in unificare.
-4. **Simetria "ascunde la 0 linii" (punctul 3) e o recomandare, nu o certitudine ceruta explicit de
- plan** — planul cere doar "apare cand...", nu specifica explicit comportamentul la disparitia ultimei
- linii. **Recomandare:** simetria propusa aici (argumentata pe tiparul `lb_cursuri`), dar de confirmat
- cu Marius inainte de implementare, pentru ca schimba usor experienta (campul "clipeste" la
- adaugare/stergere repetata a aceleiasi linii).
diff --git a/docs/cercetare/s4e_lista_preturi_pe_sursa.md b/docs/cercetare/s4e_lista_preturi_pe_sursa.md
deleted file mode 100644
index a79e294..0000000
--- a/docs/cercetare/s4e_lista_preturi_pe_sursa.md
+++ /dev/null
@@ -1,444 +0,0 @@
-# S4e — Lista de preturi disponibila si pe factura din comanda
-
-Proiectare pe cod, READ-ONLY (fara editari, fara `git_sync.ps1`/`txt2vcx.ps1`, fara commit, fara
-scriere Oracle — numai `SELECT`), pentru povestea **S4e** din
-`docs\plan_13_unificare_formular_facturare.md:2249-2267` (decizia 16, text integral in sectiunea J
-a planului). Nu se ating `COMUN\clase\ofacturare_comun.vc2` si `COMUN\programe\ofacturare_editare.prg`
-(perimetrul altei sarcini in lucru; `COMUN\programe\ofacturare_comun.prg` si
-`COMUN\programe\ofacturare.prg` sunt citite, nu editate). Decizia 29 (stergerea unei linii din comanda
-ramane fara protectie) nu se reargumenteaza.
-
-**Status: cercetare incheiata.**
-
----
-
-## Verdict (esenta, pentru cine nu citeste tot)
-
-**Reteta literal citata in decizia 16 — `APPEND FROM` la `ofacturare.prg:454-473`, care lipeste
-lista de preturi peste `crsarticole` — nu trebuie generalizata pe comanda ca atare. E nesigura acolo,
-pe cod, nu doar teoretic.** `crsarticole` e simultan grid-sursa **si** registrul de cantitate ramasa
-citit/scris de `do_sterge` si `do_scrie_factura` (decizia 39, S4 punctul 2). Doua motive concrete,
-verificate pe cod si pe SQL exportat:
-
-1. **Coliziune de `id_c`.** Fiecare procedura `cursor_*` din `PACK_FACTURARE` numeroteaza `id_c` cu
- `ROWNUM`, pornind de la 1, **independent** de orice alta executie. `cursor_comanda` (liniile
- comenzii) si `cursor_preturi` (lista de preturi) ar produce, executate separat si apoi lipite
- prin `APPEND FROM`, doua seturi de `id_c` care se suprapun (1, 2, 3…). `do_sterge` potriveste
- randul de sters in `crsarticole` **prin `id_c`** (`ofacturare.vc2:14652-14655`,
- `:14658-14659`) — o coliziune ar face ca stergerea unei linii libere sa modifice cantitatea
- ramasa a unei linii de comanda complet diferite (sau invers), tacut, fara eroare.
- Codebase-ul insusi cunoaste acest risc: `cursor_contract` (`PACK_FACTURARE:2722`,
- `SELECT rownum - 10000 as id_c ...`) foloseste deliberat un offset ca sa nu se suprapuna cu
- spatiul de `id_c` al celuilalt cursor din acelasi apel.
-2. **Poluarea registrului.** `do_scrie_factura` face `Calculate Sum(cantitate) To lnCantitateRamasa`
- peste **tot** `crsarticole` ca sa decida daca se ofera inchiderea automata a comenzii
- (`ofacturare.vc2:14332-14338`). Coloana `cantitate` din `cursor_preturi` **nu inseamna "ramas de
- facturat"** — inseamna **stoc disponibil** (`NVL(C.CANTITATE,0)`, derivat din miscari de stoc,
- `PACK_FACTURARE:2276-2280` si similar pe fiecare ramura). Amestecarea celor doua ar face ca suma
- folosita pentru decizia de inchidere sa includa cantitati de stoc fara nicio legatura cu ce a mai
- ramas de facturat din comanda — decizia de inchidere automata ar deveni gresita, tacut.
-
-**De ce merge pe contract fara aceste probleme**: pe contract, lista de preturi **nu intra niciodata
-in acelasi cursor** cu articolele contractului. `cursor_contract` intoarce **doua** cursoare Oracle
-separate (`V_CURSOR` = `cursor_preturi`, mapat pe `crsarticole`; `V_CURSOR2` = articolele/ratele
-contractului, mapat pe `crsarticole1`, cu `id_c` offset `-10000`) si **niciun `do_scrie_factura`
-nu calculeaza `Sum(cantitate)` pe tipurile de contract** (2,6,26,52) — acel `Do Case` nu are ramura
-pentru ele, cad in `Otherwise`, fara nicio logica de inchidere automata. Contractul "merge" pentru ca
-lista de preturi traieste azi acolo unde nu exista niciun registru de citit.
-
-**Solutia curata pentru comanda, verificata ca fezabila pe cod**: liniile libere **nu intra deloc in
-`crsarticole`**. Mecanismul de adaugare a lor e cel construit de **S4** — cautare filtrata pe server
-(`cursor_preturi` cu parametru de filtru, `docs\cercetare\s4_cautare_articole_server.md`, punctul 4)
-legata printr-un `combosql`/`APPEND BLANK` **direct pe `crsfactura`** (exact tiparul deja existent in
-`frm_facturare_articole2.But_nou1.do_adauga`, `ofacturare.vc2:17118-17122`: `Select crsFactura /
-APPEND BLANK`), nu prin `do_adauga_articol`/`Scatter` dintr-un cursor sursa. Fiindca linia nu vine
-niciodata dintr-un rand real al lui `crsarticole`, `crsfactura.id_c` ramane la valoarea implicita a
-campului (`N(20)`, fara `Null`, deci `0` la `APPEND BLANK`) — **valoare pe care Oracle nu o produce
-niciodata** (`ROWNUM` porneste de la 1), deci `do_sterge`-ul de azi (`For id_c = poArticol.id_c`) e
-deja, prin constructie, un no-op sigur pe o linie libera, **fara nicio modificare de cod in
-`do_sterge`**. Precedentul exista deja in acelasi fisier: linia de discount adaugata la
-`ofacturare.vc2:14531-14537` (`Append Blank` pe `crsfactura`, fara `id_c`) foloseste exact acest
-tipar azi, in productie.
-
-Ramane un gol real de proiectat, nu de presupus rezolvat: **validarea de cantitate/stoc pe o linie
-libera** nu se poate sprijini pe `do_verifica_articol` (cuplat de `crsarticole`) — vezi sectiunea 6.
-
----
-
-## 0. Ce e deja stabilit (nu se reinvestigheaza)
-
-- Optiunea "Cauta in lista de preturi…" intra in meniul de adaugare proiectat la S4b
- (`docs\cercetare\s4b_bara_butoane_meniu.md`) — S4e ii da un element de meniu, nu un buton propriu.
-- **Decizia 29**: stergerea unei linii venite din comanda ramane FARA protectie — se sterge ca
- oricare alta, comanda ramane facturata partial. Nu se reia.
-- **Legatura cu S4 punctul 2 (decizia 39)**: `crsarticole` e si registru al cantitatii ramase de
- facturat. La momentul scrierii acestui raport, `docs\cercetare\s4_punct2_registru_cantitate_ramasa.md`
- e **in lucru** (sectiuni "IN LUCRU", fara concluzie de proiectare inca). Acest raport **nu asteapta**
- acea proiectare: dovezile de mai jos (id_c, `Calculate Sum`) sunt citite direct pe codul actual, nu
- presupuse din raportul in lucru. Presupunerea facuta explicit aici: **designul propus (liniile
- libere nu intra in `crsarticole`) e compatibil cu orice varianta de decuplare a registrului pe care
- S4 punctul 2 ar alege-o** — pentru ca liniile libere nu ating deloc cursorul/mecanismul pe care
- punctul 2 il decupleaza. Daca punctul 2 alege sa mute registrul intr-un cursor complet nou (nu
- `crsarticole`), concluzia ramane aceeasi cu o singura schimbare de nume.
-- **S4 (`docs\cercetare\s4_cautare_articole_server.md`) a decis deja**, pe cod, ca pentru
- comanda/aviz (3,4,21,25,28,42,47) `crsarticole` **ramane incarcat in masa**, neschimbat — punctul 7
- al acelui raport. Aceasta decizie priveste **selectia articolelor comenzii insesi** (raman pe
- `grd_articole`/`crsarticole`/`do_adauga_tot`, neschimbate). **Nu exclude** mecanismul S4e: cautarea
- filtrata pe server construita de S4 (`cursor_preturi` cu `V_FILTRU_COD`/`V_FILTRU_DEN`) e exact
- ce S4e reutilizeaza pentru liniile **libere**, un canal separat, care nu inlocuieste si nu atinge
- `grd_articole`.
-
-## 1. Ce face azi calea de copiere (`ofacturare.prg:454-473`)
-
-Cod complet (`COMUN\programe\ofacturare.prg:454-473`):
-
-```
-ELSE
- IF m.llCopiere
- * Modificare sau copiere factura
- * Nu adaug automat articolele din factura originala, ca sa dau posibilitate de modificare a cantitatilor, pretului, explicatiei
- * ofrmdetaliifactura.do_adauga_tot()
-
- * Sterg din cursorul cu articole inregistrarile adaugate in factura
- *DELETE FROM crsArticole
-
- * Adaug in lista articolelor cursorul cu lista de preturi ca sa pot adauga si alte articole in factura copiata/modificata
- lcSqlCursor = [{call pack_facturare.cursor_preturi(?poDate.zi_curs,?poDate.tip,?poDate.id_valuta,] + ;
- [?poDate.id_gestiune_init,?gnLuna,?gnAn,?gnIdUtil,?gnIdSucursala)}]
-
- lcCursorTemp = [crsArticoleTemp]
- llSucces = goExecutor.oExecuta(lcSqlCursor, lcCursorTemp)
- IF m.llSucces
- SELECT crsArticole
- APPEND FROM DBF(m.lcCursorTemp)
- ENDIF
- USE IN (SELECT(m.lcCursorTemp))
- ENDIF && m.llCopiere
-```
-
-Pas cu pas:
-
-1. Se executa `pack_facturare.cursor_preturi(...)` intr-un cursor temporar separat, `crsArticoleTemp`
- (nu direct in `crsarticole`).
-2. `SELECT crsArticole` + `APPEND FROM DBF(lcCursorTemp)` — VFP potriveste coloanele **dupa nume**;
- coloanele care exista in `crsArticoleTemp` dar nu in `crsArticole` (sau invers) sunt ignorate
- tacut de `APPEND FROM` (nu da eroare pentru coloane lipsa pe o parte sau alta — completeaza cu
- valoarea implicita a campului pe partea destinatie). Cele doua cursoare au aceeasi structura de
- baza (`creeaza_facturacrs`/coloanele standard `cursor_facturare`), deci in practica maparea e
- completa.
-3. `id_c` din `crsArticoleTemp` (numerotat `ROWNUM` de Oracle, incepand de la 1, independent de
- executia anterioara) se copiaza **ca atare** in `crsArticole` — **nu se renumeroteaza**.
-4. `crsArticoleTemp` se inchide (`USE IN`); rezultatul ramane doar in `crsArticole`, care de acum
- contine doua seturi de randuri provenite din doua interogari Oracle diferite, cu spatii de `id_c`
- care se pot suprapune.
-
-**De ce e sigur aici, dar nu neaparat pe comanda**: aceasta ramura ruleaza **doar** cand
-`m.llCopiere` e adevarat, si cand `llCopiere` e adevarat, cursorul de baza `crsArticole` **nu mai
-vine din `cursor_comanda`** — Do Case-ul de la `ofacturare.prg:266-308` verifica `Case m.llCopiere`
-**primul**, inaintea oricarei ramuri pe `tnTip`, deci pentru copiere cursorul de baza e intotdeauna
-`cursor_retur_document` (documentul copiat insusi), indiferent de tipul original. Un document copiat
-nu (mai) e o "comanda" (`poDate.tip` dupa copiere nu e niciodata `3`), deci nici `do_scrie_factura`
-(care cere `poDate.Tip = 4` sau `Inlist(poDate.Tip,3,21,25,28,42,47)` pentru logica de inchidere
-automata), nici `do_sterge` (aceleasi conditii de tip) nu citesc/scriu `crsarticole` ca registru pe
-calea de copiere — **coliziunea de `id_c` exista tehnic si aici, dar nu are efect observabil**,
-pentru ca nimic nu mai citeste cursorul ca registru pe acest `poDate.tip`. Aplicarea aceleiasi tehnici
-pe un document de tip 3 (unde registrul chiar e citit) ar expune exact coliziunea descrisa in verdict.
-
-## 2. De ce merge azi pe contract si nu pe comanda
-
-**Pe contract, lista de preturi si articolele contractului sunt doua cursoare separate de la bun
-inceput, populate de o singura procedura Oracle cu doua `OUT REF CURSOR`-uri**
-(`PACK_FACTURARE:2646-2950`, `cursor_contract`):
-
-```
-PROCEDURE cursor_contract(..., V_CURSOR OUT cursor_facturare, V_CURSOR2 OUT cursor_facturare) IS
-...
-OPEN V_CURSOR2 FOR
- ...
- SELECT rownum - 10000 as id_c, id_ctr, id_articol, id_rata, ... , opt_facturare
- FROM (... CTR_ARTICOLE OPT_FACTURARE=3 UNION ALL ... CTR_SCADENTAR OPT_FACTURARE IN (1,2) ...)
- ORDER BY data, numar, data_rata, denumire;
-
-pack_facturare.cursor_preturi(V_DATA_CURS, V_TIP, V_ID_VALUTA, V_ID_GESTIUNE_INIT, V_LUNA, V_AN,
- V_ID_UTIL, V_ID_SUCURSALA, V_CURSOR);
-END cursor_contract;
-```
-
-`V_CURSOR` (= `crsarticole`, mapat in VFP) **este** rezultatul unui apel intern la `cursor_preturi` —
-lista de preturi completa, exact ca pe un document liber de tip 1/5/7/10. `V_CURSOR2` (= `crsarticole1`)
-e interogarea proprie contractului, cu `id_c` deliberat decalat cu `-10000` fata de spatiul lui
-`ROWNUM` simplu — dovada directa ca autorii codului au tratat coliziunea de `id_c` intre cele doua
-cursoare ca pe un risc real de evitat, nu ca pe ceva neglijabil.
-
-**Consecinta pentru UI**: pe un document de contract, `grd_articole` (RecordSource `crsarticole`)
-afiseaza azi **lista de preturi**, nu articolele contractului — de aceea capul lui de coloana e deja
-"Cantitate in stoc" si mesajul e deja "Acest articol nu este pe stoc!"
-(`ofacturare.vc2:15129-15143`, citat integral):
-
-```
-Case Inlist(poDate.tip, 2, 6)
- && facturare pe baza de contract
- This.lb_titlu_alb_b121.Caption = [FACTURA PE CTR. ] + Alltrim(poDate.descriere)
- This.grd_articole.RemoveObject('cSerie')
- && articole din lista de preturi
- This.grd_articole.cCantitate.header1.Caption = [Cantitate in stoc]
- This.cmesaj_cantitate = [Acest articol nu este pe stoc!]
-```
-
-`grd_contracte` (RecordSource `crsarticole1`) e gridul secundar, cu articolele/ratele contractului.
-Contractul "are deja lista de preturi" pentru ca **asa e populat de la inceput** — nu exista niciun
-`APPEND`/merge, doar doua interogari separate aratate in doua griduri diferite.
-
-**Confirmarea ca registrul nu se aplica pe contract**: `do_scrie_factura`'s `Do Case`
-(`ofacturare.vc2:14282-14389`) are exact patru ramuri — `poDate.eProforma=1`, `poDate.Tip=4`,
-`Inlist(poDate.Tip,3,21,25,28,42,47)`, `Otherwise`. Tipurile de contract (2,6,26,52) nu apar in
-niciuna din primele trei, deci cad pe `Otherwise` — `pack_facturare.scrie_factura2` se cheama direct,
-**fara** `Select crsarticole / Calculate Sum(cantitate) ...` si fara `pnParametruAditional` derivat
-din vreo suma. Contractul nu are, azi, nicio decizie de "inchidere automata" bazata pe
-`Sum(crsarticole.cantitate)` — deci amestecul de continut din `crsarticole` (lista de preturi) nu are
-cum sa strice o logica ce nu exista pentru acest tip. **Pe comanda, aceeasi ramura a Do Case-ului
-(`Inlist(poDate.Tip,3,21,25,28,42,47)`) exista si citeste exact `crsarticole`**
-(`ofacturare.vc2:14332-14338`, citat in verdict) — de aici diferenta reala.
-
-## 3. Proiectarea adaugarii
-
-**Liniile libere NU intra in `crsarticole`.** Mecanismul recomandat:
-
-1. **Sursa de date**: cursorul filtrat construit de S4 —
- `pack_facturare.cursor_preturi` supraincarcat cu `V_FILTRU_COD`/`V_FILTRU_DEN`
- (`docs\cercetare\s4_cautare_articole_server.md`, punctul 4/9, pasul 1). Nu se cere nimic nou
- in Oracle pentru S4e insusi — se reutilizeaza mecanismul deja proiectat pentru S4 (S4e devine
- inca un consumator al aceluiasi cursor filtrat, nu un cursor nou). "Alege din nomenclator…"
- (S4g, decizia 27/34) e un cursor separat, in afara acestei povesti.
-2. **Legarea in UI**: `APPEND BLANK` direct pe `crsfactura`, urmat de editare inline prin
- `combosql` pe celula de cod/denumire — exact tiparul deja existent, azi, in productie (chiar
- daca in celalalt formular) la `frm_facturare_articole2.But_nou1.do_adauga`
- (`ofacturare.vc2:17118-17122`):
- ```
- PROCEDURE do_adauga
- Select crsFactura
- APPEND BLANK
- this.grd_factura.SetFocus()
- ENDPROC
- ```
- Meniul S4b ("Cauta in lista de preturi…") declanseaza acest gest, cu focus direct pe celula de
- cautare — S4b insusi a documentat aceasta echivalenta (sectiunea 6 a raportului S4b): "aceste
- doua optiuni de meniu ajung la acelasi gest UI".
-3. **`crsfactura.id_c` ramane la valoarea implicita a campului** (`N(20)`, fara `Null`,
- `creeaza_facturacrs`, `COMUN\programe\ofacturare_comun.prg:1775-1785`) — adica `0` la
- `APPEND BLANK`, valoare pe care Oracle nu o produce niciodata pentru `id_c` (`ROWNUM` incepe de
- la 1). Consecinta: `do_sterge`-ul de azi (`For id_c = poArticol.id_c`, vezi sectiunea 4) nu
- gaseste niciodata un rand de potrivit in `crsarticole` pentru o linie libera — comportament
- corect prin constructie, **fara nicio modificare de cod**.
- *Precedent in acelasi fisier, deja in productie*: linia de discount adaugata la finalul
- documentului (`ofacturare.vc2:14531-14537`, `Select crsfactura / Append Blank / Replace
- denumire With Replicate('Z',20), ... , id_temp With 99999`) — nu seteaza `id_c` deloc, foloseste
- deja acelasi tipar de "rand sintetic fara sursa in `crsarticole`".
-4. **`crsfactura.opt_facturare`** (numeric, implicit `0`) ramane la valoarea implicita si pentru o
- linie libera — coincide cu valoarea pe care o are deja o linie normala din lista de preturi
- (`opt_facturare=0` inseamna azi "nu vine din contract", conventia citita de `do_sterge` la
- `ofacturare.vc2:14615-14619`). Nu e nevoie de o valoare noua pe acest camp pentru distinctia
- "libera vs. comanda" — distinctia se face deja prin `id_c` (punctul 3).
-5. **Completarea campurilor de pret/TVA/valuta**: identic cu maparea deja proiectata de S4
- (`s4_cautare_articole_server.md`, punctul 6 — tabelul camp-cu-camp) — S4e nu adauga camp nou,
- preia mecanismul S4 ca atare pentru randul ales din cautarea filtrata.
-
-**Ce ramane de verificat la implementare, nu de presupus**: daca `combosql`-ul legat pe `grd_factura`
-(construit pentru S4) trebuie sa apara pe **toate** coloanele relevante (cod, denumire) ale unei
-linii nou-adaugate prin acest gest, sau doar pe coloana pe care s-a facut click — comportamentul
-exact al `LostFocus`-ului de completare in masa a celorlalte campuri (`s4_cautare_articole_server.md`,
-punctul 5, pasul 4) ramane in perimetrul S4, S4e doar il consuma.
-
-## 4. Stergerea
-
-**(a) O linie venita din comanda** — comportament **neschimbat**, decizia 29 se aplica ca azi:
-`do_sterge` (`ofacturare.vc2:14608-14693`) gaseste `poArticol.opt_facturare = 0` (linie din
-`crsarticole`, comanda), potriveste pe `id_c` (`ofacturare.vc2:14652-14655`,
-`Case (gnScadereStoc = 1 And poDate.tip = 23) Or Inlist(poDate.tip,3,4,21,25,28,42,47) => Select
-crsarticole / Replace cantitate With cantitate + poArticol.cantitate For id_c = poArticol.id_c`),
-reface cantitatea ramasa in `crsarticole`. La `do_scrie_factura`, `Calculate Sum(cantitate)` peste
-`crsarticole` (neschimbat, fara linii libere in el) vede corect cantitatea marita — comanda ramane
-"facturata partial", fara nicio interventie noua. Nicio confirmare, niciun marcaj "refuzat" —
-exact decizia 29.
-
-**(b) O linie libera adaugata** — `poArticol.opt_facturare = 0` (aceeasi valoare ca (a): `0` nu
-distinge intre "din lista de preturi ca supliment pe comanda" si "din lista de preturi ca document
-liber" — nu trebuie sa distinga, pentru ca in ambele cazuri `lcCursor = crsarticole`
-la `ofacturare.vc2:14615-14619`). Executia lui `Replace cantitate With cantitate + poArticol.cantitate
-For id_c = poArticol.id_c` gaseste **zero randuri** in `crsarticole` cu `id_c = 0` (Oracle nu produce
-niciodata `id_c = 0`), deci `REPLACE ... FOR` e un no-op — nimic nu se schimba in registru. Corect: o
-linie libera nu a fost niciodata scazuta din vreun "ramas de facturat", deci nu are ce sa refaca la
-stergere. **Nicio schimbare de cod necesara in `do_sterge` pentru acest caz.**
-
-**Verificare de facut la implementare, nu presupunere**: confirmarea exacta a valorii implicite
-(`0` vs. posibil `.NULL.` daca proprietatile campului se schimba fata de ce arata azi
-`creeaza_facturacrs`) — ambele valori produc acelasi rezultat (`REPLACE ... FOR` fara potrivire),
-dar merita un test explicit inainte de a considera punctul inchis, nu doar citirea definitiei
-campului.
-
-## 5. Capul de coloana si mesajul de cantitate
-
-**Corectie fata de ipoteza initiala a task-ului**: capul de coloana "Cantitate comandata" si mesajul
-"A fost facturata intreaga cantitate comandata pentru acest articol!" (`ofacturare.vc2:15144-15150`)
-apartin lui `grd_articole`/`crsarticole` — gridul care, cu proiectarea din sectiunea 3, **continua sa
-arate exclusiv liniile comenzii** (liniile libere nu intra niciodata acolo). Deci acest cap de coloana
-si acest mesaj **raman corecte, neschimbate**, pentru ca nu se mai aplica vreodata unei linii libere.
-
-**Unde apare totusi problema semnalata de task**: nu in `grd_articole`, ci in **validarea de
-cantitate/stoc a liniei libere insesi**, care trebuie sa arate un mesaj propriu, nu mostenit de la
-`Thisform.cmesaj_cantitate` (proprietate unica per formular, setata o singura data in `Init` dupa
-`poDate.tip` — daca `poDate.tip = 3`, ea contine azi tocmai textul de comanda). Daca validarea unei
-linii libere ar reutiliza `Thisform.cmesaj_cantitate` fara sa o schimbe pe moment, un articol liber
-epuizat din stoc ar afisa gresit "A fost facturata intreaga cantitate comandata" — mesajul cerut
-de plan la punctul de atentie e real, doar localizat gresit initial (nu pe `grd_articole`, ci pe
-mecanismul de validare a liniei libere, vezi sectiunea 6).
-
-**Propunere concreta de text** (romana, de validat cu Marius la implementare):
-- `grd_articole` (comanda), neschimbat: cap coloana **"Cantitate comandata"**, mesaj
- **"A fost facturata intreaga cantitate comandata pentru acest articol!"**.
-- Linie libera (validare separata, sectiunea 6), text propus, calchiat dupa formularea deja
- folosita pe lista de preturi simpla (`ofacturare.vc2:15122-15127`, tipurile 1/5/7/10, unde
- `cmesaj_cantitate` ramane la valoarea implicita a formularului): **"Nu mai exista stoc disponibil
- pentru acest articol!"** — coerent cu formularea deja folosita pe contract
- (`[Acest articol nu este pe stoc!]`, `ofacturare.vc2:15136`), fara sa foloseasca acelasi text
- identic (ca sa nu para o dublare accidentala a mesajului de contract).
-
-## 6. Validarea de cantitate
-
-**Ce se pastreaza neschimbat**: pentru liniile din comanda, alegerea prin `grd_articole` ramane pe
-calea de azi — `do_adauga_articol` -> `do_verifica_articol(tlContract=.F., tnCantitate=poArticol.cantitate)`
-(`ofacturare.vc2:12813-12869`, `:14731-14787`). `poArticol.cantitate` provine din
-`crsarticole.cantitate`, care e "ramas de facturat" (`A.CANTITATE - NVL(D.CANTITATE,0)`,
-`PACK_FACTURARE:3030`) — cererea din plan ("liniile din comanda sa nu-si piarda validarea de
-cantitate") e satisfacuta **prin constructie**: acest drum nu e atins de nimic din proiectarea S4e,
-pentru ca liniile libere nu intra niciodata in `crsarticole` si nu modifica randurile lui.
-
-**Ce nu se poate reutiliza ca atare pentru o linie libera**: `do_verifica_articol` cere un
-`poArticol` scatter-uit dintr-un cursor sursa deja incarcat (`crsarticole`/`crsarticole1`) — o linie
-libera adaugata prin `APPEND BLANK` + `combosql` (sectiunea 3) nu are un asemenea rand sursa. Capacul
-de cantitate pentru un articol gestionabil ales liber trebuie sa vina din **stocul curent al
-articolului**, nu din "ramas de facturat" — informatie pe care randul intors de cautarea filtrata
-(`cursor_preturi` cu `V_FILTRU_COD`/`V_FILTRU_DEN`) o are deja in coloana `cantitate` (aceeasi
-semantica de stoc descrisa in verdict), fara sa fie nevoie de un apel Oracle suplimentar.
-
-**Gol real de proiectare, necesar S4e, neacoperit de niciun raport anterior (S4/S4b)**: nici
-`s4_cautare_articole_server.md`, nici `s4b_bara_butoane_meniu.md` nu descriu un mecanism de validare
-a cantitatii/stocului pentru randul ales prin `combosql` pe `grd_factura` — ambele rapoarte se opresc
-la "randul se completeaza cu valorile din cursorul filtrat" (mapare de campuri), fara sa acopere
-"ce se intampla daca utilizatorul introduce o cantitate mai mare decat stocul". **De proiectat la
-implementare**: fie (a) o verificare in `LostFocus`/`Valid` a celulei de cantitate din `grd_factura`,
-similara ca forma cu `do_verifica_articol` dar alimentata din randul `combosql` (nu din
-`crsarticole`), fie (b) reutilizarea `do_verifica_articol` insasi, cu un `poArticol` construit ad-hoc
-din randul `combosql` in loc de `Scatter` dintr-un cursor — a doua varianta pastreaza un singur loc
-de validare in cod, dar cere ca `do_verifica_articol` sa primeasca `poArticol` ca parametru explicit
-in loc sa citeasca variabila `Private poArticol` deja populata de apelant (schimbare de contract a
-metodei, nu doar de continut). Ambele variante trebuie sa aleaga mesajul din sectiunea 5, nu
-`Thisform.cmesaj_cantitate` motenit din `Init`.
-
-## 7. Aceeasi problema pe alte surse
-
-| Sursa | `crsarticole` = registru citit de `do_scrie_factura`? | `do_sterge` ajusteaza `crsarticole` pe `id_c`? | Concluzie pentru "APPEND FROM literal" |
-|---|---|---|---|
-| **comanda** (3,21,25,28,42,47) | **Da** — `Inlist(poDate.Tip,3,21,25,28,42,47)`, `:14332-14338` | **Da** — aceleasi tipuri, `:14652-14655` | **Nesigur** — subiectul acestui raport; solutia e "linii libere in afara `crsarticole`" (sectiunea 3) |
-| **avize** (4, "factura din avize") | **Da** — `poDate.Tip = 4`, `:14301-14311` | **Da** — `Inlist(poDate.tip,3,4,21,25,28,42,47)` include 4, `:14652-14655` | **Acelasi risc ca pe comanda** — `cursor_avize` are aceeasi semantica "ramas de facturat" (`docs\cercetare\s4_cautare_articole_server.md`, punctul 1.4); solutia din sectiunea 3 se aplica identic |
-| **contract** (2,6,26,52) | **Nu** — tipurile nu apar in `Do Case`-ul din `do_scrie_factura`, cad pe `Otherwise` | Da, dar pe `crsarticole1` (`opt_facturare<>0`), niciodata pe `crsarticole` | **Sigur** — lista de preturi traieste deja intr-un cursor separat (`crsarticole`), fara sa fie citita ca registru; nimic de schimbat |
-| **retur ca document** (8,9,24) | **Nu** — cad pe `Otherwise`, fara `Sum(cantitate)`/`pnParametruAditional` | **Da, partial** — `Inlist(poDate.tip,8,9,24) => Replace cantitate With cantitate - poArticol.cantitate For id_c = poArticol.id_c`, `:14658-14659` (semn opus, urmareste maximul returnabil, nu inchiderea) | **Risc de coliziune `id_c` ramane, dar fara poluarea `Sum`**: o linie libera adaugata literal prin `APPEND FROM` in `crsarticole` pe un document de retur ar putea, la stergere, atinge tacut cantitatea maxima returnabila a unei linii reale (aceeasi problema de `id_c` din verdict, punctul 1) — **de tratat cu aceeasi solutie (linii libere in afara `crsarticole`) si in S4f**, nu doar aici. Decizia 22 (retur fara factura originala e permis) nu schimba aceasta concluzie — priveste alt aspect (mostenirea gestiunii/pretului) |
-| **transfer subunitati** (23, 41) | Nu (cad pe `Otherwise`) | Partial, doar tip 41 (`Case gnScadereStoc = 1 And poDate.tip = 41`, `:14647-14649`, cu semn opus) | In afara perimetrului S4e (surse via `cursor_gestiune`, nu `cursor_comanda`/`cursor_preturi`); acelasi principiu de precautie se aplica daca se cere vreodata "lista de preturi si pe transfer" |
-
-**Concluzie de tabel**: comanda si avize sunt genuin identice ca risc si ca solutie — **orice
-implementare a S4e trebuie sa acopere ambele tipuri de sursa cu acelasi mecanism** ("linii libere in
-afara `crsarticole`"), nu doar comanda cum sugereaza titlul povestii. Contractul ramane cum e azi
-(nimic de schimbat). Returul ca document (S4f) trebuie avertizat explicit sa nu foloseasca reteta
-`APPEND FROM` literal, desi riscul lui e mai mic (fara poluarea sumei de inchidere).
-
-## 8. Pasi de implementare
-
-1. **Extinde meniul S4b cu "Cauta in lista de preturi…" pe comanda/aviz** (deja in tabelul propus de
- S4b, sectiunea 3 a acelui raport) — leaga optiunea de gestul `APPEND BLANK` pe `crsfactura`
- descris in sectiunea 3 de mai sus, nu de un al doilea cursor bulk.
- *Verificabil*: pe un document de tip 3 (comanda) sau 4/21/25/28/42/47 (avize), alegerea optiunii
- adauga un rand gol in `grd_factura` cu focus pe celula de cautare, fara niciun apel catre
- `cursor_comanda`/`cursor_avize` in plus (verificabil in logul `goExecutor`).
-2. **Confirma valoarea implicita a `crsfactura.id_c` la `APPEND BLANK`** (sectiunea 4) — test direct,
- nu citire de definitie. *Verificabil*: dupa `APPEND BLANK` pe un `crsfactura` gol, `id_c` al
- noului rand e o valoare pe care Oracle n-o produce niciodata pentru `id_c` (azi: `0`).
-3. **Adauga validarea de cantitate/stoc pentru linia libera** (sectiunea 6, varianta aleasa la
- implementare) — mesaj propriu, nu `Thisform.cmesaj_cantitate` mostenit.
- *Verificabil*: pe un articol gestionabil cu stoc 0, adaugarea lui ca linie libera pe un document
- de comanda arata mesajul de stoc propus in sectiunea 5, nu mesajul de "cantitate comandata".
-4. **Verifica prin regresie ca `do_sterge`/`do_scrie_factura` raman neatinse** — niciun cod nou in
- aceste doua metode pentru cazul liniei libere (confirmat teoretic in sectiunea 4, dar de validat
- pe date reale). *Verificabil*: pe un document de comanda cu o linie a comenzii si o linie libera
- adaugate, stergerea liniei libere nu modifica `Calculate Sum(cantitate)` peste `crsarticole`;
- stergerea liniei din comanda reface cantitatea ei, neschimbat fata de azi.
-5. **Extinde acelasi mecanism pe avize (tip 4/21/25/28/42/47)** — nu doar comanda (tabelul din
- sectiunea 7). *Verificabil*: identic cu pasul 4, pe un document "factura din avize".
-6. **Avertizeaza explicit S4f (retur ca document)** sa nu foloseasca `APPEND FROM` literal pentru
- lista de preturi pe documentele de retur (8,9,24) — risc de coliziune `id_c` cu maximul returnabil,
- chiar daca fara poluarea sumei de inchidere. Nu e un pas de implementat aici, e o nota de predare
- catre acea poveste (deja referentiata la decizia 22/S4f in plan).
-
-## 9. Ce nu se poate testa headless
-
-- **Comportamentul `combosql`/`APPEND BLANK` in `grd_factura`** — capcana deja confirmata pe acest
- proiect (`grid-coloane-nu-se-materializeaza-headless`): sub `-A -T`, `ColumnCount`/`RecordSource`
- raman artefacte. Verificarea vizuala a mesajului/capul de coloana (sectiunea 5) si a gestului de
- adaugare (sectiunea 3) cere harnessul UI vizibil, nu rulare headless.
-- **`LostFocus`/`Valid` pe celula de cantitate** (sectiunea 6) — daca implementarea alege varianta
- (a) din sectiunea 6 (verificare directa in eveniment de celula), comportamentul depinde de randare
- de grid, deci nu e testabil direct headless; varianta (b) (reutilizare `do_verifica_articol` cu
- `poArticol` construit ad-hoc) **este** apelabila programatic, fara UI, daca semnatura metodei
- primeste parametrul explicit.
-- **`AMESSAGEBOX` la mesajul de stoc** (sectiunea 5) — verificabil ca text literal in cod, nu ca
- aparitie reala pe ecran, din acelasi motiv structural ca oriunde altundeva in suita.
-- **Ce se poate verifica headless, direct**: continutul `crsfactura`/`crsarticole` dupa apeluri
- directe (nu prin click) la `do_sterge`/`do_scrie_factura`/gestul de `APPEND BLANK`, cu date de
- test pregatite manual (un `crsarticole` cu 2-3 randuri de comanda, un `crsfactura` cu o linie de
- comanda si una libera inserate programatic) — confirma `id_c`, `Sum(cantitate)`, si comportamentul
- `REPLACE ... FOR` fara sa deschida formularul.
-
-## 10. Riscuri si decizii ramase lui Marius
-
-1. **Metoda de validare a cantitatii pe linia libera** (sectiunea 6) — varianta (a) sau (b); (b)
- cere schimbarea contractului lui `do_verifica_articol` (parametru nou `poArticol`), (a) dubleaza
- logica de validare in doua locuri diferite ale codului. **Recomandare**: (b), pentru un singur
- loc de intretinut — coerent cu principiul deja aplicat in S4b sectiunea 5 ("echivalenta tot vs.
- alege" tine pe convergenta catre o singura rutina).
-2. **Textul exact al mesajului de stoc pentru linia libera** (sectiunea 5) — propunerea e o
- recomandare, nu o decizie finala; de confirmat impreuna cu textele deja stabilite la S3b
- (punctul marunt `a` din plan, `:524`).
-3. **S4f trebuie avertizat explicit sa nu repete reteta `APPEND FROM`** pentru retur (sectiunea 7,
- pasul 6) — nu e o decizie de luat aici, dar cineva trebuie sa o duca mai departe cand S4f intra
- in lucru, altfel riscul de coliziune `id_c` pe retur se reintroduce pe alta poveste, fara sa mai
- fie legat de acest raport.
-4. **Interactiunea cu S4 punctul 2, in lucru la momentul acestui raport** — proiectarea de aici
- presupune ca liniile libere raman complet in afara oricarui mecanism de registru, indiferent cum
- arata forma lui finala dupa decuplare. Daca punctul 2 decide sa scoata bookkeeping-ul din
- `crsarticole` intr-un cursor nou (cea mai probabila directie, judecand dupa decizia 39), concluzia
- sectiunilor 3-4 de aici ramane valabila fara nicio schimbare — liniile libere nu ating niciun
- cursor de registru, indiferent de numele lui. Daca punctul 2 alege in schimb sa pastreze
- `crsarticole` ca sursa unica dar sa filtreze `Sum(cantitate)`/`do_sterge` printr-un camp nou
- (de exemplu un flag `liber`), acel camp ar trebui setat pe liniile libere **daca** ele ar intra
- totusi in `crsarticole` — proiectare pe care acest raport o considera inutila (liniile libere nu
- trebuie sa intre acolo deloc), dar merita re-confirmat cu punctul 2 cand acel raport se incheie,
- ca sa nu ramana doua solutii partial suprapuse pentru aceeasi problema.
-5. **Nu s-a masurat, doar dedus din forma interogarii** (decizia 31 a planului, aplicata si aici):
- nimic din acest raport se sprijina pe volume de date masurate — toate concluziile despre `id_c`/
- `Sum(cantitate)` vin din citirea directa a SQL-ului si a codului VFP, nu din executii de test.
-
-## Handoff
-
-Cercetare incheiata, fara nicio problema de context intalnita in aceasta runda — nu a fost necesara
-predarea. Toate cele zece sectiuni cerute de brief sunt completate mai sus, cu `fisier:linie`
-verificat direct pe fisierele text reale (nu `.bak`) si pe SQL-ul exportat curent
-(`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`). Nicio editare
-de cod, niciun `git_sync.ps1`/`txt2vcx.ps1`, niciun commit, nicio scriere pe Oracle.
-
-**Corectie fata de premisa initiala a task-ului**, de retinut explicit pentru cine citeste doar
-rezumatul: reteta citata in decizia 16 (`APPEND FROM`, `ofacturare.prg:454-473`) **nu** trebuie
-generalizata literal pe comanda — e sigura doar in contextul ei actual (copiere, fara registru activ
-pe cursorul respectiv). Solutia corecta, verificata ca fezabila si ca deja partial sprijinita de
-mecanisme existente (S4's `cursor_preturi` filtrat, `APPEND BLANK`-ul din `frm_facturare_articole2`,
-valoarea implicita `0` a lui `id_c`), e ca liniile libere sa **nu intre niciodata in `crsarticole`**
-— exact ipoteza pe care brief-ul o semnala ca posibila si cerea sa fie confirmata sau infirmata pe
-cod, nu presupusa.
diff --git a/docs/cercetare/s4f_retur_formular_unificat.md b/docs/cercetare/s4f_retur_formular_unificat.md
deleted file mode 100644
index 620a63f..0000000
--- a/docs/cercetare/s4f_retur_formular_unificat.md
+++ /dev/null
@@ -1,727 +0,0 @@
-# S4f — Returul in formularul unificat
-
-Proiectare pe cod, READ-ONLY (fara editari, fara `git_sync.ps1`/`txt2vcx.ps1`, fara commit, fara
-scriere Oracle — doar `SELECT`), pentru povestea **S4f** din
-`docs\plan_13_unificare_formular_facturare.md:2287-2330` (decizia 17, proiectata in sectiunea N,
-`:1574-1655`). Nu s-a atins `COMUN\clase\ofacturare_comun.vc2` si
-`COMUN\programe\ofacturare_editare.prg` — doar citite, cand au aparut in cautari.
-
-Surse de adevar deja stabilite, citate nu reinvestigate: `docs\cercetare\legatura_linie_retur.md`,
-`docs\cercetare\factura_retur_document.md`, `docs\cercetare\retur_si_lista_preturi.md`,
-`docs\cercetare\s4b_bara_butoane_meniu.md`.
-
-## Verdict (esenta, 10 randuri)
-
-**Corectat dupa avertismentul S4e** (`docs\cercetare\s4e_lista_preturi_pe_sursa.md`, sectiunile 3 si
-7): mecanismul `APPEND FROM` din decizia 16 (`ofacturare.prg:454-473`) **e respins pentru orice
-cursor care serveste si drept registru citit de `do_sterge`**, `crsarticole` fiind exact acel cursor
-pe documentele de retur (`Inlist(poDate.tip,8,9,24) => Replace cantitate With cantitate -
-poArticol.cantitate For id_c = poArticol.id_c`, `ofacturare.vc2:14658-14659`) — riscul e coliziune de
-`id_c` intre `cursor_retur_document` si `cursor_preturi`, ambele numerotate `ROWNUM` independent.
-Sectiunea 5 de mai jos e rescrisa pe solutia validata de S4e: **liniile libere nu intra deloc in
-`crsarticole`**, se adauga direct in `crsfactura` prin `APPEND BLANK` + `combosql` (tiparul deja in
-productie la `frm_facturare_articole2.But_nou1.do_adauga`), iar campul de distinctie e
-**`crsfactura.id_c`** (`0` implicit pe o linie libera, valoare pe care Oracle n-o produce niciodata
-pentru `id_c`), nu o coloana lipsa in `crsarticole`.
-
-Partea grea nu e ce parea: N.1 (documentul de retur, tip 8/9/24) merge deja cap-coada — alegere
-multipla de facturi, populare din `cursor_retur`, gestiune si pret de achizitie mostenite, stergere
-si retur partial. Munca reala e in trei bucati inguste. **(1) Nu se muta dialogul de alegere a
-facturilor** in bara de butoane a gridului — s-a verificat pe cod ca alegerea ramane la nivelul
-antetului (sectiunea pliata), exact cum recomanda deja `s4b_bara_butoane_meniu.md` §9.3/tabelul
-"puncte marunte", randul h; ce se muta in meniul "Adauga articole" e **rezultatul** alegerii (liniile
-deja aduse), ca "Adauga tot din facturile alese" / "Alege liniile de returnat…", simetric cu
-comanda/contract/avize. **(2)** Ridicarea lui `But_retur` la nivel de document e cod nou real, nu o
-mutare de buton — azi alegerea e per-articol si niciodata scrisa ca legatura persistata.
-**(3)** Liniile libere pe retur folosesc reteta S4e ("`APPEND BLANK` pe `crsfactura`, niciodata pe
-`crsarticole`"), **plus** un gol nou de proiectat, gasit in aceasta sesiune si necunoscut de S4e (care
-nu are dialog de gestiune pe comanda/avize): mecanismul de alegere a gestiunii
-(`frm_articol_gest_factura`, `.lRetur=.T.`) **suprascrie pretul de vanzare cu pretul din stoc**
-(`ofacturare.vc2:4094-4103`) — corect pentru o linie mostenita dintr-o factura sursa, dar gresit
-pentru o linie libera, a carei pret de vanzare trebuie sa vina din lista de preturi (decizia 16), nu
-din costul de stoc; in plus, acel dialog se intra azi doar dintr-un `poArticol` scatter-uit din
-`crsarticole` (`do_adauga_articol`/`do_alege_stoc`), pe care o linie libera din `crsfactura` nu-l are
-— e nevoie de un punct de intrare nou in dialog, nu doar de reparat pretul. Vezi sectiunea 5 si
-riscurile R1/R7.
-
----
-
-## 1. Inventarul celor doua cai de retur de azi
-
-### 1.1 N.1 — factura de retur ca document (tip 8, 9, aviz 24)
-
-| Pas | Ce face | `fisier:linie` |
-|---|---|---|
-| Intrare | Tile `Page2.Cw1` -> `politica.mpr` -> `factureaza(8)`/`factureaza(9)` din meniul shortcut | `COMUN\clase\ofundal_facturare.vc2:882-884`, `Meniuri\politica.mn2:14-15,45-46` |
-| Antet | `nIdTipDoc=5`, formular `frm_date_factura`, aviz retur (24) foloseste `frm_date_aviz` cu `nIdTipDoc=6` | `COMUN\programe\ofacturare.prg:192-196,222-226` |
-| Alegere facturi sursa | `frm_date_factura.do_cauta_facturi` -> `caut_facturi_multiple_client(id_client, in_valuta, id_valuta, .T.)` -> `cauta_alfa(..., tnTipReturn=1)`, selectie multipla, exclude tipurile de retur din sursa | `COMUN\clase\ofacturare.vc2:9173-9212`; `COMUN\programe\oproceduri_facturare.prg:2091-2121` |
-| Validare obligatorie | Fara alegere, antetul nu se poate inchide (`inainte_de_do_termin`) | `ofacturare.vc2:9523-9526` |
-| Populare linii | `pack_facturare.cursor_retur(V_IN_VALUTA,V_LISTAID,V_ID_UTIL)` -> `cursor_retur_document(...,V_COPIERE=0,...)`, `SELECT` direct din `VANZARI_DETALII`, filtrat pe `ID_VANZARE IN (V_LISTAID)` | `ofacturare.prg:306-307`; `ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:3943-3956,3958-4071` |
-| Gestiune + pret achizitie | `ID_GESTIUNE`/`PRET_ACHIZITIE` copiate neschimbate din linia originala; `GESTIONABIL = NVL2(A1.ID_GESTIUNE,1,0)` | `ff_...sql:4034-4035,4055-4056,4048` |
-| Stergere linie | Permisa, cantitatea reintra in cursorul sursa | `ofacturare.vc2:14608-14693`, ramura `:14658-14659` |
-| Retur partial | Permis, validat fata de maximul = `CANTITATE` a liniei originale, fara agregare cu retururi anterioare | `ofacturare.vc2:14743-14754`, `ff_...sql:4036` |
-| Adaugare libera | **Nu se poate azi** — `do_adauga_articol` ia articolul mereu din `crsarticole`, care pe tip 8/9/24 **este** rezultatul lui `cursor_retur` | `ofacturare.vc2:12843-12851` |
-
-### 1.2 N.2 — `But_retur` per-articol, in factura normala (tip 1, 5, 7, 10)
-
-| Pas | Ce face | `fisier:linie` |
-|---|---|---|
-| Vizibilitate | Doar pe tip 1/5/7/10; pe documentele de retur (8/9/24) butonul nu exista in UI | `ofacturare.vc2:15122-15127` |
-| Declansare | `caction=do_retur` -> `do_adauga_articol(.F.,.F.,.T.)` | `cmd_butoane.vc2:324-338`; `ofacturare.vc2:13963-13965` |
-| Alegere factura sursa | **Per articol**, la fiecare adaugare: `caut_facturi_multiple_client_articol(id_client,in_valuta,id_valuta,.F.,id_articol)` -> `cauta_alfa` cu titlu simplu "Alegeti factura" (nu selectie multipla) | `oproceduri_facturare.prg:2124-2159` |
-| Acumulare | `thisform.cListaIdArticoleRetur` acumuleaza CSV de perechi `id_articol:id_vanzare`, cate una per articol adaugat; `poDate.listaid` e folosit **transient** (salvat in `lnListaIdOld` si restaurat imediat dupa) doar cat dureaza dialogul per-articol | `ofacturare.vc2:12882-12892` |
-| Gestiune | **Se alege**, nu se mosteneste — `pack_facturare.cursor_gestiuni_articol_retur`, prin `do_alege_stoc(...,tlRetur=.T.)` -> `frm_articol_gest_factura` | `ofacturare.vc2:13230,13353-13385` |
-| Pret | **Suprascris cu pretul din stoc** (`pretv`), nu cel din lista de preturi — vezi sectiunea 5 | `ofacturare.vc2:4094-4103` |
-| Semn cantitate | Explicit `poArticol.cantitate = (-1) * cantitate` cand `Thisform.lRetur` | `ofacturare.vc2:4103` |
-| Trimitere Oracle | `poDate.listaid = thisform.cListaIdArticoleRetur` la scriere finala | `ofacturare.vc2:13977-13979` |
-| Legatura persistata | **Nicio legatura scrisa** — `listaid` e folosit doar ca filtru in calculul de disponibil pe rulaj (`RUL`), nu scrie nimic in `VANZARI_CORESP` sau pe linia noua | `ff_...sql:8142-8212` |
-
-### 1.3 Ce au in comun si unde diverg
-
-Comun: excluderea returului dintr-un retur (acelasi filtru `tip in (1,2,3,4,5,6,10,-1,-2,-3,-4,-11)`
-in ambele functii de cautare), conventia de semn negativ pe cantitate, `frm_articol_gest_factura`
-ca formular de alegere a gestiunii pentru linia gestionabila.
-
-Diverg pe tot restul: N.1 alege facturile **o singura data, la nivel de document, inainte** ca
-articolele sa existe; N.2 alege **per articol, in orice moment**, fara limita de cate ori. N.1
-mosteneste gestiune+pret_achizitie fara alegere; N.2 le cere explicit. N.1 scrie
-`VANZARI_CORESP(TIP=3)`; N.2 nu scrie nimic persistat. Zero cod comun intre cele doua cai —
-`ofacturare.vc2:12813-12900` (N.2, `do_adauga_articol`) si `ofacturare.prg:306-311` (N.1,
-`cursor_retur`) nu se ating.
-
----
-
-## 2. `do_cauta_facturi` / `cauta_alfa(..., tnTipReturn=1)` — contractul exact
-
-### 2.1 Cine il cheama si cand
-
-Pe `frm_date_factura` exista un control generic de cautare, `Ct_clb_altele` (clasa
-`ct_clb_cautare`), a carui iconita de lupa e legata de `cprocedura = thisform.do_cauta_altele`
-(`ofacturare.vc2:8721-8729`). `do_cauta_altele` e un dispecer pe `nid_tip`:
-
-```
-Case Inlist(Thisform.nid_tip,8,9)
- Thisform.do_cauta_facturi()
-```
-(`ofacturare.vc2:8953-8954`)
-
-**Secventa confirmata pe cod** (`factureaza()`, `ofacturare.prg:187-311`): `frm_date_factura` se
-creeaza si se afiseaza (`.Show()`, `:230-235`) **inainte** ca `Do Case tnTip` de la `:266-308` sa
-ruleze `cursor_retur`, si mult inainte ca `lcObject = [frm_facturare_articole]` sa fie ales
-(`:395`). Executia continua abia dupa ce `ofrmceredate` (antetul) se elibereaza (`:248`), iar
-`pnButon` (setat la inchiderea antetului) e verificat imediat dupa. Deci **azi dialogul de alegere
-a facturilor ruleaza pe formularul de antet, complet inainte ca formularul de articole sa existe** —
-`crsarticole` se incarca o singura data, cu `poDate.listaid` deja fixat.
-
-Control observat, semnificativ pentru sectiunea 3: `Ct_clb_altele` are
-`cconditie = EMPTY(NVL(poDate.listaid,''))` (`ofacturare.vc2:8722`) — sugereaza ca iconita de
-cautare e activa doar cat timp nimic nu a fost inca ales; **neverificat** insa exact ce proprietate
-citeste `cconditie` (clasa `ct_clb_cautare` nu a fost gasita in text in acest repo, posibil intr-un
-`.vcx` neconvertit sau in `COMUNROA`), deci nu se poate confirma daca astazi re-alegerea e blocata
-explicit sau doar descurajata vizual. De tratat ca ipoteza, nu ca fapt confirmat.
-
-### 2.2 Contractul functiei
-
-`caut_facturi_multiple_client(tnIdPart, tnInValuta, tnIdValuta, tlFacturiMultiple)`
-(`oproceduri_facturare.prg:2091-2121`):
-- **Intrare**: client (obligatoriu — dialogul nu porneste fara el), valuta (doar daca `tnInValuta`),
- `tlFacturiMultiple=.T.` la acest apel -> `lnTipReturn=1` in `cauta_alfa`.
-- **Sursa**: `select serie_act,numar_act,data_act,dataora,id_vanzare from fact_vfacturi where
- sters=0 and tip in (1,2,3,4,5,6,10,-1,-2,-3,-4,-11) [+ conditie sucursala] [+ client] [+ valuta]`
- — fara filtru SQL pe perioada/serie (filtrarea pe acele coloane e comportament generic al
- `cauta_alfa`, nu parametru dedicat).
-- **Iesire**: XML cu randurile bifate (`ales=1`), convertit local prin `Xmltocursor(...,
- "crsFacturiTemp")`; **nimic nu ajunge la Oracle in acest pas**.
-- **Populare aditiva a rezultatului in VFP**: `poDate.listaid = cursor2lista("crsFacturiTemp",
- "id_vanzare", ",")` — **inlocuieste** intreg continutul (`=`, nu `+=`); daca dialogul se apeleaza a
- doua oara azi, a doua rulare suprascrie complet prima (dar azi asta nu se intampla niciodata pentru
- ca dialogul ruleaza o singura data, inainte de orice alta actiune pe document — vezi 2.1).
-- **`cauta_alfa(...,tnTipReturn=1)`** (`COMUN\programe\cauta_alfa.prg:16-260`, mecanismul generic
- folosit peste tot in suita): adauga singur coloana `ales` (`cauta_alfa.prg:124`), titlu explicit
- "Alegeti ... (mouse-click pe numar sau apasati SPACE)", filtrare interactiva pe coloanele afisate.
- Nu are mecanism de dezactivare a unei optiuni individuale, nici submeniu — doar bifare/debifare.
-
-### 2.3 Varianta per-articol
-
-`caut_facturi_multiple_client_articol(tnIdPart, tnInValuta, tnIdValuta, tlFacturiMultiple, tnIdArticol)`
-(`oproceduri_facturare.prg:2124-2159`) — **aceeasi functie de baza**, cu doua diferente: filtru
-suplimentar `b.id_articol = ?pnIdArticol` (join pe `vanzari_detalii`) si `tlFacturiMultiple=.F.` la
-apelul din `do_adauga_articol` (`:12884`), deci `lnTipReturn=0` -> selectie **simpla**, nu multipla.
-Titlu simplu "Alegeti factura". Rezultatul e un obiect cu un singur `id_vanzare`, nu un cursor.
-
----
-
-## 3. Proiectarea punctului 1 — alegerea facturilor sursa ca sursa in meniul de adaugare
-
-**Ce NU se schimba**: alegerea propriu-zisa a facturilor sursa (dialogul cu bifare multipla) ramane
-la nivelul antetului — in formularul unificat, sectiunea pliata (decizia 7). Verificat impotriva
-tabelului "puncte marunte" din plan (`plan_13...md`, randul h): *„Alege facturile de returnat…"
-ramane doar la antet in etapa I; mutarea (in bara de butoane) e o poveste separata* — si confirmat
-independent de tabelul de meniu al lui `s4b_bara_butoane_meniu.md` §3: pe randul "retur (8,9,24)",
-meniul "Adauga articole" propus contine **"Adauga tot din facturile alese" · "Alege liniile de
-returnat…" · "Cauta in lista de preturi…" · "Alege din nomenclator…"** — nu si "Alege facturile de
-returnat…". **Punctul 1 al lui S4f nu contrazice asta**: ce se muta in meniul de adaugare e
-rezultatul alegerii deja facute la antet (liniile din facturile alese), simetric cu comanda/
-contract/avize, nu dialogul de alegere a facturilor insusi.
-
-**Ce SE schimba, si e proiectarea reala**: azi secventa e rigida — antet modal -> `cursor_retur` ->
-formular de articole (sectiunea 2.1). In formularul unificat exista un singur formular, mereu
-deschis; sectiunea de antet (pliata) si gridul de articole coexista. Trei consecinte de proiectat:
-
-1. **Cand se declanseaza `cursor_retur_document`?** Nu mai poate fi legat de "inchiderea antetului"
- (nu mai exista acel eveniment). Trebuie legat de **confirmarea dialogului de alegere** (butonul de
- cautare din sectiunea pliata, echivalentul lui `Ct_clb_altele`/`do_cauta_facturi`): imediat ce
- utilizatorul bifeaza facturile si confirma, `poDate.listaid` se seteaza si `cursor_retur_document`
- ruleaza pe loc, populand/repopuland `crsarticole`. Documentul poate porni cu tipul deja pe 8/9/24
- (ales din combo-ul de tip document) inainte ca vreo factura sa fie aleasa — grid-ul de articole
- ramane gol pana la prima alegere, exact ca azi cand `Reccount(crsarticole)=0` da mesajul "Nu exista
- articole pentru optiunile alese!" (`ofacturare.prg:325`).
-2. **Poate opera la orice moment, nu doar o data.** Spre deosebire de azi (dialogul ruleaza o singura
- data, inainte ca gridul sa existe), in formularul unificat butonul din sectiunea pliata e
- apasabil oricand documentul e deschis. Trebuie decis explicit comportamentul la a doua apasare —
- vezi punctul urmator.
-3. **Alegere aditiva sau inlocuitoare, la a doua apasare.** Azi `poDate.listaid = ...` **inlocuieste**
- (nu `+=`), dar azi nu conteaza pentru ca nu se poate apasa a doua oara dupa ce gridul exista. In
- formularul unificat, daca utilizatorul a ales deja factura A, a adaugat cateva linii din ea in
- `crsfactura`, si apoi vrea sa adauge si din factura B, doua variante:
- - **(a) Inlocuire** — a doua alegere reseteaza `poDate.listaid`/`crsarticole` la noul set ales;
- liniile deja mutate in `crsfactura` raman (crsfactura e independent de crsarticole dupa mutare),
- dar orice linie inca needitata din factura A dispare din `crsarticole` fara avertisment. Simplu
- de implementat (identic cu azi), dar surprinzator pentru operator.
- - **(b) Aditiv** — a doua alegere **extinde** `poDate.listaid` cu facturile noi (evitand
- duplicate) si ruleaza `cursor_retur_document` filtrat doar pe facturile noi, cu
- `INSERT INTO crsarticole` (nu `SELECT INTO`), exact reteta deja propusa de
- `s4b_bara_butoane_meniu.md` §9.3, optiunea 2 — cere cod VFP nou (bucla de filtrare +
- `INSERT`), dar zero cod nou in `pack_facturare` (aceeasi procedura, apelata de mai multe ori).
- Consistent cu filozofia deciziei 16 ("sursa umple documentul, nu il inchide").
-
- **Recomandare**: varianta (b), aditiv — e coerenta cu tratamentul lista-de-preturi (S4e) si cu
- comanda/contract (unde alegerea suplimentara nu sterge ce exista deja), si evita pierderea tacuta
- de linii needitate. **Ramane decizie de confirmat de Marius** — nici plan-ul, nici
- `s4b_bara_butoane_meniu.md` nu au tranzat-o explicit (§9.5, punctul 2 acolo o listeaza tot ca
- deschisa).
-
-**Consecinta pentru validarea de antet**: garda de azi (`inainte_de_do_termin`, `descriere` obligatoriu
-pentru tip 8/9, `ofacturare.vc2:9523-9526`) nu mai are un moment natural "inainte de a inchide
-antetul" — se muta la garda echivalenta din `Termina` (aceeasi verificare, alt declansator).
-
----
-
-## 4. Proiectarea punctului 2 — ridicarea `But_retur` la nivel de document
-
-**Ce se pastreaza din calea per-articol**: alegerea gestiunii ramane per-articol, prin
-`cursor_gestiuni_articol_retur` si `frm_articol_gest_factura` — decizia 22/N.3 spune explicit ca
-gestiunea si pretul de achizitie **se aleg**, nu se mostenesc, pentru orice linie fara factura
-sursa unica precisa (si N.2 nu are niciodata o factura "sursa unica a documentului", are cel mult
-factura aleasa pentru articolul curent). Punctul 2 nu schimba asta.
-
-**Ce se schimba**: alegerea facturii sursa nu mai e per-articol (un dialog `cauta_alfa` cu selectie
-simpla la fiecare `do_retur`), ci **la nivel de document**, dupa modelul N.1 — un singur dialog cu
-selectie multipla (`caut_facturi_multiple_client`, acelasi ca la N.1, dar filtrat pe articolul
-curent doar daca ramane necesar; de decis daca filtrul pe articol dispare complet odata cu ridicarea
-la document). Consecinta directa: `poDate.listaid` (sau un camp nou, vezi mai jos) ar fi populat o
-singura data pentru intreg documentul, nu reconstruit per articol prin `caut_facturi_multiple_client_articol`.
-
-**Capcana de proiectare, gasita pe cod**: `poDate.listaid` e deja **partajat** intre N.1 si N.2 azi —
-N.2 il suprascrie transient (`lnListaIdOld = poDate.listaid` ... `poDate.listaid = m.lnListaIdOld`,
-`ofacturare.vc2:12882,12892`) doar cat dureaza alegerea per-articol, apoi il restaureaza. Daca N.2
-ridicat la document incepe sa scrie **permanent** in `poDate.listaid` (ca N.1), cele doua mecanisme
-intra in conflict pe acelasi camp — un document normal (tip 1/5/7/10) cu retur ridicat la nivel de
-document ar avea `poDate.listaid` populat cu facturile de retur alese, camp care pe alte tipuri
-(comanda/contract/avize) e deja folosit cu alt sens (id-uri de comanda/contract/aviz sursa, vezi
-`ofacturare.prg:266-308`). **Nu e conflict pe tip 1/5/7/10** — acele tipuri nu folosesc azi
-`poDate.listaid` pentru altceva (sunt populate cu `cursor_preturi`, care nu ia `V_LISTAID` ca
-parametru) — deci reutilizarea e sigura tehnic, dar merita un camp cu nume propriu
-(`poDate.listaid_retur` sau similar) ca sa nu se ambiguizeze semantic ce inseamna `listaid` pe un
-document normal. **De decis la implementare**, nu blocant.
-
-**Ce arata in bara de butoane / meniu (S4b)**: tabelul din `s4b_bara_butoane_meniu.md` §3 nu are
-azi un rand pentru "retur intr-o factura normala" — doar pentru documentele de retur propriu-zise
-(8,9,24). Ridicarea lui N.2 la nivel de document introduce o optiune noua in meniul "Adauga
-articole" **pentru tipurile 1,5,7,10**: "Retur de articole…" (deja anticipata in tabelul §3 al
-raportului S4b, coloana lista de preturi: "Cauta in lista de preturi… · Alege din nomenclator… ·
-**Retur de articole…**"). Aceasta optiune deschide dialogul de alegere multipla la nivel de document
-(prima data), apoi pe alegerile ulterioare acelasi comportament aditiv/inlocuitor discutat la
-sectiunea 3 se aplica identic.
-
-**Ce dispare**: `caut_facturi_multiple_client_articol` (filtrul per-articol) ramane cod mort daca
-alegerea trece integral la nivel de document — sau se pastreaza ca alegere secundara optionala
-("mai am nevoie de o factura sursa doar pentru articolul X", nefolosita azi in acest scenariu). Nu
-e clar din decizia 17/N.3 daca trebuie eliminata explicit sau doar nu mai e calea principala — **de
-decis de Marius** (risc R3).
-
----
-
-## 5. Proiectarea punctului 3 — liniile libere pe document de retur
-
-**Corectie fata de premisa initiala a brief-ului** ("prin acelasi `APPEND FROM` ca la S4e"): S4e a
-gasit ca reteta literala a deciziei 16 (`ofacturare.prg:454-473`) **nu e sigura** pe niciun tip unde
-`crsarticole` e citit ca registru de `do_sterge`/`do_scrie_factura`, si a documentat asta explicit
-pentru retur, in tabelul sau de la §7:
-
-> "**retur ca document (8,9,24)** | `crsarticole` = registru citit de `do_scrie_factura`? **Nu** —
-> cad pe `Otherwise`, fara `Sum(cantitate)`/`pnParametruAditional` | `do_sterge` ajusteaza
-> `crsarticole` pe `id_c`? **Da, partial** — `Inlist(poDate.tip,8,9,24) => Replace cantitate With
-> cantitate - poArticol.cantitate For id_c = poArticol.id_c` (`:14658-14659`, semn opus, urmareste
-> maximul returnabil, nu inchiderea) | Concluzie: **risc de coliziune `id_c` ramane, dar fara
-> poluarea `Sum`**: o linie libera adaugata literal prin `APPEND FROM` in `crsarticole` pe un
-> document de retur ar putea, la stergere, atinge tacut cantitatea maxima returnabila a unei linii
-> reale — de tratat cu aceeasi solutie (linii libere in afara `crsarticole`) si in S4f."
-> (`s4e_lista_preturi_pe_sursa.md`, §7, randul "retur ca document")
-
-Solutia S4e (verificata acolo pe comanda/avize) se aplica identic aici — sectiunile de mai jos sunt
-rescrise pe ea, nu pe `APPEND FROM`.
-
-### 5.1 Mecanismul corect: `APPEND BLANK` pe `crsfactura`, niciodata pe `crsarticole`
-
-**Liniile libere nu intra in `crsarticole`.** Se adauga direct in `crsfactura`, prin acelasi gest deja
-in productie la `frm_facturare_articole2.But_nou1.do_adauga` (`ofacturare.vc2:17118-17122`):
-
-```
-PROCEDURE do_adauga
- Select crsFactura
- APPEND BLANK
- this.grd_factura.SetFocus()
-ENDPROC
-```
-
-urmat de editare inline prin `combosql` pe celula de cod/denumire (mecanismul construit de S4/S4e
-pentru cautarea filtrata pe server, `pack_facturare.cursor_preturi` cu `V_FILTRU_COD`/`V_FILTRU_DEN`).
-Optiunea de meniu "Cauta in lista de preturi…" (deja in tabelul S4b §3, pe randul retur) declanseaza
-exact acest gest — **nu** un `cursor_retur_document` suplimentar si **nu** un `APPEND FROM` peste
-`crsarticole`.
-
-### 5.2 Cum se distinge o linie libera de una din factura sursa
-
-**Campul corect e `crsfactura.id_c`, nu o coloana pe `crsarticole`.** O linie mostenita ajunge in
-`crsfactura` prin `do_adauga_articol`, care face `Select (lcCursor) / Scatter Name poArticol` pe
-randul ales din `crsarticole` (populat de `cursor_retur_document`, cu `id_c = ROWNUM`, pornind de la
-1) si copiaza acel `id_c` in randul nou din `crsfactura`. O linie libera, adaugata prin `APPEND BLANK`
-direct pe `crsfactura` (5.1), **nu trece niciodata prin acest `Scatter`** — `id_c` ramane la valoarea
-implicita a campului (`N(20)`, fara `Null`, deci `0`, `creeaza_facturacrs`,
-`COMUN\programe\ofacturare_comun.prg:1775-1785`, citat si verificat de S4e §3 punctul 3). **Oracle nu
-produce niciodata `id_c = 0`** (`ROWNUM` incepe la 1) — deci `crsfactura.id_c = 0` e semnalul curat,
-fara camp nou, care distinge o linie libera de una mostenita. Acelasi tipar e deja in productie pentru
-linia de discount (`ofacturare.vc2:14531-14537`, `Append Blank` fara `id_c` setat).
-
-**Consecinta directa, fara cod suplimentar**: `do_sterge`, ramura de retur
-(`Case Inlist(poDate.tip,8,9,24) => Select crsarticole / Replace cantitate With cantitate -
-poArticol.cantitate For id_c = poArticol.id_c`, `ofacturare.vc2:14658-14659`) cauta in `crsarticole`
-un rand cu `id_c = poArticol.id_c`. Pentru o linie libera, `poArticol.id_c = 0`, iar `crsarticole` nu
-are niciodata un rand cu acel `id_c` — `REPLACE ... FOR` devine **no-op prin constructie**. Stergerea
-unei linii libere de pe un document de retur **nu atinge** maximul returnabil al nici unei linii
-mostenite — exact ce cerea brief-ul la punctul 5, si exact acelasi mecanism (nu doar aceeasi idee) ca
-solutia S4e pentru comanda.
-
-### 5.3 Pretul de vanzare — riscul gasit (R1, ramane valabil)
-
-**Nu e doar despre gestiune/pret de achizitie, si nu se rezolva prin mutarea in `crsfactura`.** Cand
-o linie ajunge la `do_alege_stoc` cu `Inlist(poDate.tip,8,9,24)` adevarat (orice linie pe un document
-de retur, indiferent de origine — conditia e pe `poDate.tip`, nu pe un flag de linie), se deschide
-`frm_articol_gest_factura`. In acel formular, la schimbarea coloanei de gestiune
-(`grd_gestiuni.RowColChange`), daca `Thisform.lRetur` e adevarat:
-
-```
-If Thisform.lRetur
- poArticol.pretftva = pretv && pret DIN STOC, nu din lista de preturi
- ...
- poArticol.cantitate = (-1) * cantitate
-Endif
-```
-(`ofacturare.vc2:4094-4103`)
-
-Pentru o linie **mostenita** (N.1), asta e corect prin constructie — returnezi marfa la pretul cu
-care a fost vanduta. Pentru o linie **libera** (decizia 22 — articol niciodata vandut clientului, deci
-fara "pret de retur" de mostenit), suprascrierea cu pretul de stoc e o **eroare de pret**: linia
-libera ar iesi cu costul de stoc in loc de pretul din lista de preturi ales prin `combosql` la 5.1.
-
-**Solutie propusa, actualizata**: `frm_articol_gest_factura` primeste un al doilea semnal, distinct de
-`tlRetur` ("esti pe flux de retur"), care sa insemne "aceasta linie are factura sursa" — derivat acum
-din `crsfactura.id_c <> 0` (5.2), nu dintr-o coloana lipsa in `crsarticole`. Ramura de suprascriere
-pret (`:4094-4103`) se activeaza doar cand acest al doilea semnal e adevarat.
-
-### 5.4 Golul nou, nu tratat de S4e: punctul de intrare in dialogul de gestiune
-
-**S4e nu are acest gol pentru ca nu are dialog de gestiune pe comanda/avize** — liniile libere de
-acolo se completeaza integral prin `combosql` (pret, TVA, valuta) fara sa mai treaca prin niciun
-dialog de alegere a gestiunii. Pe retur, decizia 22 cere explicit ca gestiunea si pretul de achizitie
-sa **se aleaga** pentru o linie libera — mecanismul care stie sa faca asta e
-`cursor_gestiuni_articol_retur` + `frm_articol_gest_factura`, dar acel dialog se intra azi **doar**
-din `do_alege_stoc`, apelat de `do_adauga_articol` pe baza unui `poArticol` scatter-uit dintr-un rand
-**deja incarcat in `crsarticole`** (`ofacturare.vc2:12843-12851,12891`). O linie libera adaugata prin
-`APPEND BLANK` pe `crsfactura` (5.1) **nu are** un asemenea rand sursa — exact acelasi gol pe care
-S4e l-a semnalat, netratat, pentru validarea de cantitate pe comanda (`s4e_lista_preturi_pe_sursa.md`
-§6: *"`do_verifica_articol` cere un `poArticol` scatter-uit dintr-un cursor sursa deja incarcat... o
-linie libera... nu are un asemenea rand sursa"*).
-
-**Consecinta pentru S4f, mai stricta decat pe comanda**: pe comanda/avize (S4e), lipsa unui `poArticol`
-de sursa afecteaza doar validarea de cantitate (un gol de acoperit, dar linia se poate scrie si fara
-gestiune aleasa — comanda/avize nu cer gestiune diferita de cea din lista de preturi). Pe retur, lipsa
-aceluiasi `poArticol` blocheaza **si** alegerea gestiunii, care e obligatorie prin decizia 22. Trebuie
-proiectat un punct de intrare nou in `frm_articol_gest_factura`/`do_alege_stoc`, care sa porneasca de
-la randul **deja inserat in `crsfactura`** (dupa `combosql`, cu `id_articol` si cantitate deja
-completate) in loc de la un rand din `crsarticole` — practic o a doua cale de apel, cu acelasi dialog
-la capat, dar `poArticol` construit ad-hoc din `crsfactura` in loc de `Scatter` din `crsarticole`.
-Aceeasi problema structurala, aceeasi solutie propusa (poArticol construit ad-hoc) ca varianta (b) de
-la S4e §6 pentru `do_verifica_articol` — de unificat la implementare daca se poate, nu de rezolvat de
-doua ori independent.
-
-### 5.5 Maximul returnabil — nu se aplica, si acum e clar de ce
-
-Confirmat structural: azi maximul returnabil pe N.1 **nu e un calcul de "cat s-a mai returnat"**, e
-pur si simplu `CANTITATE` a liniei originale (`ff_...sql:4036`, `ofacturare.vc2:15236-15239`,
-`do_verifica_articol:14743-14754`) — validarea respinge doar semnul gresit (`tnCantitate >= 0` in mod
-retur), nu o depasire fata de un istoric. **Pentru o linie libera, intrebarea nici nu se pune in
-termenii de azi**: `do_verifica_articol`, ca si dialogul de gestiune (5.4), asteapta un `poArticol`
-din `crsarticole` — o linie libera nu are unul, deci nu poate trece prin comparatia de maxim existenta
-nici macar din greseala. Validarea proprie a liniei libere (cantitate/stoc, construita ad-hoc, 5.4)
-nu are nimic de comparat cu un "maxim returnabil" — verifica doar disponibilul de stoc curent, ca pe
-o linie normala de lista de preturi (acelasi gol deschis de S4e §6 pentru comanda, aceeasi solutie).
-
----
-
-## 6. Efectul asupra `VANZARI_CORESP`
-
-**Scrierea nu depinde de continutul liniilor, ci de alegerea facuta la antet.**
-`scrie_corespondente_vanzari(3)` (`ff_...sql:14834-14836`, apelata din `finalizeaza_factura`) scrie
-direct din `pack_facturare.clistaid` (variabila de sesiune, = `poDate.listaid` trimis la
-`initializeaza_date_factura`), **independent** de ce a ajuns efectiv in `VANZARI_DETALII` la
-finalizare:
-
-```sql
-INSERT INTO VANZARI_CORESP (ID_VANZARE_FACT, ID_VANZARE_AVIZ, TIP)
- SELECT pack_facturare.nid_vanzare, ID_VANZARE, 3
- FROM VANZARI WHERE ID_VANZARE IN (SELECT X FROM table(charn2collection(V_LISTAID,',')));
-```
-(`ff_...sql:15481-15516`, citat integral in `legatura_linie_retur.md:45-53`)
-
-**Consecinta directa pentru liniile libere**: daca documentul de retur contine si linii libere (din
-lista de preturi), corespondenta **tot se scrie**, si scrie exact aceleasi facturi alese la antet —
-liniile libere nu adauga si nu scot randuri din `VANZARI_CORESP`, pentru ca sursa e `poDate.listaid`
-(fixat la antet), nu continutul `crsfactura`/`VANZARI_DETALII`. Un document de retur cu 3 linii
-mostenite din factura A si 2 linii libere scrie tot un singur rand in `VANZARI_CORESP`
-(`ID_VANZARE_FACT`=documentul nou, `ID_VANZARE_AVIZ`=factura A, `TIP=3`) — corespondenta descrie
-"acest document a folosit ca sursa factura A", nu "aceste linii vin din factura A".
-
-**Ce se scrie cand nu s-a ales nicio factura sursa**: nu e un caz posibil pentru documentul de retur
-insusi — validarea de antet (`inainte_de_do_termin`, `descriere` obligatoriu, sectiunea 3) impune cel
-putin o factura aleasa inainte ca documentul sa poata continua. Deci pentru N.1/S4f (documente 8/9/24)
-`clistaid` nu e niciodata gol la scriere. **Pentru N.2 ridicat la document (punctul 2)** raspunsul e
-diferit: acolo documentul e de tip 1/5/7/10, iar `poDate.listaid`/campul nou echivalent (sectiunea 4)
-nu e obligatoriu — un document normal fara nicio linie de retur nu are ce sa scrie. **Intrebare
-deschisa, verificata partial**: daca `scrie_corespondente_vanzari(3)` e apelata azi doar cand
-`ntip in (8,9)` (confirmat de `legatura_linie_retur.md:113`: *"TIP=3: factura de retur
-(scrie_corespondente_vanzari(3), :14834-14836, la ntip in (8,9))"*), atunci **ridicarea lui N.2 la
-nivel de document NU va scrie automat `VANZARI_CORESP`** — documentul ramane tip 1/5/7/10, gardat de
-`ntip`, nu de continutul `listaid`. Linia exacta a acestui `IF`/`CASE` in exportul curent
-(`ff_2026_08_09_01...sql`) **nu a fost re-verificata caracter cu caracter** in aceasta sesiune (citata
-din raportul sursa, care a folosit un export anterior cu alta numerotare) — de reverificat la
-implementare, dar concluzia structurala (gating pe `ntip`, nu pe `listaid`) e solida.
-
-**Decizie de proiectare care rezulta**: ridicarea lui N.2 la nivel de document (punctul 2) **nu
-capata**, prin simpla ridicare, o corespondenta persistata in `VANZARI_CORESP` — comportamentul
-raman identic cu azi (nicio legatura scrisa), *cu exceptia* cazului in care Marius decide explicit ca
-merita cod Oracle nou (extinderea gardei `ntip in (8,9)` la un al treilea semnal, ex. "are `listaid`
-populat"). Decizia 35 (un singur cod de scriere contabila, cod Oracle nou doar cand strict necesar)
-face ca varianta "fara schimbare in pack_facturare" sa fie implicita — **de confirmat cu Marius**
-(risc R4), nu de presupus.
-
----
-
-## 7. Semnul cantitatii / al valorii pe retur
-
-**Doua mecanisme diferite, verificate separat pe cod:**
-
-- **N.1 (documente 8/9/24)**: cantitatea vine deja cu semnul corect direct din
- `cursor_retur_document` — `CANTITATE` a liniei originale (pozitiva ca valoare de referinta, dar
- interpretata cu semn de retur prin `poDate.tip`); semnul efectiv de scriere in `VANZARI_DETALII`
- e controlat de codul Oracle care insereaza documentul de retur (nu urmarit aici, in afara
- perimetrului VFP), iar in UI validarea `do_verifica_articol` (`llRetur = Inlist(poDate.tip,8,9,24)`)
- respinge `tnCantitate >= 0` in mod retur — deci utilizatorul introduce cantitatea ca valoare
- pozitiva ("cat returnez"), iar semnul negativ e o conventie aplicata la nivel de tip de document,
- nu per linie.
-- **N.2 (`But_retur`)**: semnul negativ **e aplicat explicit in cod VFP**, in
- `frm_articol_gest_factura` — `poArticol.cantitate = (-1) * cantitate` (`ofacturare.vc2:4103`),
- declansat de `Thisform.lRetur` (adevarat cand `tlRetur` a fost trimis la `Init`, indiferent de
- `poDate.tip`). Aici semnul **nu** vine din `poDate.tip` (documentul e tip 1/5/7/10, pozitiv prin
- design), ci e o negatie explicita facuta pentru ca acea linie anume e un retur intr-un document
- altfel normal.
-
-**Implicatie pentru liniile libere pe document de retur (S4f punctul 3)**: pentru ca documentul
-intreg e tip 8/9/24, orice linie — libera sau mostenita — trece prin acelasi tratament de tip de
-document (semnul negativ e o proprietate a **documentului**, nu a liniei, in acest caz). Nu exista
-risc de "linie libera cu semn pozitiv gresit" atata timp cat validarea ramane gatata pe `poDate.tip`
-si nu pe originea liniei — de verificat explicit ca ramura noua a validarii (5.4, sarirea peste
-maximul returnabil) **nu** atinge si sare peste verificarea de semn, care trebuie sa ramana activa
-identic pe linii libere si mostenite.
-
-**Implicatie pentru N.2 ridicat la document (punctul 2)**: aici semnul **ramane** o proprietate de
-linie (nu de document, pentru ca documentul e tip normal 1/5/7/10) — mecanismul de la
-`ofacturare.vc2:4103` se pastreaza neschimbat, declansat de acelasi `tlRetur`/`Thisform.lRetur`,
-indiferent daca alegerea facturii sursa se face per-articol (ca azi) sau la nivel de document
-(punctul 2). Nimic de schimbat aici — doar de confirmat ca noul flux (alegere la document) tot
-seteaza `tlRetur=.T.` la apelul catre `do_alege_stoc`/`frm_articol_gest_factura` pentru fiecare linie
-de retur adaugata.
-
----
-
-## 8. Unde se aseaza informatia de provenienta in UI
-
-**Inchis pe cod, cf. `legatura_linie_retur.md`**: legatura linie-la-linie nu se poate afisa in niciun
-caz — nici `cursor_retur_document` nu aduce `ID_VANZARE`/`ID_VANZARE_DET` in `crsarticole`
-(`ff_...sql:3965-4028`, coloanele lipsesc din SELECT), nici `INSERT`-ul final in `VANZARI_DETALII`
-nu are coloana de sursa (`PACK_FACTURARE:13705-13757`, listata explicit, fara camp de provenienta).
-
-**Ce se poate afisa, verificat**: la nivel de **document**, cand exact o singura factura sursa a fost
-aleasa, `VANZARI_CORESP(TIP=3)` da fara ambiguitate factura sursa:
-
-```sql
-SELECT v.serie_act, v.numar_act
- FROM VANZARI_CORESP c JOIN VANZARI v ON v.ID_VANZARE = c.ID_VANZARE_AVIZ
- WHERE c.ID_VANZARE_FACT = :id_document_retur AND c.TIP = 3 AND c.STERS = 0;
-```
-(`legatura_linie_retur.md:174-178`, interogare formulata, neverificata pe date live in acel raport)
-
-**Propunere concreta de text si conditie** (in romana, pentru sectiunea pliata / antetul
-formularului unificat):
-
-- **O singura factura sursa aleasa**: eticheta fixa de tip "Provine din factura: **{serie} {numar}**"
- langa campul de descriere existent (`poDate.text_aditional`, deja populat azi cu
- "RETUR FACTURA {numere}" — `factura_retur_document.md:65`), afisata read-only, imediat sub sau langa
- campul de tip document.
-- **Mai multe facturi sursa alese**: eticheta devine "Provine din facturile: **{lista serie+numar}**"
- — aceeasi sursa de date (`poDate.descriere`, deja populata cu lista, nu doar `VANZARI_CORESP`),
- **fara** sa se sugereze vreo distributie pe linii.
-- **Niciodata pe linie** — nici coloana in grid, nici tooltip per rand care sa pretinda o sursa
- exacta. Pentru liniile libere in particular, nu exista nimic de afisat (nu au sursa) — nu se
- introduce o valoare "N/A" vizibila care ar sugera ca alte linii AU o sursa unica atunci cand de
- fapt (cu selectie multipla) nici ele nu o au cu certitudine.
-- **Conditie tehnica**: textul se construieste din `poDate.descriere` (deja in memorie, fara interogare
- suplimentara) — nu necesita interogarea `VANZARI_CORESP` de mai sus decat daca se doreste
- reafisarea la redeschiderea unui document deja emis (regenerare, etapa II) — caz in care
- interogarea de mai sus e necesara pentru ca `poDate.descriere` nu mai exista in memorie.
-
----
-
-## 9. Pasi de implementare ordonati
-
-1. **Confirmarea comportamentului aditiv/inlocuitor la alegerea facturilor sursa** (sectiunea 3,
- punctul 3) — decizie de produs, nu cod. *Gata cand:* Marius a ales (a) sau (b); fara asta pasii 2-3
- nu se pot implementa fara risc de refacere.
- *Verificabil:* niciunul (decizie, nu cod).
-2. **Butonul/actiunea de alegere a facturilor sursa, mutat in sectiunea pliata a formularului
- unificat**, pastrand `do_cauta_facturi`/`caut_facturi_multiple_client` neschimbate — doar
- punctul de declansare se muta din antetul modal in sectiunea pliata a formularului unic, si
- `cursor_retur_document` se declanseaza la confirmarea dialogului, nu la inchiderea unui formular
- separat (sectiunea 3, punctele 1-2).
- *Gata cand:* pe un document nou de tip 8/9/24, deschis in formularul unificat, alegerea facturilor
- sursa din sectiunea pliata populeaza `crsarticole` cu exact aceleasi randuri ca azi (gestiune, pret
- achizitie, pret vanzare identice), verificabil prin comparatie directa a cursorului.
-3. **Meniul "Adauga articole" pe tipurile 8/9/24**, cu optiunile "Adauga tot din facturile alese" /
- "Alege liniile de returnat…" peste `crsarticole` deja populat (reteta comuna S4b, sectiunile 4-5
- ale acelui raport) — fara alegere de facturi in acest meniu (sectiunea 3).
- *Gata cand:* meniul contine exact aceste doua optiuni pe tip 8/9/24, plus "Cauta in lista de
- preturi…"/"Alege din nomenclator…" (punctul urmator).
-4. **Liniile libere — `APPEND BLANK` pe `crsfactura`, semnalul de distinctie pe `id_c`** (sectiunile
- 5.1-5.2): optiunea de meniu "Cauta in lista de preturi…" pe tip 8/9/24 declanseaza
- `Select crsFactura / APPEND BLANK` + `combosql`, exact tiparul S4e (`ofacturare.vc2:17118-17122`)
- — **nu** `APPEND FROM` peste `crsarticole`. `id_c` ramane implicit (`0`) pe randul nou.
- *Gata cand:* dupa adaugarea unei linii libere pe un document de test, `crsfactura.id_c = 0` pe acel
- rand si `crsarticole` ramane neschimbat (acelasi `Reccount`/continut ca inainte de adaugare).
-5. **Punct de intrare nou in dialogul de gestiune, pornind de la randul din `crsfactura`** (sectiunea
- 5.4) — `frm_articol_gest_factura`/`do_alege_stoc` primesc o a doua cale de apel, cu `poArticol`
- construit ad-hoc din randul deja inserat in `crsfactura` (dupa `combosql`), nu din `Scatter` pe un
- rand din `crsarticole`. Fara acest pas, o linie libera nu poate ajunge deloc la alegerea gestiunii
- ceruta de decizia 22.
- *Gata cand:* pe o linie libera adaugata pe un document de retur, dialogul de gestiune se deschide si
- returneaza `ID_GESTIUNE`/`PRET_ACHIZITIE` alese de operator, fara sa fi trecut prin `crsarticole`.
-6. **Fixarea pretului de vanzare pe liniile libere** (sectiunea 5.3, riscul R1) — ramura de
- suprascriere din `frm_articol_gest_factura` (`ofacturare.vc2:4094-4103`) primeste al doilea semnal
- ("are sursa" vs. "e libera"), derivat din `crsfactura.id_c <> 0` (pasul 4), si nu suprascrie
- `pretftva` cand linia e libera.
- *Gata cand:* o linie libera adaugata pe un document de retur pastreaza pretul din lista de preturi
- dupa alegerea gestiunii, verificabil comparand `poArticol.pretftva` inainte si dupa
- `RowColChange` in dialogul de gestiune.
-7. **Validarea de cantitate/stoc pe liniile libere** (sectiunea 5.5) — mecanism nou, nu
- `do_verifica_articol` ca atare (care cere un `poArticol` din `crsarticole`); verifica disponibilul
- de stoc curent, fara nicio comparatie cu un maxim returnabil. Unificabil cu golul echivalent
- deschis de S4e §6 pentru comanda/avize, daca implementarea alege aceeasi varianta (`poArticol`
- construit ad-hoc, parametru explicit).
- *Gata cand:* pe o linie libera, orice cantitate <= stocul curent trece validarea, cu mesaj propriu
- (nu "cantitate maxima de returnat"); pe o linie mostenita, comportamentul de azi ramane neschimbat.
-8. **Ridicarea `But_retur` la nivel de document (punctul 2)** — dialog de alegere multipla la
- deschiderea primei linii de retur pe un document normal (1/5/7/10), populare cu un camp nou sau
- reutilizarea controlata a lui `poDate.listaid` (sectiunea 4), pastrand calea per-articol existenta
- ca fallback sau eliminand-o explicit (decizie separata, risc R3).
- *Gata cand:* pe o factura normala, alegerea facturilor sursa se face o singura data, iar liniile de
- retur adaugate ulterior (mai multe articole) folosesc acel set fara sa redeschida dialogul de
- cautare la fiecare articol.
-9. **`VANZARI_CORESP` pentru N.2 ridicat la document** (sectiunea 6) — de decis daca se adauga cod
- Oracle nou sau ramane fara corespondenta persistata (risc R4); implementat doar dupa decizia lui
- Marius.
- *Gata cand:* comportamentul ales (cu sau fara corespondenta) e implementat consistent si testat pe
- un document cu retur ridicat la nivel de document si mai multe facturi sursa.
-10. **Textul de provenienta la antet** (sectiunea 8) — afisare read-only din `poDate.descriere`,
- condusa de numarul de facturi alese (0/1/multiple).
- *Gata cand:* eticheta arata corect in toate trei cazurile (nicio factura inca, o factura, mai
- multe), fara sa apara pe grid/linie.
-
-*Depinde de:* S2 (formular unificat de baza), S4e (mecanismul `APPEND BLANK` + `combosql` pentru
-liniile libere pe document cu sursa, NU `APPEND FROM`) — exact ca in plan (`plan_13...md:2330`),
-corectat fata de reteta literala a deciziei 16.
-
----
-
-## 10. Cum se verifica
-
-**Proba din plan** (`plan_13...md:2327-2329`): *"un document de retur deschis in formularul unificat
-aduce liniile facturilor alese cu aceleasi valori ca azi — inclusiv gestiunea si pretul de
-achizitie —, permite stergere si cantitate partiala, iar pe o factura normala se poate face retur
-alegand facturile o singura data."*
-
-Pasi concreti:
-
-1. **Paritate N.1**: pe date de test, emite un document de retur (tip 8) pe calea veche (formularul
- actual) si retine `crsarticole` rezultat (gestiune, pret achizitie, pret vanzare, cantitate per
- linie). Repeta aceeasi alegere de facturi sursa in formularul unificat si compara `crsarticole`
- camp cu camp — trebuie sa fie identic, pentru ca sursa Oracle (`cursor_retur_document`) nu se
- schimba, doar punctul VFP care o declanseaza.
-2. **Stergere si retur partial**: pe formularul unificat, sterge o linie mostenita si verifica ca
- cantitatea reintra in `crsarticole` (acelasi test ca azi, `do_sterge` neschimbat); introdu o
- cantitate mai mica decat maximul pe o linie mostenita si verifica validarea.
-3. **Linie libera**: adauga o linie din lista de preturi pe documentul de retur deschis (prin
- `APPEND BLANK` + `combosql`, nu `APPEND FROM`); verifica (a) `crsfactura.id_c = 0` pe acel rand si
- `crsarticole` neschimbat; (b) pretul de vanzare = pretul din lista de preturi, nu din stoc; (c)
- gestiunea/pretul de achizitie sunt cerute prin dialogul de gestiune (intrat pe calea noua, 5.4), nu
- completate automat; (d) cantitatea nu e limitata de niciun maxim istoric, doar de stocul curent;
- (e) semnul cantitatii ramane negativ (consistent cu documentul); (f) stergerea liniei libere nu
- modifica `crsarticole` (verifica direct: `Reccount`/continut identic inainte si dupa stergere).
-4. **`VANZARI_CORESP` neschimbat de liniile libere**: dupa emiterea documentului din pasul 3,
- interogheaza:
- ```sql
- SELECT ID_VANZARE_FACT, ID_VANZARE_AVIZ, TIP FROM VANZARI_CORESP
- WHERE ID_VANZARE_FACT = :id_document_nou AND TIP = 3;
- ```
- — trebuie sa arate exact facturile alese la antet, indiferent de cate linii libere s-au adaugat.
-5. **N.2 ridicat la document**: pe o factura normala, adauga doua linii de retur pentru articole
- diferite folosind acelasi set de facturi sursa ales o singura data (nu redeschide dialogul la
- fiecare articol); verifica semnul cantitatii (negativ) si absenta oricarei scrieri in
- `VANZARI_CORESP` (daca decizia de la punctul 8/risc R4 pastreaza comportamentul de azi).
-6. **Provenienta**: deschide un document de retur cu o singura factura sursa — verifica textul de
- antet; alege doua facturi sursa — verifica ca textul listeaza ambele si nu implica o sursa unica.
-
-## 11. Ce nu se poate testa headless
-
-Reluat din capcanele deja confirmate pe acest proiect (`s4b_bara_butoane_meniu.md` §8), plus
-specificul retur:
-
-- **`cauta_alfa` cu `tnTipReturn=1`** — dialog modal (`.Show(1)`), blocheaza thread-ul UI; testarea
- automata a bifarii multiple nu se poate face prin injectare de input pe aceasta masina (partajata,
- memoria `masina-partajata-fara-input-real`). Se verifica indirect: apeland direct
- `caut_facturi_multiple_client`/`cursor_retur_document` cu parametri de test si citind cursorul
- rezultat, ocolind UI-ul.
-- **`frm_articol_gest_factura`** — acelasi tip de dialog modal; verificarea suprascrierii de pret
- (risc R1, sectiunea 5.3) si a noului punct de intrare pornit din `crsfactura` (sectiunea 5.4) se
- poate face doar citind codul metodei `RowColChange`/noua metoda de intrare si, separat, apeland
- direct logica de calcul cu date de test simulate — nu prin click real in grid.
-- **Coloanele griduri** (`grd_articole`, gridul dialogului de alegere) — capcana deja cunoscuta:
- `ColumnCount=0` sub `-A -T`; verificare vizuala necesita harness UI vizibil, nu headless.
- (memoria `grid-coloane-nu-se-materializeaza-headless`)
-- **Textul de provenienta din sectiunea pliata** (sectiunea 8) — verificabil headless ca **continut
- al proprietatii** (`Caption`/`Value` a controlului), nu ca "arata bine" vizual.
-- **Secventa reala de deschidere a dialogului din sectiunea pliata** (declansarea la click, nu doar
- codul din spatele ei) — necesita harness UI vizibil pentru captura de interactiune.
-
-**Ce se poate verifica headless, direct**: continutul `crsarticole`/`crsfactura` dupa apeluri directe
-ale rutinelor (`cursor_retur_document`, `do_adauga_articol`, `do_verifica_articol`, `APPEND BLANK` pe
-`crsfactura`) cu parametri de test; valoarea `crsfactura.id_c` pe randurile noi (semnalul de la 5.2,
-`0` pe liniile libere, valoare reala pe cele mostenite); continutul real din
-`VANZARI_CORESP`/`VANZARI_DETALII` dupa emiterea unui document de test pe schema Oracle (doar
-`SELECT`, verificare post-factum).
-
----
-
-## 12. Riscuri si ce ramane de decis de Marius
-
-**R1 — Pretul de vanzare pe liniile libere se suprascrie cu pretul de stoc, daca nu se trateaza
-explicit** (sectiunea 5.3). Cel mai concret risc gasit in aceasta cercetare, netratat in plan pana
-acum. **Recomandare**: al doilea semnal ("linie cu sursa" vs. "linie libera") pe langa `tlRetur`,
-derivat din `crsfactura.id_c <> 0` (5.2), care sa dezactiveze suprascrierea de pret doar pentru
-liniile libere. Necesita o mica modificare in `frm_articol_gest_factura` (nu in `pack_facturare`).
-
-**R7 — Punctul de intrare in dialogul de gestiune pentru o linie libera nu exista azi** (sectiunea
-5.4). Gol nou, mai strict decat echivalentul lui pe comanda/avize (S4e §6, doar validare de
-cantitate) — pe retur blocheaza si alegerea gestiunii/pretului de achizitie, obligatorie prin decizia
-22. `do_alege_stoc`/`frm_articol_gest_factura` se intra azi doar dintr-un `poArticol` scatter-uit din
-`crsarticole`; o linie libera (`APPEND BLANK` pe `crsfactura`, 5.1) nu are asa ceva. **Recomandare**:
-a doua cale de apel, cu `poArticol` construit ad-hoc din randul `crsfactura` deja completat prin
-`combosql`, unificata daca se poate cu solutia aleasa pentru golul echivalent de validare (R7 aici,
-S4e §6/varianta b acolo) — un singur mecanism de "construieste `poArticol` fara sursa in `crsarticole`",
-nu doua independente.
-
-**R2 — Alegere aditiva sau inlocuitoare la a doua apasare a dialogului de facturi sursa** (sectiunea
-3, punctul 3). Nu e tratat de nicio decizie existenta. **Recomandare**: aditiv, consistent cu
-filozofia deciziei 16, dar cere cod VFP nou (bucla de filtrare pe facturi noi + `INSERT INTO
-crsarticole`).
-
-**R3 — Ce se intampla cu `caut_facturi_multiple_client_articol` (alegerea per-articol) dupa ridicarea
-lui `But_retur` la nivel de document.** Ramane ca optiune secundara sau se elimina? Nefolosit oriunde
-altundeva in cod (verificat implicit — apelul e doar din `do_adauga_articol`, ramura `tlRetur`).
-**Recomandare**: se elimina, pentru ca pastrarea ambelor cai ar insemna doua UX-uri pentru aceeasi
-actiune, exact riscul pe care unificarea vrea sa il elimine.
-
-**R4 — `VANZARI_CORESP` pentru N.2 ridicat la document.** Gardat azi pe `ntip in (8,9)`, nu pe
-continutul `listaid` — **reconfirmat independent** in aceasta sesiune, pe exact acelasi export
-(`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:14834-14836`): `WHEN pack_facturare.ntip in (8, 9) THEN
-pack_facturare.scrie_corespondente_vanzari(3);`, in interiorul unui `CASE` fara alta conditie pe
-`listaid`. Daca ramane asa, un document normal
-cu retur ridicat la document nu va avea nicio legatura persistata catre facturile sursa alese — exact
-ca azi cu `But_retur` per-articol, deci nu e o regresie, dar nici un castig. **Recomandare**: se lasa
-neschimbat (fara cod Oracle nou), consistent cu decizia 35 (economie de cod de intretinut) — de
-confirmat explicit cu Marius, pentru ca punctul 2 al S4f ("ridicarea la nivel de document") ar putea
-crea asteptarea implicita ca acum exista si o legatura persistata, cand de fapt nu exista.
-
-**R5 — `Ct_clb_altele.cconditie` — semantica exacta neconfirmata** (sectiunea 2.1). Daca acest camp
-chiar dezactiveaza azi re-alegerea dupa prima selectie, design-ul nou (sectiunea 3) trebuie sa decida
-explicit sa **elimine** aceasta restrictie (pentru varianta aditiva) — altfel comportamentul nou ar
-fi mai permisiv decat parea sa fie azi, fara sa fi fost o decizie constienta. **De verificat la
-implementare**, cand clasa `ct_clb_cautare` devine accesibila (posibil in `COMUNROA`, in afara acestui
-repo).
-
-**R6 — Semnul cantitatii pe liniile libere, verificare explicita ceruta de brief** (sectiunea 7): nu
-e un risc nou — analiza arata ca semnul e o proprietate a documentului (tip 8/9/24), nu a liniei,
-deci liniile libere il mostenesc automat corect. Se listeaza aici doar ca sa fie explicit ca punctul
-a fost verificat, nu omis.
-
----
-
-## Handoff
-
-Cercetare incheiata fara sa fie nevoie de predare de context — un subagent de verificare
-(`ab0be8e27f0fb97f3`, Explore/general-purpose) a esuat de doua ori sa returneze rezultate, apoi a
-raspuns complet la a treia incercare (reluat prin `SendMessage`), confirmand independent 4 puncte deja
-scrise pe cod propriu in raport: (1) `do_cauta_facturi` e declansat explicit de user, prin
-`Ct_clb_altele`/`caut_ora.vc2:787-798,839-844` -> `do_cauta_altele` -> `do_cauta_facturi`
-(`ofacturare.vc2:8940-8961,9173`), inainte de orice deschidere a `frm_facturare_articole`; (2)
-`scrie_corespondente_vanzari(3)` e gardat exact pe `ntip in (8,9)`
-(`ff_...sql:14834-14836`) — folosit sa inchid definitiv R4; (3)
-`thisform.cListaIdArticoleRetur` poate acumula `ID_VANZARE` diferit per articol
-(`ofacturare.vc2:12882-12892`); (4) `poDate.listaid` e acelasi camp la N.1 si N.2, dar cu rol
-tranzitoriu la N.2 (salvat/restaurat) si definitiv doar la `do_scrie_articole`
-(`ofacturare.vc2:13977-13979`). Niciuna din aceste confirmari nu a schimbat vreo concluzie a
-raportului, doar le-a intarit sursa.
-
-**Corectie aplicata dupa livrare**, la avertismentul `team-lead` (bazat pe
-`docs\cercetare\s4e_lista_preturi_pe_sursa.md`, sectiunile 3 si 7): sectiunea 5 (liniile libere) a
-fost **rescrisa integral** — reteta `APPEND FROM` peste `crsarticole` (premisa initiala a brief-ului)
-e inlocuita cu mecanismul validat de S4e (`APPEND BLANK` pe `crsfactura` + `combosql`, niciodata pe
-`crsarticole`), campul de distinctie devine `crsfactura.id_c = 0` (nu absenta `PRET_ACHIZITIE` pe
-`crsarticole`), si s-a adaugat un gol nou, negasit de S4e (care nu are dialog de gestiune pe
-comanda/avize): punctul de intrare in `frm_articol_gest_factura` pentru o linie fara rand sursa in
-`crsarticole` (risc R7, nou). Verdictul de la inceputul raportului, pasii de implementare (9),
-verificarea (10) si sectiunile headless (11) au fost actualizate in consecinta. Restul raportului
-(sectiunile 1-4, 6-8, 12 minus R1/R7) ramane neschimbat fata de livrarea initiala.
-
-Fisierul SQL folosit: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`
-(cel mai recent din director). Nicio editare de cod, niciun `git_sync.ps1`/`txt2vcx.ps1`, niciun
-commit, nicio scriere Oracle.
diff --git a/docs/cercetare/s4g_adaugare_articole_modificare.md b/docs/cercetare/s4g_adaugare_articole_modificare.md
deleted file mode 100644
index 45ea33c..0000000
--- a/docs/cercetare/s4g_adaugare_articole_modificare.md
+++ /dev/null
@@ -1,437 +0,0 @@
-# S4g — Adaugarea de articole la modificarea oricarui document (proiectare)
-
-Proiectare, nu implementare. Zero fisiere de cod atinse, zero write-back, zero commit. Pe Oracle
-doar `SELECT`. Continua planul `docs\plan_13_unificare_formular_facturare.md` liniile 2494-2530 si
-cercetarile `canal_cont_venit_fara_politica.md` (sectiunea "Proiectarea parametrului de cont
-contabil"), `parametru_cont_contabilizeaza_articol.md`, `coresp_cont_venchelt.md`,
-`optiune_firma_cont_debit.md`.
-
-**STARE: cercetare/proiectare incheiata.**
-
-Sursa PL/SQL verificata direct in aceasta runda: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`
-(17217 linii, confirmat `wc -l`). Cod VFP citit: `COMUN\clase\ofacturare.vc2`,
-`COMUN\programe\ofacturare_comun.prg` (ambele permise). Neatinse: `COMUN\clase\ofacturare_comun.vc2`,
-`COMUN\programe\ofacturare_editare.prg` (perimetrul sesiunii #6).
-
----
-
-## 0. Premisele deja decise (nu se redeschid)
-
-- Povestea: a doua sursa de articole in meniu, "Alege din nomenclator...", disponibila si la
- modificarea oricarui document deja emis, inclusiv auto (tip = -12, dar livrat separat, dupa).
-- Decizia 20: din nomenclator se ofera si gestionabile, si negestionabile — nu se copiaza filtrul
- `in_stoc = 0` al lui ROAAUTO.
-- Decizia 21: contul de gestiune are fallback, nu NULL, nu refuz — mecanism separat de cel de aici
- (priveste `id_gestiune`/`Cont` de gestiune al liniei, nu contul de venit), presupus deja rezolvat
- cand derivarea din sectiunea 3 porneste.
-- Decizia 27 (transportul inlocuit de decizia 34): contul de venit se **deriva** in VFP —
- `CORESP_CONT_VENCHELT` pentru gestionabile (pe contul de gestiune al liniei), `NOM_ARTICOLE.CONT`
- daca e 6xx/7xx pentru negestionabile, altfel `704`.
-- Decizia 34: transportul e parametru nou, direct — nu prin `id_pol`/politica tehnica. Ocolul prin
- `pack_preturi.adauga_politica_pret_art` e abandonat.
-- Decizia 35: acelasi drum serveste si editarea prin regenerare — nu se proiecteaza a doua ruta de
- contare.
-- Decizia 36 (noua, 10.08.2026): `SCD` pe ramura fara politica nu e hardcodat `'4111'` literal —
- vine dintr-o optiune de firma (`getoptiunefirma`), cu `4111` ca implicit dublu (rand in `OPTIUNI`
- + fallback hardcodat in PL/SQL), tiparul deja folosit de `RF_CONT_INCASARE_*` in acelasi pachet.
-- "Alte servicii" ROAAUTO ocoleste complet `contabilizeaza_articol` — exceptie, nu jumatate de
- mecanism.
-- Regula deja adoptata in #13: liniile libere nu intra deloc in `crsarticole` — `APPEND BLANK` +
- `combosql` direct in `crsfactura`, ca `id_c` sa ramana `0` si `do_sterge` sa fie no-op prin
- constructie (verificat aici ca acelasi tipar se aplica si campului `id_pol`, sectiunea 4).
-- Ordine: intai ROAFACTURARE, apoi tip = -12.
-
----
-
-## 1. Punctul central: parametru vs politica, cine castiga
-
-### 1.1 Ce face azi codul, verificat direct pe sursa (nu preluat din rapoarte)
-
-`contabilizeaza_articol` (`ff_...:7173-7547`) primeste un singur parametru,
-`detalii_articol VANZARI_DETALII_TEMP%ROWTYPE`. Primul lucru pe care il face (`:7275-7302`):
-
-```sql
-BEGIN
- SELECT COMPUS, ID_POL_ART
- INTO V_COMPUS, V_ID_POL_ART
- FROM VCRM_POLITICI_PRET_ART
- WHERE ID_ARTICOL = detalii_articol.id_articol
- AND ID_POL = detalii_articol.id_pol;
-EXCEPTION
- WHEN NO_DATA_FOUND THEN
- ...
- RAISE_APPLICATION_ERROR(-20000, 'Articolul ... nu este definit in politica de preturi ... (FACT-024)');
-END;
-```
-
-Daca `detalii_articol.id_pol` e `NULL`, comparatia `ID_POL = NULL` nu se potriveste niciodata —
-`NO_DATA_FOUND` garantat, FACT-024 garantat. Acelasi rezultat daca `id_pol` e populat dar articolul
-nu e in acea politica. **`cursor_articol`** (`:7218-7271`), care face tot lucrul real (`scrie_nota`,
-`descarca_gestiune`, discount), e filtrat **pe exact aceeasi cheie** (`A.ID_POL = detalii_articol.id_pol
-AND A.ID_ARTICOL = detalii_articol.id_articol`, `:7270-7271`) — daca `SELECT INTO` de mai sus a picat
-in `NO_DATA_FOUND`, cursorul ar gasi tot zero randuri (aceeasi cauza). Deci punctul de intrare in
-politica e unic si dublu-verificat (o data prin exceptie explicita, o data structural prin cursor).
-
-Design-ul deja facut (`canal_cont_venit_fara_politica.md:132-138`) propune sa infasoare **toata
-functia** intr-un switch la nivel de metoda:
-
-```
-IF detalii_articol.cont_venit IS NOT NULL THEN
-
-ELSE
-
-END IF;
-```
-
-**Aceasta e deja, prin constructie, varianta "parametrul castiga necondiionat cand e populat"** —
-cand `cont_venit` nu e `NULL`, executia nu se mai uita deloc la `id_pol`/politica, indiferent daca
-acestea ar fi rezolvat sau nu. Team-lead-ul cere explicit sa se decida asta ca punct de proiectare,
-nu sa ramana o consecinta implicita a formei codului — mai jos analiza celor 3 variante realiste.
-
-### 1.2 Cele 3 variante
-
-**A. Parametrul castiga mereu cand e populat** (= design-ul existent, ca atare).
-- *Ce se strica*: daca, dintr-un motiv oarecare (bug VFP, sau — mai realist — decizia 35: la
- **regenerare**, daca logica de derivare a lui `cont_venit` ar rula necondiionat pe toate liniile
- documentului, inclusiv cele scrise initial prin "Cauta in lista de preturi..." cu `id_pol` real),
- o linie ajunge la Oracle cu **ambele** populate, `SCC`-ul politicii reale e inlocuit tacut cu
- contul derivat generic, `SCD` cu optiunea de firma (posibil diferita de `NOTE_CONTABILE.SCD` al
- notei reale), `ASCD`/`ASCC`/`EXPLICATIE`/`CU_TVA` cu variantele generice ale ramurii noi. **Fara
- nicio eroare** — factura se emite, dar cu alta contare decat cea configurata prin politica. Cel
- mai periculos tip de defect: tace si trece verificarea vizuala (suma corecta, cont plauzibil).
-
-**B. Politica castiga mereu cand `id_pol` e populat** (indiferent daca rezolva sau nu).
-- Ar cere schimbarea conditiei de switch din `cont_venit IS NOT NULL` in ceva de forma
- `id_pol IS NULL AND cont_venit IS NOT NULL` — adica: daca exista `id_pol` pe linie, mergi pe
- ramura veche necondiionat, chiar daca acel `id_pol` nu rezolva (caz FACT-024 de azi).
-- *Ce se strica*: exact scenariul in care mecanismul nou ar fi cel mai util — o linie cu `id_pol`
- populat gresit/stale (nu neaparat imposibil, doar improbabil in fluxul normal, vezi 1.3) —
- ar continua sa primeasca FACT-024 desi VFP a trimis explicit un cont de rezerva. Varianta cea mai
- fragila: defineste "castigatorul" pe **prezenta** unui camp, nu pe **rezolvarea** lui.
-
-**C. Parametrul e folosit doar cand politica nu rezolva** (fallback real, nu switch pe camp).
-- Cere ca `SELECT INTO ... FROM VCRM_POLITICI_PRET_ART` (1.1) sa ramana **necondiionat**, exact ca
- azi (deja rulat pe fiecare linie, cost zero suplimentar), dar `EXCEPTION WHEN NO_DATA_FOUND` sa
- verifice `cont_venit`: daca e populat, ramura noua; daca nu, `RAISE FACT-024` ca azi. Semantic
- corect — politica, cand exista si rezolva, nu e niciodata inlocuita tacut; parametrul e strict ce
- a fost gandit sa fie: o plasa pentru cazul in care politica lipseste.
-- *Cost real*: restructurare interna a functiei, nu doar un `IF` la inceput. Codul de dupa blocul
- `EXCEPTION` verifica azi `IF V_COMPUS = 1 THEN ... ELSE END IF`
- (`:7305,7391`) — `V_COMPUS` ramane `NULL` daca s-a intrat pe `EXCEPTION`, deci "cade" oricum pe
- ramura `ELSE` care deschide `cursor_articol` (gaseste zero randuri, nu declanseaza nimic, dar nici
- ramura noua). Trebuie introdus un flag explicit (`V_ARE_POLITICA`/similar) propagat din interiorul
- `EXCEPTION` pana la punctul de decizie, marind suprafata modificata fata de varianta A (care
- atinge doar granita functiei, cu restul intact).
-
-### 1.3 Ar putea sa apara vreodata, in fluxul normal, ambele populate?
-
-Verificat direct in aceasta runda (nu presupus): `crsfactura` (cursorul VFP din care se scrie orice
-linie) are `id_pol N(20) Null` (`COMUN\programe\ofacturare_comun.prg:1775`) — camp nullable, deci la
-`APPEND BLANK` (mecanismul liniilor libere, confirmat de S4e ca acelasi gest se foloseste si pentru
-"Alege din nomenclator...") ramane `.NULL.` implicit, nu `0`. La scriere, `poArt.id_pol` (scatter
-din randul respectiv) ajunge in apelul RPC ca `Nvl(Alltrim(Str(poArt.id_pol)),[NULL])`
-(`ofacturare.vc2:14072`, identic la `:18107`) — literal SQL `NULL` cand campul e `.NULL.`. **O linie
-"din nomenclator" trimite deci `id_pol = NULL` la Oracle prin constructie, nu doar prin conventie de
-utilizare** — cursorul de cautare al nomenclatorului (`caut_articol`, `ocautare.prg`, deja confirmat
-de `coresp_cont_venchelt.md` sectiunea 9d) nu are coloana `id_pol` in output, deci nu exista niciun
-punct in care combosql-ul ar putea popula acest camp cu o valoare reala pentru o astfel de linie.
-
-Ramane un singur scenariu real de ambiguitate: **regenerarea** (decizia 35). La regenerare, toate
-liniile documentului (cele scrise initial prin "Cauta in lista de preturi...", cu `id_pol` real, **si**
-cele adaugate prin "Alege din nomenclator...", fara `id_pol`) trec din nou prin acelasi drum de
-scriere. Daca logica VFP care calculeaza `cont_venit` (sectiunea 3) ar rula **necondiionat** pe toate
-liniile din grid, in loc sa fie conditionata explicit de "linia nu are `id_pol`", ar produce exact
-combinatia periculoasa din varianta A. **Asta nu e un risc Oracle — e un risc de implementare VFP**,
-dar exact tipul de risc pe care design-ul Oracle trebuie sa nu-l agraveze printr-un switch care il
-face invizibil.
-
-### 1.4 Recomandare
-
-**Niciuna dintre cele 3 variante pure, ci varianta A (deja proiectata, cea mai simpla) plus o garda
-explicita pe combinatia ambigua**, nu o rezolvare tacita in orice directie:
-
-```sql
-IF detalii_articol.cont_venit IS NOT NULL THEN
- IF detalii_articol.id_pol IS NOT NULL THEN
- RAISE_APPLICATION_ERROR(-20000,
- 'Articolul ' || detalii_articol.id_articol ||
- ' are simultan politica de pret (' || detalii_articol.id_pol ||
- ') si cont de venit calculat — conflict netratat (FACT-0xx)');
- END IF;
-
-ELSE
-
-END IF;
-```
-
-Motivare, in ordine:
-1. **Combinatia nu trebuie sa apara niciodata in fluxul normal** (1.3) — `id_pol` ramane `NULL` prin
- constructie pentru orice linie scrisa prin gestul "linie libera". Daca totusi apare, e un semnal
- ca ceva e stricat in populate-ul liniei (VFP a trimis ambele campuri, posibil din cauza logicii
- de regenerare descrisa la 1.3) — situatie de bug de investigat, nu de "rezolvat" silentios.
-2. **Variantele B si C rezolva combinatia in cate o directie fixa** — ambele ascund o eroare de date
- in loc sa o semnaleze: B ar putea reintroduce FACT-024 pe o linie unde VFP a oferit deja o
- solutie; A fara garda ar inlocui tacut o politica reala. O garda explicita e singurul comportament
- care nu presupune ca stie mai bine decat datele ce s-a intamplat.
-3. **Cost de implementare minim**: un singur `IF` suplimentar, la intrarea in ramura deja proiectata
- — nu restructureaza funcia (spre deosebire de varianta C), nu schimba conditia switch-ului
- principal (spre deosebire de B).
-4. **Compatibilitate/regresie zero pe apelantii de azi**: cand `cont_venit` e `NULL` (toti apelantii
- existenti, care nu cunosc inca acest parametru), executia intra direct pe `ELSE` — garda nu se
- evalueaza niciodata, comportamentul e identic bit-cu-bit cu azi. Cand `cont_venit` e populat si
- `id_pol` e `NULL` (cazul intentionat, "din nomenclator"), garda trece nevazuta, ramura noua
- ruleaza normal.
-
-**Numele codului de eroare** (`FACT-0xx` in schita de mai sus) ramane de ales de Marius, distinct de
-`FACT-024` (care ramane, neschimbat, pentru cazul "niciuna din cele doua" — linie fara politica si
-fara cont).
-
----
-
-## 2. Suprafata de schimbare pe Oracle
-
-Deja proiectata si verificata adversarial in `canal_cont_venit_fara_politica.md` si
-`parametru_cont_contabilizeaza_articol.md`; rezumat + completarea cu decizia 36 si garda de la
-sectiunea 1.4:
-
-1. **Coloana noua**: `VANZARI_DETALII_TEMP.CONT_VENIT VARCHAR2(4) NULL` (fara `NOT NULL`, fara
- `CHECK` — acelasi tipar ca `ACT_TEMP.SCC`). Optional, recomandat pentru trasabilitate:
- `VANZARI_DETALII.CONT_VENIT`, plus extinderea listei explicite de coloane din
- `scrie_in_vanzari` (`PACK_FACTURARE:13705-13757`, confirmat ca listeaza 24 coloane explicit, nu
- `SELECT *` — de extins cu o a 25-a daca se alege trasabilitatea).
-2. **Parametru nou pe `adauga_articol_factura`** (`ff_...:4989-5015`), la coada, dupa `V_LOT`:
- `V_CONT_VENIT IN VARCHAR2 DEFAULT NULL` — apelul VFP existent (pozitional, se opreste la
- `V_LOT`, confirmat la doua locuri, `ofacturare.vc2:14069-14091` si `:18089-18114`, doua clase
- distincte cu aceeasi metoda, nu o duplicare) ramane neschimbat, echivalent cu "trimite NULL".
- Plumbing identic cu `V_CONT`/`V_CONT2`, o coloana in plus in `INSERT INTO VANZARI_DETALII_TEMP`
- (`ff_...:5222-5282`).
-3. **`contabilizeaza_articol` insasi NU primeste parametru nou** — ramane `VANZARI_DETALII_TEMP%ROWTYPE`;
- coloana noua ajunge automat prin `SELECT * BULK COLLECT INTO tab_detalii FROM VANZARI_DETALII_TEMP`
- (`:6063`), fara nicio schimbare la cei 3 apelanti interni (`scrie_factura2`,
- `scrie_factura_avize_retur`, `scrie_aviz_retur`).
-4. **Ramura noua in `contabilizeaza_articol`**, cu garda de la sectiunea 1.4:
- - `SCC := detalii_articol.cont_venit`.
- - `SCD` (decizia 36): `PACK_SESIUNE.getoptiunefirma('FACT_SCD_ARTFPRET')`, cu fallback hardcodat
- `'4111'` cand optiunea lipseste/e goala — optiune noua in tabelul `OPTIUNI`
- (`VARTYPE='CHARACTER'`, script de migrare idempotent, tiparul exact al `RF_CONT_INCASARE_*`,
- deja folosit in acelasi pachet, `optiune_firma_cont_debit.md` sectiunea 3.4). Ramurile de aviz
- raman `'418'`/`'461'`, neschimbate.
- - `ASCD`/`ASCC` din `GetAnaliticByGrupUtilizatori(pack_facturare.nid_util, V_SCD/V_SCC)` — acelasi
- fallback deja folosit necondiionat pe ramurile de aviz azi.
- - `EXPLICATIE` din `detalii_articol.explicatia` (parametru deja existent, `V_EXPLICATIE`).
- - `ID_VENCHELT`/`ID_SECTIE` din `pack_facturare.nid_venchelt`/`nid_sectie_stoc` (fallback de
- sesiune deja folosit ca prioritate azi).
- - `IN_VALUTA` din `pack_facturare.nin_valuta` (parametru obligatoriu, fara `DEFAULT`, mereu
- curent — nu o presupunere, sursa solida).
- - `CU_TVA`: hardcodat `1`, **cu efect colateral real si masurat, nu "inofensiv"** —
- `parametru_cont_contabilizeaza_articol.md` sectiunea 2b arata ca pe combinatia specifica "linie
- fallback cu TVA 0% + discount global pe factura + acea linie e prima/singura vazuta" valoarea
- forteaza `nproc_tva_max`/`nid_jtva_coloana` pentru toata linia de discount a facturii. Ramane
- "de confirmat cu Marius", cu argumentul mai tare decat in propunerea initiala.
- - Apeluri o singura data (nu in bucla): `scrie_nota(...)`, `descarca_gestiune(...)` (garda
- identica, `nscadere_stoc=1 AND id_gestiune<>-1000 AND in_stoc=1`), discount (garda identica).
- - Articole compuse (`V_COMPUS=1`) exclus structural — o linie fara `id_pol` nu poate avea
- `ID_POL_ART`, deci intrebarea "e compus" nu se poate pune pe aceasta ramura (confirmat pe
- schema view-ului, nu presupus).
-5. **Ordinea de deploy**: DB inainte de EXE. Parametrul nou are `DEFAULT NULL`, deci EXE-ul vechi
- ruland pe DB-ul nou functioneaza neschimbat (nu trimite parametrul). EXE-ul nou ruland pe DB-ul
- vechi (fara coloana/parametru) ar esua la primul apel cu al 27-lea argument — deci EXE-ul nou
- **nu** poate merge inaintea migrarii DB. Ordine standard, fara surpriza.
-6. **Regenerarea (decizia 35)**: `initializeaza_date_factura` reseteaza starea de sesiune
- (`DELETE FROM VANZARI_DETALII_TEMP`, `nid_act := 0`) la fiecare emitere — nimic din ramura noua
- citeste vreo stare presupunand "documentul e nou". Calea Oracle e identica la regenerare, **cu o
- exceptie separata, in alt pachet**: reemiterea cu acelasi `ID_FACT` ar da azi `ORA-00001` pe
- `PK_DOCUMENTE` in `PACK_CONTAFIN.SET_IDFACT` — problema deja proiectata separat
- (`idfact_refolosire_si_documente.md`), nu intersecteaza si nu invalideaza design-ul de aici, dar
- ramane o bucata de lucru distincta, necesara pentru ca regenerarea sa fie completa.
-7. **Gol neadresat inca**: ramura `ntip = 4` ("factura din avize", `:7520-7537`) apeleaza
- `scrie_fact_aviz_custodie` in loc de `descarca_gestiune`+discount — design-ul nu specifica ce se
- intampla pe fallback aici. In practica improbabil (o linie de aviz sursa fara politica n-ar fi
- ajuns la factura pe acest drum, `adauga_articol_factura:5096` cere deja `A.ID_POL = V_ID_POL` pe
- avizul sursa), dar de exclus explicit inainte de implementare, nu de presupus tacit.
-
----
-
-## 3. Derivarea contului in VFP
-
-### 3.1 Sursele, in ordine (decizia 27)
-
-1. **Articol gestionabil** (are `id_gestiune` valid, `in_stoc=1`): `CORESP_CONT_VENCHELT.CONT_VENIT`,
- cautat pe **contul de gestiune al liniei** (`poArt.Cont`, camp deja gathered pe `poArticol` in
- ambele metode `do_scrie_articole`, confirmat la `ofacturare.vc2:12945,13835` si echivalentele in
- `frm_facturare_articole2`). Cheia de join e mereu `CONT` (nu `ID_GESTIUNE`, nu `TIP_DOC`) —
- confirmat pe 4+ consumatori Oracle reali ai tabelului (`pack_vin`, `pack_devize`,
- `gestiune_pack_gest_import`, un raport din 2026), niciodata pentru `CONT_VENIT` insa — aceasta
- propunere ar fi **primul consumator real** al coloanei, desi populata din 2023 (20 conturi de
- gestiune uzuale: 301-303/3021-3028, 331/332, 341, 345/346/348, 361, 371, 381). View-ul VFP-safe e
- `VCORESP_CONT_VENCHELT` (`STERS=0` deja filtrat in view).
-2. **Articol negestionabil**, sau gestionabil dar corespondenta nu rezolva (rand lipsa pentru acel
- `CONT`): `NOM_ARTICOLE.CONT`, **doar daca** primul caracter e `6` sau `7` (`verific_cont` nu
- restrange campul la o clasa, deci poate contine legitim orice cont valid, inclusiv 6xx/7xx pe un
- articol negestionabil).
-3. **Fallback final**: literal `'704'`. Fara reteta de cod deja scrisa in `pack_facturare` pentru
- aceasta valoare, dar cu un precedent independent de "704 = cont implicit client" in alt subsistem
- (`anaf_efactura.vc2:8376`, `cconte = 704`) — nu o inventie, dar cod nou.
-
-### 3.2 Unde sta codul si cand ruleaza
-
-Locul natural: chiar in `do_scrie_articole` (ambele clase, `frm_facturare_articole` si
-`frm_facturare_articole2`, confirmat ca 2 locuri distincte de atins, nu 1), imediat inainte de
-construirea textului RPC pentru fiecare linie, **conditionat explicit de `Empty(Nvl(poArt.id_pol,0))`**
-— nu la momentul adaugarii liniei in grid. Doua motive:
-- **Regenerarea (decizia 35)** re-parcurge toate liniile la fiecare scriere; derivarea la momentul
- scrierii (nu la adaugare) garanteaza ca valoarea reflecta starea curenta a corespondentelor/
- nomenclatorului, nu una inghetata la momentul in care linia a fost adaugata initial in grid.
-- **Conditionarea explicita pe `id_pol` gol** (nu pe "linia vine din nomenclator" ca marcaj separat)
- e chiar garda ceruta la sectiunea 1.3-1.4: o linie cu `id_pol` populat nu trebuie sa primeasca
- niciodata o valoare pe `cont_venit`, indiferent de sursa ei — un singur punct de decizie, in
- oglinda exacta cu conditia pe care Oracle o va verifica la randul lui (sectiunea 1.4).
-
-### 3.3 Ce se intampla cand derivarea esueaza
-
-- **Corespondenta nu are rand pentru acel `CONT`** (gestiune fara corespondenta configurata): cade pe
- pasul 2 (`NOM_ARTICOLE.CONT`), nu pe eroare.
-- **`NOM_ARTICOLE.CONT` nu incepe cu 6/7** (cont de gestiune sau alt tip pe un articol negestionabil,
- configurare atipica): cade pe pasul 3 (`704`), nu pe eroare.
-- **Niciodata `NULL`/gol trimis la Oracle pentru o linie "din nomenclator"** — ultimul pas e un
- literal, nu o interogare care poate esua. Aceasta e proprietatea care face garda de la 1.4
- inofensiva pe fluxul normal: `cont_venit` e *intotdeauna* populat cand `id_pol` e gol, deci
- ramura noua din Oracle ruleaza mereu cand ar trebui, iar FACT-024 (ramura veche) nu mai poate fi
- atinsa de o linie din nomenclator dupa implementare — dispare exact problema pe care povestea o
- rezolva.
-- **Nu e proiectata aici** (ramane de decis la implementare, in afara acestei povesti): daca vreo
- validare suplimentara ar trebui sa verifice ca valorile derivate (`CONT_VENIT` din corespondenta,
- `NOM_ARTICOLE.CONT`) sunt conturi valide in planul de conturi al anului curent — azi
- `verific_cont` exista ca mecanism (`oproceduri_comune.prg:2389-2415`) dar nu e cablat automat pe
- acest drum nou.
-
----
-
-## 4. Fluxul in formularul unificat
-
-1. Utilizatorul deschide un document deja emis la modificare (`frm_modific2024`/formularul unificat,
- in afara perimetrului #6/omodificari.vc2, care nu se atinge aici) si alege din meniu "Alege din
- nomenclator..." (a doua sursa, langa "Cauta in lista de preturi...", ambele reduse la acelasi
- gest UI conform S4b/S4e).
-2. Gestul UI: `Select crsfactura / APPEND BLANK` (tiparul deja in productie la
- `frm_facturare_articole2.But_nou1.do_adauga`, `ofacturare.vc2:17118-17122`), focus pe celula de
- cautare, `combosql` legat pe cursorul filtrat pe nomenclator (`caut_articol`/echivalent, fara
- coloana `id_pol` in output — confirmat, sectiunea 1.3).
-3. **`crsfactura.id_c` ramane `0`** (valoarea implicita a campului `N(20)` fara `Null`, la
- `APPEND BLANK`) — valoare pe care Oracle nu o produce niciodata pentru `id_c`. `do_sterge`
- (potriveste pe `id_c`) e no-op prin constructie pe aceasta linie, fara nicio modificare de cod —
- exact regula deja adoptata in #13, reconfirmata aici pentru sursa "nomenclator" (S4e o stabilise
- pentru sursa "lista de preturi pe comanda"; acelasi cursor de scriere `crsfactura`, acelasi
- mecanism, doar alt cursor de cautare in fata).
-4. **`crsfactura.id_pol` ramane `.NULL.`** (camp `N(20) Null`, `ofacturare_comun.prg:1775`), pentru
- ca sursa de cautare (nomenclator) nu are aceasta coloana in output — confirmat direct in aceasta
- runda (sectiunea 1.3), nu presupus.
-5. Utilizatorul completeaza cantitate/pret (campuri editabile inline pe grid, tipar deja existent).
-6. La `do_scrie_articole` (salvarea documentului), pentru fiecare linie cu `Empty(Nvl(poArt.id_pol,0))`,
- se ruleaza derivarea din sectiunea 3 si se populeaza al 27-lea argument pozitional al apelului RPC
- catre `adauga_articol_factura` cu valoarea calculata; pentru restul liniilor (cele cu `id_pol`
- populat, "din lista de preturi"), argumentul ramane `NULL` — comportament identic cu azi.
-7. Documentul se salveaza; pe Oracle, `contabilizeaza_articol` ruleaza ramura noua (sectiunea 1-2)
- pentru liniile fara politica, ramura veche neschimbata pentru restul.
-8. **Editarea** (regenerare, decizia 35): acelasi `do_scrie_articole`, aceeasi conditie pe `id_pol`,
- acelasi rezultat — nu exista o a doua cale de contare pentru liniile deja existente pe document.
-
----
-
-## 5. Ce ramane in afara (partea auto)
-
-- `tip = -12` (facturare auto, ROAAUTO) — livrat separat, dupa ce mecanismul de mai sus e stabil pe
- documentele ROAFACTURARE (ordinea deja decisa in plan).
-- "Alte servicii" din ROAAUTO ramane exceptia ei — ocoleste complet `contabilizeaza_articol`, nu
- foloseste si nu va fi migrata sa foloseasca acest mecanism ca parte a acestei povesti; daca se
- decide vreodata unificarea, e o poveste separata.
-- Gridul read-only din `frm_modific2024` (al #6) — S4g incepe dupa ce #6 se termina (decizia 30),
- nicio proiectare de aici nu presupune sau modifica acel perimetru.
-- Validarea de cantitate/stoc pentru o linie liberă la modificare (analogul sectiunii 6 din
- `s4e_lista_preturi_pe_sursa.md`, dar pentru nomenclator, nu lista de preturi) — nu re-proiectata
- aici, acelasi gol semnalat deja de S4e se aplica identic si pe sursa "nomenclator"; de rezolvat cu
- acelasi mecanism (varianta (b), reutilizare `do_verifica_articol` cu `poArticol` explicit).
-
----
-
-## 6. Teste minime
-
-Pe langa cele deja listate in `canal_cont_venit_fara_politica.md` sectiunea 6 si
-`nota_contabila_fara_politica.md`, specifice acestei povesti:
-
-1. **Factura normala cu politica, parametru NULL** — verifica ACT identic cu azi (regresie de baza).
-2. **Aviz cu articol adaugat din nomenclator (fara politica)** — `SCD` ramane `'461'`/`'418'`
- (ramurile de aviz raman hardcodate independent de ramura noua/veche), nu `getoptiunefirma`.
-3. **`ntip = 46`** (daca exista pe fluxul de modificare vizat) — `scrie_nota` nu se cheama pe acea
- ramura; de confirmat ca ramura noua nu e atinsa deloc pentru acest tip.
-4. **Articol gestionabil din nomenclator, cu corespondenta configurata** — un singur rand `ACT`,
- `SCC` = `CORESP_CONT_VENCHELT.CONT_VENIT` pentru contul de gestiune al liniei, `SCD` = optiunea
- de firma (sau `4111` daca optiunea lipseste), linie TVA scrisa separat.
-5. **Articol negestionabil din nomenclator, fara corespondenta aplicabila** — `SCC` = `NOM_ARTICOLE.CONT`
- daca incepe cu 6/7, altfel `'704'`.
-6. **Articol negestionabil** (`id_gestiune=-1000`) cu `cont_venit` populat — `descarca_gestiune` NU
- ruleaza.
-7. **Discount pe o linie din nomenclator** — foloseste `V_ASCD`/`V_CU_TVA` calculate in ramura noua.
-8. **Document in valuta** (`nin_valuta=1`) cu linie din nomenclator — `IN_VALUTA=1` pe nota,
- `SUMA_VAL` completat.
-9. **Linie fara politica si fara cont derivat** (nu ar trebui sa se poata construi prin UI, dar de
- testat direct pe Oracle) — FACT-024 tot apare, regresie negativa: garda nu s-a slabit.
-10. **Linie cu ambele populate** (construita direct la nivel de apel Oracle, nu prin UI — testeaza
- garda de la sectiunea 1.4, nu fluxul normal) — noua eroare explicita apare, nu o rezolvare
- tacita in nicio directie.
-11. **Regenerare pe un document mixt** (o linie din lista de preturi cu `id_pol`, o linie din
- nomenclator fara `id_pol`) — dupa regenerare, prima linie tot cu `SCC` din politica, a doua tot
- cu `SCC` derivat; niciuna nu trece pe ramura celeilalte.
-12. **`id_c` si `do_sterge`** (mostenit din tiparul S4e, de re-verificat pentru sursa nomenclator):
- o linie din nomenclator adaugata la modificare, apoi stearsa inainte de salvare — no-op pe
- `crsarticole`, fara efect asupra vreunei linii reale a documentului.
-
----
-
-## 7. Riscuri si de decis de Marius
-
-1. **Garda explicita pe combinatia `id_pol` + `cont_venit` ambele populate** (sectiunea 1.4) — e o
- recomandare de proiectare a acestui raport, nu o decizie deja luata de Marius; codul exact al
- erorii si numarul `FACT-0xx` raman de ales.
-2. **`CU_TVA` hardcodat `1`** — are un efect colateral masurat (nu doar teoretic), prin
- `nproc_tva_max`, pe combinatia specifica linie-scutita + discount global de factura. De confirmat
- explicit, nu de presupus inofensiv.
-3. **Decizia 36 (`SCD` prin optiune de firma)** — numele exact al cheii (`FACT_SCD_ARTFPRET` propus),
- daca se adauga validare de cont la citire (niciun precedent existent nu valideaza), si
- `PROGRAME` (restrans la ROAFACTURARE sau extins ca `RF_CONT_INCASARE_*`) raman decizii deschise
- in `optiune_firma_cont_debit.md` sectiunea 4.
-4. **Ramura `ntip=4`/"factura din avize" pe fallback** (sectiunea 2 punctul 7) — probabil imposibil
- de atins prin acest drum (avizul sursa cere deja `id_pol`), dar nu exclus explicit prin cod sau
- test — de confirmat inainte de implementare.
-5. **Suprafata de regresie in restul suitei** (ROAGEST, ROAAUTO, ROAACNPRO, ROAIMOB) pentru
- `adauga_articol_factura` — pe baza cercetarilor existente, aceste produse folosesc proceduri
- separate (`_deviz`/`_stoc`) sau alt pachet complet (`pack_acn`), deci risc asteptat zero, dar
- cautarea directa in `COMUN`-urile lor pentru un apel simplu la `adauga_articol_factura(` nu s-a
- terminat in nicio runda anterioara — de re-rulat inainte de implementare, nu de presupus incheiata.
-6. **Validarea de cantitate/stoc pentru linia libera la modificare** (sectiunea 5) — gol mostenit
- de la S4e, nu inchis aici, de rezolvat cu acelasi mecanism pe ambele surse (lista de preturi si
- nomenclator).
-7. **Trasabilitatea `CONT_VENIT` pe `VANZARI_DETALII`** (sectiunea 2 punctul 1) — optionala pentru
- ca mecanismul sa functioneze, dar fara ea coloana nu se pastreaza dupa fapt; de decis daca merita
- extinderea listei explicite de coloane din `scrie_in_vanzari`.
-8. **`idfact_refolosire_si_documente.md`** — obstacol real pentru ca regenerarea (decizia 35) sa fie
- completa (reemitere cu acelasi `ID_FACT`), in `PACK_CONTAFIN`, nu in `pack_facturare` — nu
- blocheaza design-ul de aici, dar e o bucata de lucru separata, necesara inainte ca "editare =
- regenerare" sa functioneze end-to-end.
-
----
-
-## STARE / CE RAMANE
-
-Cercetare/proiectare incheiata pentru toate cele 6 puncte cerute in brief, cu punctul central
-(sectiunea 1) tratat explicit ca decizie de proiectare (nu doar consecinta implicita a codului
-existent deja schitat in rundele anterioare). Nicio editare de cod, niciun `git_sync.ps1`/
-`txt2vcx.ps1`, niciun commit, nicio scriere pe Oracle. Context consumat moderat in aceasta runda —
-nu a fost necesara predarea de mijloc de sesiune.
-
-**Ce nu s-a putut inchide complet, de reluat separat**:
-- Cautarea exhaustiva a apelantilor `adauga_articol_factura` simplu in restul suitei (risc 5,
- sectiunea 7) — de re-rulat, nu s-a terminat in nicio runda anterioara din lipsa de timp, nu din
- cauza unei erori.
-- Confirmarea explicita a lui Marius pe hardcodarile/optiunile ramase deschise (`CU_TVA=1`, numele
- cheii de optiune, garda de la sectiunea 1.4) — sunt recomandari argumentate, nu decizii finale.
diff --git a/docs/cercetare/s5_acoperire_tipuri.md b/docs/cercetare/s5_acoperire_tipuri.md
deleted file mode 100644
index d64afd1..0000000
--- a/docs/cercetare/s5_acoperire_tipuri.md
+++ /dev/null
@@ -1,502 +0,0 @@
-# Cercetare + proiectare — S5: acoperirea tuturor tipurilor de document
-
-Proiectare pe cod, READ-ONLY (fara editari, fara `git_sync.ps1`/`txt2vcx.ps1`, fara commit, fara
-scriere pe Oracle — numai `SELECT`), pentru povestea **S5** din
-`docs\plan_13_unificare_formular_facturare.md` (`#### S5`). Nu s-a atins
-`COMUN\clase\ofacturare_comun.vc2` si `COMUN\programe\ofacturare_editare.prg` (perimetrul altei
-sarcini in lucru) — doar citite cand au aparut in cautari (n-a fost cazul).
-
-Sursa VFP: `COMUN\clase\ofacturare.vc2` (`frm_facturare_articole` = formularul de productie,
-`:10968-15739`; `frm_facturare_articole2` = prototipul, `:15741-19355` — **nu e subclasa** a
-primului, mostenesc separat din `_frmbase`, au `Init` propriu fiecare). Sursa de rutare:
-`COMUN\programe\ofacturare.prg` (`factureaza` = standard, `:81-...`; `factureaza2` = prototip,
-`:660-...`). Referinta de tipuri: `COMUN\docs\tipuri_documente_facturare.md`.
-
-## Verdict (rezumat, citeste asta primul)
-
-1. **`Do Case`-ul din `frm_facturare_articole.Init` (`ofacturare.vc2:15109-15248`) acopera 21 de
- valori de `tip`** (grupate in 14 ramuri): `1,2,3,4,5,6,7,8,9,10,21,22,23,24,25,26,28,29,41,42,47`.
-2. **Patru tipuri sunt reale, reachable prin `factureaza()`, dar nu apar in niciun `Case`** —
- pierd titlu, cap de coloana, mesaj de stoc, vizibilitate discount, eliminare `cSerie`: **`45`
- (factura restaurant), `48`/`49` (custodie cu/fara descarcare K), `52` (contract, factura fiscala
- valuta)**. Confirmat pe meniuri (`Meniuri\politica.mn2:18,26,29`, `Meniuri\contracte.mn2:18`) si
- pe rutarea cursorului (`ofacturare.prg:271-282`), care **le recunoaste** — doar Init-ul
- formularului de articole nu le-a "prins" niciodata. **Nu doar `52`**, cum semnalase raportul S4b —
- sunt patru, nu unul.
-3. **Cinci tipuri din referinta (`43,44,46,50,51`) nu sunt niciodata pasate lui `factureaza()`
- in tot arborele `D:\ROA`** (cautare exhaustiva, zero potriviri) — nu ajung la acest formular deloc
- azi. `50` e marcat explicit "in lucru" in sursa; `51` (ROAACNPRO) foloseste `id_set=50100`, un
- interval separat de restul (`25000+`), semn ca provine dintr-un flux Oracle direct al altui produs,
- nu din `factureaza()` local.
-4. **Descoperire centrala, dincolo de ce cerea misiunea**: prototipul (`frm_facturare_articole2.Init`,
- `:18988-19080`) **nu e o versiune partiala a Do Case-ului standard — e aproape gol**. Singurul
- lucru pe care-l face pe tip e sa aleaga cuvantul `lcTipDoc` ("factura" vs "aviz"), pe o lista
- **mai scurta** (lipseste `24`). Nu seteaza titlu (nu exista `lb_titlu_alb_b121` in tot fisierul
- prototipului), nu schimba capul coloanei de cantitate, nu schimba mesajul de stoc, nu ascunde
- discountul, **nu are deloc conceptul de coloana `cSerie`** (gridul prototipului, `grd_factura`,
- n-are niciodata `RemoveObject('cSerie')` — cautare pe tot fisierul, zero potriviri in intervalul
- `15741-19355`). Daca formularul unificat porneste de la prototip (cum indica decizia de baza a
- planului), **toata diferentierea pe tip trebuie reconstruita de la zero**, nu doar completata.
-5. **Rutarea cursorului diverge intre standard si prototip pe trei tipuri, nu doua**: `23`
- (confirmat deja de S4/S4b), plus **`52` si `24`, gasite aici** — pe prototip, `Case Inlist(tnTip,
- 2, 26, 6)` (`ofacturare.prg:762`) **omite `52`** fata de standard (`Inlist(tnTip, 2, 26, 6, 52)`,
- `:283`), si `Case Inlist(tnTip, 8, 9)` (`:819`) **omite `24`** fata de standard (`Inlist(tnTip, 8,
- 9, 24)`, `:307`). Daca cineva ar factura tip `52` sau `24` prin prototip azi (`gnFacturareNou=1`),
- `lcSqlCursor` ar ramane nedefinit — eroare, nu doar diferenta de comportament.
-6. **Tipurile `26` si `52` n-au niciun bookkeeping `crsarticole`** (nici Rol A, nici Rol B) —
- inchis aici punctul lasat deschis de raportul S4 punctul 2: excluderea lor din toate cele patru
- `Case`-uri de bookkeeping din `do_adauga_articol`/`do_sterge` e totala (Do Case exhaustiv, fara
- ramura implicita), nu doar "neconfirmata".
-7. **`27` si `30` raman pe calea lor** — confirmat pe cod, cu o nuanta importanta pentru `30`: nu
- e un formular separat, ci **acelasi `frm_facturare_articole`, instantiat si trecut prin acelasi
- `Init`/`Do Case`, dar niciodata aratat** (`ofacturare.prg:444-453`: calculeaza totalurile, apasa
- programatic `but_termin1.Click()`, apoi `Release()`, fara `Show()`). Tip `30` **e afectat de
- golurile din `Do Case`** exact ca oricare alt tip needitat — doar ca defectele (titlu, cap de
- coloana) nu se vad niciodata pe ecran.
-
----
-
-## 0. Metoda de verificare — lista de referinta
-
-Lista completa de tipuri vine din `COMUN\docs\tipuri_documente_facturare.md` (sursa unica, deja
-verificata pe cod de acea cercetare). Tipuri incluse in tabelul de mai jos: toate cele din sectiunile
-"Facturi" si "Avize de expeditie" (documentele care intra prin `frm_facturare_articole`/`2`).
-Sectiunea "Tipuri negative" (`-1..-13`) **nu intra in acest formular** — sunt scrise de alte produse
-(ROAGEST, ROAAUTO) prin propriile lor fluxuri, niciodata prin `factureaza()` din ROAFACTURARE
-(cautare exhaustiva `factureaza(-` in tot `D:\ROA`, zero potriviri) — declarate aici explicit **ramase
-pe calea altui produs**, nu "neacoperite".
-
----
-
-## 1. Tabelul complet, tip cu tip
-
-Coloane: `tip` = `VANZARI.TIP` · **Case propriu** = are ramura proprie in `frm_facturare_articole.Init`
-(`ofacturare.vc2:15109-15248`)? · **titlu** = ce seteaza pe `lb_titlu_alb_b121.Caption` · **cap
-cantitate** = ce seteaza pe `grd_articole.cCantitate.header1.Caption` (implicit ramane cel din
-design, `[Cantitate in stoc]`, daca nu e suprascris) · **mesaj stoc** = `This.cmesaj_cantitate` ·
-**discount** = `clb_discount.Visible` · **`cSerie`** = coloana ramane (`Da`) sau se scoate (`Nu`) ·
-**butoane** = ce se face vizibil (`but_urmator_tot1`/`but_retur`, ambele `.F.` la design) · **cursor
-standard** = ramura din `factureaza` (`ofacturare.prg:266-308`) · **cursor prototip** = ramura din
-`factureaza2` (`:748-822`, gol daca lipseste) · **Rol crsarticole** = A (cantitate ramasa de
-facturat) / B (plafon de sesiune) / — (fara bookkeeping), din `docs\cercetare\s4_punct2_registru_cantitate_ramasa.md`
-· **stare S5** = acoperit azi / gol de completat / ramas pe calea veche / neatins.
-
-### Facturi
-
-| tip | denumire | Case propriu | titlu | cap cantitate | mesaj stoc | discount | `cSerie` | butoane vizibile | cursor standard | cursor prototip | Rol | stare S5 |
-|---|---|---|---|---|---|---|---|---|---|---|---|---|
-| 1 | lista de preturi (lei) | **Da** `:15122` (grup 1,5,7,10) | — (implicit) | "Cantitate in stoc" | "nu e pe stoc!" | vizibil (implicit) | **Nu** (scoasa) | `but_retur` | `cursor_preturi` (grup 1,22,5,29,7,10,23), `:279-282` | `cursor_preturi` (grup 1,22,5,29,7,10), `:758-761` | B (gestionabil, `1,22,29`) | acoperit azi, de portat |
-| 2 | contract (lei) | **Da** `:15129` (grup 2,6) | "FACTURA PE CTR. …" | "Cantitate in stoc" | "nu e pe stoc!" | vizibil | **Nu** | — | `cursor_contract` (grup 2,26,6,52), `:283-291` | `cursor_contract` (grup 2,26,6 — **fara 52**), `:762-769` | B doar pt. `opt_facturare=0`; — pe rest | acoperit azi, de portat |
-| 3 | comanda | **Da** `:15144` | "FACTURA LA COMANDA …" | "Cantitate comandata" | "cantitate comandata facturata" | vizibil | **Nu** | `but_urmator_tot1` | `cursor_comanda` (grup 3,21,25,28,42,47), `:292-293` | `cursor_comanda` (acelasi grup), `:771-773` | **A** | acoperit azi, de portat |
-| 4 | din avize | **Da** `:15151` | "FACTURA DIN AVIZE" | — (implicit) | "cantitate de pe aviz facturata" | **ascuns** (`.F.`, `:15154`) | Da (nu se scoate) | `but_urmator_tot1` | `cursor_avize`, `:294-295` | `cursor_avize`, `:774-775` | **A** | acoperit azi, de portat |
-| 5 | lista de preturi valuta | **Da** `:15122` (grup 1,5,7,10) | — | "Cantitate in stoc" | "nu e pe stoc!" | vizibil | **Nu** | `but_retur` | `cursor_preturi` | `cursor_preturi` | — | acoperit azi, de portat |
-| 6 | contract valuta | **Da** `:15129` (grup 2,6) | "FACTURA PE CTR. …" | "Cantitate in stoc" | "nu e pe stoc!" | vizibil | **Nu** | — | `cursor_contract` | `cursor_contract` | B partial (ca 2) | acoperit azi, de portat |
-| 7 | credit note | **Da** `:15122` (grup 1,5,7,10) | — | "Cantitate in stoc" | "nu e pe stoc!" | vizibil | **Nu** | `but_retur` | `cursor_preturi` | `cursor_preturi` | — | acoperit azi, de portat |
-| 8 | retur factura lei | **Da** `:15236` (grup 8,9) | — | "Cant. max. de returnat" | "nu se mai poate returna" | vizibil | Da (nu se scoate) | `but_urmator_tot1` | `cursor_retur`, `:306-307` | `cursor_retur` (grup 8,9), `:819-820` | B (invers) | acoperit azi, de portat |
-| 9 | retur factura valuta | **Da** `:15236` (grup 8,9) | — | "Cant. max. de returnat" | "nu se mai poate returna" | vizibil | Da | `but_urmator_tot1` | `cursor_retur` | `cursor_retur` | B (invers) | acoperit azi, de portat |
-| 10 | factura fiscala valuta | **Da** `:15122` (grup 1,5,7,10) | — | "Cantitate in stoc" | "nu e pe stoc!" | vizibil | **Nu** | `but_retur` | `cursor_preturi` | `cursor_preturi` | — | acoperit azi, de portat |
-| **43** | bon fiscal magazine (ROARETAIL) | Nu | — | — | — | — | — | — | *nicio ramura* | *nicio ramura* | n/a | **neatins** — niciodata pasat lui `factureaza()` (cautat in tot `D:\ROA`); colectat de la magazine prin alt flux |
-| **44** | factura hotel | Nu | — | — | — | — | — | — | *nicio ramura* | *nicio ramura* | n/a | **neatins** — la fel, zero apeluri `factureaza(44` |
-| **45** | factura restaurant | **Nu** — lipseste din `Do Case` | **nesetat** | **nesetat** (implicit) | **nesetat** (ramane "nu e pe stoc!" default, `:15108`) | **nesetat** (ramane vizibil) | **Da, ramane** (nescoasa) | **nesetat** | `cursor_preturi`, `:275-278` | `cursor_preturi`, `:754-757` | — (exclus explicit din bookkeeping, `:12871,17178`) | **gol real de completat** — reachable din `Meniuri\politica.mn2:18` |
-| **46** | nota de plata restaurant | Nu | — | — | — | — | — | — | *nicio ramura* | *nicio ramura* | n/a | **neatins** — zero apeluri `factureaza(46`; zero documente in date de test (`tipuri_documente_facturare.md`, capcana 2) |
-| **48** | custodie cu descarcare K | **Nu** — lipseste din `Do Case` | **nesetat** | **nesetat** | **nesetat** | **nesetat** | **Da, ramane** | **nesetat** | `cursor_articole_k`, `:271-273` | `cursor_articole_k`, `:750-752` | — | **gol real de completat** — reachable din `Meniuri\politica.mn2:29` (submeniu `Marfaincus`) |
-| **49** | custodie fara descarcare K | **Nu** — lipseste din `Do Case` | **nesetat** | **nesetat** | **nesetat** | **nesetat** | **Da, ramane** | **nesetat** | `cursor_articole_k` | `cursor_articole_k` | — | **gol real de completat** — reachable din `Meniuri\politica.mn2:26` |
-| **50** | *(in lucru)* retur custodie | Nu | — | — | — | — | — | — | *nicio ramura* | *nicio ramura* | n/a | **neatins**, marcat explicit "in lucru" in `tipuri_documente_facturare.md` |
-| **51** | factura ROAACNPRO | Nu | — | — | — | — | — | — | *nicio ramura* | *nicio ramura* | n/a | **neatins** — `id_set=50100`, interval separat; probabil scris direct de ROAACNPRO, nu prin `factureaza()` local |
-| **52** | contract, factura fiscala valuta | **Nu** — lipseste din `Do Case` | **nesetat** | **nesetat** | **nesetat** | **nesetat** | **Da, ramane** | **nesetat** | `cursor_contract` (grup 2,26,6,52) | ***lipseste*** din grupul contract (`:762`) — `lcSqlCursor` nedefinit pe prototip | — (confirmat, vezi §2) | **gol real de completat** — reachable din `Meniuri\contracte.mn2:18` |
-
-### Avize de expeditie
-
-| tip | denumire | Case propriu | titlu | cap cantitate | mesaj stoc | discount | `cSerie` | butoane vizibile | cursor standard | cursor prototip | Rol | stare S5 |
-|---|---|---|---|---|---|---|---|---|---|---|---|---|
-| 21 | catre clienti, din comanda | **Da** `:15168` (grup 21,28,42,47) | "AVIZ DE EXPEDITIE DIN COMANDA" | — (implicit) | "avizata cantitatea comandata" | **ascuns** | **Nu** | `but_urmator_tot1` | `cursor_comanda` | `cursor_comanda` | **A** | acoperit azi, de portat |
-| 22 | catre clienti, din lista | **Da** `:15178` (grup 22,29) | "AVIZ DE EXPEDITIE DIN LISTA DE PRETURI" | — | "nu e pe stoc!" | **ascuns** | **Nu** | — | `cursor_preturi` | `cursor_preturi` | B | acoperit azi, de portat |
-| **23** | transfer subunitati, din lista | **Da** `:15187` | "TRANSFER INTRE SUBUNITATI" | — | "nu e pe stoc!" | **ascuns** | **Nu** | — | **`cursor_preturi`** (grup 1,22,5,29,7,10,**23**), `:279` | **`cursor_gestiune`** (grup **23**,41), `:776-778` | **B** (cod comun, indiferent de sursa) | acoperit azi, **dar sursa de cursor diverge intre forme — vezi §3** |
-| 24 | aviz retur | **Da** `:15242` | "RETUR AVIZ DE EXPEDITIE" | "Cant. max. de returnat" | "nu se mai poate returna" | (nemodificat aici) | **Nu** | `but_urmator_tot1` | `cursor_retur` (grup 8,9,**24**), `:306-307` | ***lipseste*** din grupul retur (`:819`, doar 8,9) — `lcSqlCursor` nedefinit pe prototip | B (invers) | acoperit azi, **dar prototipul n-are ramura de cursor — vezi §3** |
-| 25 | transfer subunitati, din comanda | **Da** `:15206` | "TRANSFER INTRE SUBUNITATI PE BAZA DE COMANDA" | — | "avizata cantitatea comandata" | **ascuns** | **Nu** | `but_urmator_tot1` | `cursor_comanda` | `cursor_comanda` | **A** | acoperit azi, de portat |
-| 26 | catre clienti, din contract | **Da** `:15216` | "AVIZ DE EXPEDITIE DIN CONTRACTUL …" | "Cantitate in stoc" | "nu e pe stoc!" | **ascuns** | **Nu** | — | `cursor_contract` (grup 2,26,6,52) | `cursor_contract` (grup 2,26,6 — fara 52, dar 26 e prezent) | — (confirmat, §2) | acoperit azi, de portat |
-| **27** | transfer subunitati, pe lucrare | n/a — **ramane pe calea lui** | n/a | n/a | n/a | n/a | n/a | n/a | `cursor_lucrare`, `:302-304` | `cursor_lucrare`, `:815-817` | n/a | **ramas pe calea veche** — `frm_avizare_lucrare`, confirmat §4 |
-| 28 | catre clienti debitori, din comanda | **Da** `:15168` (grup 21,28,42,47) | "AVIZ DE EXPEDITIE DIN COMANDA" | — | "avizata cantitatea comandata" | **ascuns** | **Nu** | `but_urmator_tot1` | `cursor_comanda` | `cursor_comanda` | **A** | acoperit azi, de portat |
-| 29 | catre clienti debitori, din lista | **Da** `:15178` (grup 22,29) | "AVIZ DE EXPEDITIE DIN LISTA DE PRETURI" | — | "nu e pe stoc!" | **ascuns** | **Nu** | — | `cursor_preturi` | `cursor_preturi` | B | acoperit azi, de portat |
-| **30** | transfer subunitati, pe NIR | n/a — **ramane pe calea lui, dar prin acelasi formular** | (irelevant — formular niciodata aratat) | (irelevant) | (irelevant) | (irelevant) | (irelevant) | (irelevant) | `cursor_aviz_nir`, `:299-300` | `cursor_aviz_nir`, `:813` | n/a | **ramas pe calea veche, cu nuanta** — vezi §4 |
-| 41 | retur transfer, lista pret | **Da** `:15197` | "RETUR TRANSFER" | — | "nu e pe stoc!" | **ascuns** | **Nu** | — | `cursor_gestiune`, `:296-298` | `cursor_gestiune` (grup 23,41) | **B** | acoperit azi, de portat |
-| 42 | catre clienti custodie, din comanda | **Da** `:15168` (grup 21,28,42,47) | "AVIZ DE EXPEDITIE DIN COMANDA" | — | "avizata cantitatea comandata" | **ascuns** | **Nu** | `but_urmator_tot1` | `cursor_comanda` | `cursor_comanda` | **A** | acoperit azi, de portat |
-| 47 | catre clienti custodie K, din comanda | **Da** `:15168` (grup 21,28,42,47) | "AVIZ DE EXPEDITIE DIN COMANDA" | — | "avizata cantitatea comandata" | **ascuns** | **Nu** | `but_urmator_tot1` | `cursor_comanda` | `cursor_comanda` | **A** | acoperit azi, de portat |
-| **50** | *(in lucru)* retur clienti custodie | Nu | — | — | — | — | — | — | *nicio ramura* | *nicio ramura* | n/a | **neatins**, "in lucru" |
-
-**Tipuri negative** (`-1..-13`, ROAGEST/ROAAUTO): **ramase pe calea altui produs** — nu trec
-niciodata prin `factureaza()`/`factureaza2` din ROAFACTURARE (cautare exhaustiva, zero potriviri),
-deci nu intra in perimetrul Do Case-ului acestui formular. Declarate aici explicit, nu omise.
-
----
-
-## 2. Tipurile care nu intra in niciun `Case` — inventar complet
-
-Cerinta explicita a misiunii: "nu doar 52". Lista completa, verificata pe intreg `Do Case`-ul
-(`ofacturare.vc2:15109-15248`, citit integral, nu esantion) fata de lista de referinta:
-
-**Nu apar in niciun `Case` al `frm_facturare_articole.Init`:**
-
-| tip | reachable prin `factureaza()`? | ce pierde concret |
-|---|---|---|
-| 43 | Nu (0 apeluri in tot `D:\ROA`) | irelevant — nu ajunge la acest formular |
-| 44 | Nu | irelevant |
-| **45** | **Da** (`Meniuri\politica.mn2:18`) | titlu, cap coloana cantitate, mesaj de stoc, `cSerie` nescoasa (ramane vizibila, desi tip 45 e explicit exclus din bookkeeping-ul de cantitate — cele doua lucruri nu sunt legate) |
-| 46 | Nu | irelevant — zero documente si in datele de test |
-| **48** | **Da** (`Meniuri\politica.mn2:29`, submeniu `Marfaincus`) | idem 45 |
-| **49** | **Da** (`Meniuri\politica.mn2:26`) | idem 45 |
-| 50 | Nu, "in lucru" | irelevant azi |
-| 51 | Nu (interval `id_set` separat, alt produs) | irelevant pentru acest formular |
-| **52** | **Da** (`Meniuri\contracte.mn2:18`) | titlu (ramane cel implicit al formularului), `cSerie` nescoasa, cap coloana cantitate implicit — **cel mai vizibil defect, pentru ca 2/6 (acelasi grup logic) au titlu corect** |
-
-**Concluzie**: din cele noua tipuri fara `Case`, **patru sunt reale si vizibile utilizatorului azi**
-(`45, 48, 49, 52`) — acestea sunt golul de completat cu valoare, nu doar `52`. Celelalte cinci
-(`43,44,46,50,51`) nu ajung niciodata la acest formular in fluxul curent — nu au nevoie de ramura in
-`Do Case` **pana cand** ceva le conecteaza la `factureaza()` (posibil, dar in afara perimetrului
-observabil aici; de tratat ca risc, nu ca bug, la sectiunea 10).
-
-**De ce raman "invizibile" azi cu `cSerie`/titlu implicit, nu cu eroare**: `Do Case ... Endcase` fara
-ramura `Otherwise` in VFP nu genereaza nicio eroare cand nimic nu se potriveste — pur si simplu sare
-peste tot blocul. De-asta tip 45/48/49/52 "merg" (formularul se deschide, factureaza cu succes), doar
-cu UI-ul netratat pentru cazul lor specific — un defect tacut, nu un crash, motiv probabil pentru care
-n-a fost observat/raportat pana acum.
-
----
-
-## 3. Divergentele standard vs. prototip
-
-| Aspect | Standard (`factureaza`) | Prototip (`factureaza2`) | Comportament corect de pastrat |
-|---|---|---|---|
-| **Cursor pe tip 23** | `cursor_preturi` (grup `1,22,5,29,7,10,23`, `:279`) — tratat ca lista de preturi | `cursor_gestiune` (grup `23,41`, `:776-778`) — tratat ca transfer | **`cursor_gestiune`**, impreuna cu 41 (deja stabilit de S4/S4b: transferul e o singura familie de tip, indiferent daca porneste "din lista" sau "retur"; tratarea ca lista de preturi pe standard e inconsistenta cu propriul titlu "TRANSFER INTRE SUBUNITATI" pe care tot standardul il afiseaza pentru tip 23) |
-| **Cursor pe tip 52** | prezent, grupat cu `2,26,6` (`:283`) | **absent** din grupul contract (`:762`, doar `2,26,6`) — `lcSqlCursor` ramane nedefinit daca cineva factureaza tip 52 prin prototip | **prezent**, grupat cu `2,6,26` — lipsa lui pe prototip e o eroare de portare, nu o alegere deliberata (nimic in cod sugereaza ca 52 trebuia tratat diferit de 2/6/26 la nivel de cursor) |
-| **Cursor pe tip 24** | prezent, grupat cu `8,9` (`:306-307`) | **absent** din grupul retur (`:819`, doar `8,9`) — `lcSqlCursor` nedefinit | **prezent**, grupat cu `8,9` — acelasi tip de omisiune ca la 52 |
-| **Init: diferentiere pe tip** | 14 ramuri, seteaza titlu/cap coloana/mesaj/discount/`cSerie`/butoane | practic nimic — doar `lcTipDoc` ("factura"/"aviz"), pe o lista **fara tip 24** | **toata logica standardului**, portata — prototipul nu are nimic de pastrat aici in afara de pozitia `lcTipDoc` |
-| **Coloana `cSerie`** | exista in grid prin design, se scoate condiționat (10 din 21 tipuri acoperite) | **nu exista deloc** ca si coloana in `grd_factura` (gridul unic al prototipului) | de decis explicit la proiectare (§5) — nu e o simpla portare, gridul insusi trebuie sa capete coloana |
-| **`but_urmator_tot1` (sau echivalentul lui)** | vizibil pe 9 din 21 de tipuri (§1) | nu exista conceptul in Init — prototipul nu are nimic care sa corespunda azi | de portat lista completa de vizibilitate din standard |
-| **`clb_discount.Visible`** | ascuns explicit pe toate tipurile de aviz (`21,28,42,47,22,29,23,41,25,26`) | niciodata atins in Init | de portat integral |
-
-**De ce conteaza asta pentru S5**: planul spune ca formularul unificat se bazeaza pe prototip
-(arhitectura lui: grid unic, editare inline, cautare pe server — deja deciziile S1-S4). Dar
-**diferentierea pe tip nu vine "aproape gata" din prototip** — vine aproape in intregime din
-standard, si trebuie portata, nu doar completata cu cele patru tipuri lipsa. Cele doua liste (tipuri
-lipsa din standard: 45/48/49/52; tot ce lipseste din prototip: aproape totul) sunt probleme
-**diferite**, care se rezolva **in aceeasi miscare** daca proiectarea de la §5 porneste de la o
-sursa unica de configurare portata integral din standard, cu cele patru completari incluse de la
-inceput (nu adaugate separat, dupa portare).
-
----
-
-## 4. Tipurile speciale (27, 30) — confirmate pe cod
-
-### Tip 27 — transfer pe baza de lucrare
-
-Confirmat la trei niveluri, toate in `ofacturare.prg`:
-- `Do Case tnTip = 27 -> poDate.nIdTipDoc = 6` (`:188-189`, tip document AVIZ);
-- `Do Case tnTip = 27 -> lcObiect = [frm_date_aviz_lucrare]` (`:218-219`) — **formular de antet
- diferit**, nu `frm_date_aviz`/`frm_date_factura`;
-- `Do Case tnTip = 27 -> lcObject = [frm_avizare_lucrare]` (`:386-387`) — **formular de articole
- diferit**, nu `frm_facturare_articole`. Cursorul sursa e si el propriu: `cursor_lucrare`
- (`:302-304`), populat pe `poDate.id_lucrare`, un camp pe care restul tipurilor nu-l au.
-
-**Ce il tine pe calea lui**: `id_lucrare` — o legatura pe care niciun alt tip de document n-o are
-(lucrare de service/executie, nu comanda/aviz/contract). `frm_avizare_lucrare` grupeaza gestiunile
-destinatie diferit (`crsgestiunidest`, `:388-393`, cu optiunea ``), o structura pe care
-`frm_facturare_articole`/`2` n-o au. **Formularul unificat n-ar avea `id_lucrare` si n-ar avea
-gruparea pe gestiuni destinatie** — motiv suficient sa ramana separat, confirmat pe cod, nu
-presupus.
-
-### Tip 30 — transfer pe baza de NIR
-
-**Nuanta importanta, gasita aici**: tip 30 **nu ocoleste** `frm_facturare_articole` — il
-instantiaza, exact ca orice alt tip din grupul "otherwise" (`ofacturare.prg:395`, `lcObject =
-[frm_facturare_articole]`, ramura `Else` a lui `If tnTip = 27`). Trece prin acelasi `Init`, acelasi
-`Do Case` de la `:15109-15248` (unde `30` nu are ramura proprie — ar avea aceleasi goluri ca 45/48/49
-daca ar fi vreodata aratat). Diferenta reala: **formularul nu e niciodata aratat**
-(`ofacturare.prg:444-453`):
-
-```
-IF tnTip = 30 && AVIZ DIN NIR
- ofrmdetaliifactura.do_calculeaza_totaluri()
- ofrmdetaliifactura.but_termin1.Click()
- plVizibil = .F.
- ...
-ELSE
- ...
- If plVizibil
- ofrmdetaliifactura.Show()
- Else
- ofrmdetaliifactura.Release()
- pnButon = 2
- Endif
-ENDIF
-```
-
-**Ce il tine pe calea lui**: nu structura formularului (e acelasi obiect), ci **automatizarea
-completa a fluxului** — cursorul sursa (`cursor_aviz_nir`, populat din `VRUL`/tranzactii de receptie,
-nu din comanda/lista de preturi) vine deja complet, iar codul apeleaza direct metodele de finalizare
-fara interactiune. **Pentru formularul unificat**: daca arhitectura noua pastreaza acelasi tipar
-("creeaza obiectul, populeaza, cheama finalizarea, `Release()` fara `Show()`"), tip 30 continua sa
-functioneze neschimbat — nu are nevoie de ramura in configurarea vizuala (§5), pentru ca vizualul nu
-se vede niciodata. **Singurul risc real**: daca `do_calculeaza_totaluri()`/`but_termin1.Click()` ale
-formularului unificat ajung sa citeasca vreo proprietate pe care doar `Do Case`-ul vizual o seteaza
-azi (de exemplu, un cod care ar verifica `This.cmesaj_cantitate` sau `lcTipDoc` in logica de calcul,
-nu doar in UI) — **de verificat explicit la implementare**, nu presupus ca "nu conteaza pentru ca nu
-se vede".
-
----
-
-## 5. Ce structura inlocuieste `Do Case`-ul de 140 de linii
-
-### Optiunile comparate
-
-**(a) Pastreaza `Do Case`, doar completeaza-l** (adauga ramuri pentru 45/48/49/52, porteaza restul in
-prototip). Cost minim imediat, dar **nu rezolva problema de fond**: un `Do Case` fara `Otherwise` nu
-semnaleaza niciodata un tip lipsa — exact mecanismul care a produs golul de azi (patru tipuri reale
-pierdute, ani la rand, fara nicio eroare). Orice tip nou de document adaugat in viitor (suita are deja
-`46,50` "in lucru", `43,44,51` din alte fluxuri) risca aceeasi soarta.
-
-**(b) Metoda separata per grup de tipuri** (`configureaza_lista_preturi()`, `configureaza_comanda()`,
-...). Mai clar decat un `Do Case` unic, dar tot **implicit** — un tip nou tot nu declanseaza nicio
-eroare daca nimeni nu-l adauga in metoda corecta; doar muta problema din 140 de linii intr-un fisier
-cu mai multe metode mici, fara sa adauge un mecanism de detectie.
-
-**(c) Tabel de configurare per tip (RECOMANDAT)**. Un cursor/tabel cu **un rand per `tip`**, coloanele
-fiind exact proprietatile pe care `Do Case`-ul le seteaza azi: `titlu`, `cap_cantitate`, `mesaj_stoc`,
-`discount_vizibil` (`L`), `are_serie` (`L`), `tip_doc` (`factura`/`aviz`), `buton_tot_vizibil` (`L`),
-`buton_retur_vizibil` (`L`), `grup_sursa` (pentru meniul S4b: `lista/comanda/aviz-comanda/transfer/
-retur/contract-articole/contract-rate`). Populat printr-un singur bloc de `INSERT INTO` (sau un DBF
-static, `configuratie_tip_document.dbf`, editabil fara compilare) — **un rand per tip din
-`tipuri_documente_facturare.md`**, inclusiv cele patru azi lipsa.
-
-`Init` devine:
-```
-SELECT * FROM configuratie_tip_document WHERE tip = poDate.tip INTO CURSOR crscfgtip
-If Reccount('crscfgtip') = 0
- * tip necunoscut -- eroare explicita, nu formular netratat tacut
- AMESSAGEBOX("Tip de document necunoscut in configurare: " + Transform(poDate.tip), 16, "Eroare configurare")
- Thisform.Release()
- Return
-Endif
-This.lb_titlu_alb_b121.Caption = crscfgtip.titlu
-This.grd_articole.cCantitate.header1.Caption = crscfgtip.cap_cantitate
-This.cmesaj_cantitate = crscfgtip.mesaj_stoc
-This.clb_discount.Visible = crscfgtip.discount_vizibil
-If !crscfgtip.are_serie
- This.grd_articole.RemoveObject('cSerie')
-Endif
-This.but_urmator_tot1.Visible = crscfgtip.buton_tot_vizibil
-This.but_retur.Visible = crscfgtip.buton_retur_vizibil
-```
-
-**De ce e mai bun decat (a)/(b) pe cost de intretinere**:
-- **Un tip lipsa devine o eroare vizibila la deschidere**, nu un formular netratat tacut — exact
- defectul care a permis golul de azi sa treaca neobservat ani la rand.
-- **"Cat de usor se vede un tip lipsa" e mecanic, nu vizual** — vezi §8, o interogare simpla compara
- lista de tipuri din configurare cu lista de referinta din `tipuri_documente_facturare.md`, fara sa
- ruleze formularul.
-- **Grupurile identice raman explicite, nu implicite** — azi, "tipurile 21,28,42,47 au acelasi titlu"
- se vede doar citind `Inlist(...)`; intr-un tabel, acelasi lucru se vede ca patru randuri cu aceeasi
- valoare in coloana `titlu` — usor de generat cu un singur `INSERT` per grup (`FOR EACH tip IN
- (21,28,42,47) ... INSERT ...`), nu mai putin explicit, dar auditabil cu `SELECT titlu, COUNT(*)
- GROUP BY titlu`.
-- **Coloana `are_serie` rezolva si divergenta standard/prototip de la §3** — prototipul nu are azi
- conceptul deloc; cu configurarea noua, adaugarea coloanei `cSerie` in gridul unificat devine
- conditionata de aceeasi sursa unica, indiferent de forma de baza.
-
-**Cost**: portarea initiala a ~21 de randuri (14 ramuri distincte de azi + 4 completari + grupare
-explicita), plus un nou tabel/cursor de intretinut. Nu e cod nou complex — e date, nu logica; riscul
-de regresie e in acuratetea portarii (fiecare valoare trebuie sa corespunda exact cu ce face azi
-`Do Case`-ul), verificabil linie cu linie fata de tabelul din §1.
-
-**Recomandare finala**: **(c)**, cu tabelul de configurare implementat ca `DBF` static (nu cursor
-generat in cod) — editabil de oricine fara sa recompileze, si direct verificabil cu `SELECT` fara sa
-porneasca formularul (vezi §8).
-
----
-
-## 6. Grupuri naturale de tipuri
-
-Din tabelul §1, grupurile care au azi (sau ar trebui sa aiba) valori identice pe toate coloanele:
-
-| Grup | Tipuri | Ce difera **in interiorul** grupului |
-|---|---|---|
-| **Lista de preturi, fara stoc special** | 1, 5, 7, 10 | Nimic in Init — difera doar valuta/tip document la nivel de antet (`poDate.in_valuta`, `nIdTipDoc`), nu in acest formular |
-| **Contract, factura** | 2, 6 (+ **52** de adaugat) | Nimic in Init dupa completare — `52` e valuta, ca `6`, dar cu alt `id_set`; titlul/coloanele sunt identice |
-| **Aviz din comanda (clienti/debitori/custodie)** | 21, 28, 42, 47 | Nimic in Init — difera doar destinatia comerciala (client normal/debitor/custodie), invizibila la acest nivel |
-| **Aviz din lista de preturi** | 22, 29 | Nimic — difera doar client normal/debitor |
-| **Retur facturi** | 8, 9 | Nimic — lei/valuta |
-| **Transfer subunitati** | 23, 41 | Sens (din lista vs. retur) — titlu diferit ("TRANSFER..." vs "RETUR TRANSFER"), restul identic; **trebuie unificate pe cursor** (§3) inainte de unificare vizuala |
-| **Comanda proprie** | 3 | Singur — cap de coloana propriu ("Cantitate comandata") |
-| **Avize proprii** | 4 | Singur — discount vizibil (spre deosebire de toate celelalte avize) |
-| **Aviz din contract** | 26 | Singur — titlu propriu, dar cursor comun cu grupul contract |
-| **Aviz retur** | 24 | Singur — cursor comun cu 8/9, dar titlu si `but_urmator_tot1` proprii |
-| **Custodie K** | 48, 49 | Identice ca structura vizuala (ambele lipsesc azi) — difera doar `cu`/`fara` descarcare K, invizibil la acest nivel |
-| **Restaurant** | 45 | Singur, azi lipsa |
-
-Observatie de proiectare: grupurile "aviz din comanda" (21/28/42/47) si "comanda" (3) au **acelasi**
-cap de coloana si mesaj de stoc conceptual ("cantitate comandata"), dar text usor diferit
-("facturata"/"avizata") — pastrate distincte in tabelul de configurare (nu fortate identice), pentru
-ca diferenta e deliberata in codul de azi (`:15149` vs `:15176`, verb diferit).
-
----
-
-## 7. Pasi de implementare, ordonati
-
-1. **Extrage tabelul de configurare din `Do Case`-ul standard, exhaustiv** — un rand per tip din
- `tipuri_documente_facturare.md` care intra prin acest formular (Facturi + Avize, exclus 27/30/
- negative), valorile copiate exact din §1. *Gata cand*: `SELECT DISTINCT tip FROM
- configuratie_tip_document` produce exact multimea `{1,2,3,4,5,6,7,8,9,10,21,22,23,24,25,26,28,29,
- 41,42,45,47,48,49,52}` (23 de tipuri) — nici unul in minus, nici unul in plus fata de lista
- calculata in §8.
-2. **Completeaza cele patru randuri azi lipsa (45,48,49,52)** cu valori coerente cu grupul lor logic
- (45 langa lista de preturi cu stoc dezactivat conceptual; 48/49 langa custodie K; 52 langa 2/6) —
- decizie de continut, nu doar de structura; **de validat cu Marius inainte de a le considera
- "gata"**, pentru ca azi nu exista niciun titlu/mesaj de referinta pentru ele (nimeni nu l-a vazut
- pe ecran). *Gata cand*: cele patru randuri au valori nenule pe toate coloanele obligatorii
- (`titlu`, `cap_cantitate`, `mesaj_stoc`).
-3. **Corecteaza rutarea cursorului**: `23` trece pe `cursor_gestiune` (unificat cu `41`, nu mai divide
- standard/prototip); `52` si `24` primesc ramura de cursor pe orice cale ramane vie din prototip
- (daca formularul unificat pastreaza `factureaza2`-stil, sau devine parte din calea unica daca
- `factureaza`/`factureaza2` se unesc — decizie separata, in afara acestei povesti). *Gata cand*:
- deschiderea formularului pe tip `23`, `24` si `52` prin calea noua produce acelasi continut in
- `crsarticole` ca varianta care functiona deja (`23`→prototip vechi pentru comparatie de continut,
- `24`/`52`→standard).
-4. **Adauga coloana `cSerie` in gridul unificat, condiționata pe `are_serie`** — azi absenta din
- gridul prototipului; adaugata o singura data, aratata/ascunsa din configurare, nu prin
- `RemoveObject` scris de mana pe fiecare tip. *Gata cand*: pe un tip cu `are_serie=.T.` (ex. 4)
- coloana e vizibila; pe un tip cu `are_serie=.F.` (ex. 3) nu e.
-5. **Inlocuieste `Do Case`-ul din `Init` cu citirea din configurare** (structura din §5), inclusiv
- ramura de eroare explicita pe tip necunoscut. *Gata cand*: pentru fiecare din cele 23 de tipuri,
- deschiderea formularului seteaza exact valorile din tabelul §1/pasul 2 (comparatie automata, nu
- vizuala — proprietatile sunt citibile headless).
-6. **Verifica tipurile speciale raman neatinse**: 27 (cale total separata, neschimbata), 30 (acelasi
- formular, dar `do_calculeaza_totaluri`/`but_termin1.Click()` nu citesc nimic setat doar de vechiul
- `Do Case` vizual — verificare explicita, §4). *Gata cand*: un document tip 30 de test se
- finalizeaza cu acelasi rezultat in `VANZARI`/`VANZARI_DETALII` inainte si dupa migrare.
-7. **Documenteaza tipurile neatinse (43,44,46,50,51) ca decizie explicita**, nu ca omisiune — un
- comentariu in tabelul de configurare (`* 43,44,46,50,51: neconectate la factureaza() in
- ROAFACTURARE, verificat `) ca viitorii cititori sa nu presupuna ca lipsesc din greseala.
- *Gata cand*: comentariul exista si linkeaza spre acest raport.
-
-*Depinde de*: S4 (cautarea articolelor pe server) pentru arhitectura gridului unic — pasul 4 de aici
-presupune ca gridul unificat exista deja in forma stabilita de S4; S4b (bara de butoane) pentru
-`buton_tot_vizibil`/`buton_retur_vizibil`, care alimenteaza si meniul `xmenu()` de acolo — coloanele
-`grup_sursa` din tabelul de configurare (§5) sunt exact ce cere S4b sectiunea 3.
-
----
-
-## 8. Cum se verifica ca acoperirea e completa — proba mecanica
-
-**Nu o citire — o interogare care compara doua liste.** Doua surse de adevar:
-
-1. **Lista de referinta**: tipurile din `COMUN\docs\tipuri_documente_facturare.md`, sectiunile
- "Facturi" si "Avize de expeditie", **minus** cele confirmate neatinse azi de acest formular (27, 30
- raman — vezi nuanta §4 — dar 43,44,46,50,51 se exclud daca raman neconectate; de recalculat lista
- la fiecare rulare, nu de la o constanta inghetata).
-2. **Lista din configurare** (dupa implementarea §5): `SELECT DISTINCT tip FROM
- configuratie_tip_document`.
-
-**Script de verificare** (headless, fara UI, rulabil oricand):
-
-```foxpro
-* verifica_acoperire_tip.prg — proba mecanica pentru S5
-LOCAL lnLipsa, lnInPlus
-* 1. lista de referinta -- tinuta manual sincron cu tipuri_documente_facturare.md
-* (facturi + avize, exclus negative; 27/30 raman in lista, tratate separat la pasul 3)
-DIMENSION laReferinta[23]
-laReferinta = [1,2,3,4,5,6,7,8,9,10,21,22,23,24,25,26,27,28,29,30,41,42,47,52] && + 45,48,49 dupa Pasul 2
-
-* 2. lista din configurare
-SELECT DISTINCT tip FROM configuratie_tip_document INTO CURSOR crsCfg
-
-* 3. tipuri de referinta fara configurare (exclus 27, 30 -- cale separata confirmata)
-* 4. tipuri in configurare fara corespondent in referinta (config "orfana")
-* -- ambele liste trebuie sa fie goale la "gata"
-```
-
-Alternativ, **fara sa astepte implementarea §5**: acelasi principiu se aplica azi direct pe
-`Do Case`-ul din `ofacturare.vc2:15109-15248`, extragand tipurile din fiecare `Case ... Inlist/=` prin
-`vfp_symbols.ps1 -Grep 'Case (poDate\.tip|Inlist\(poDate\.tip'` si comparand rezultatul cu lista de
-referinta — exact tehnica folosita in aceasta cercetare pentru a produce tabelul din §1 (nu o
-citire vizuala, o extractie sistematica).
-
-**Pentru cursor (rutare, §3)**: acelasi principiu, pe `ofacturare.prg`, comparand tipurile din fiecare
-`Do Case`/`Inlist` de la `:266-308` (standard) cu cele de la `:748-822` (prototip) — orice tip prezent
-intr-una si absent in cealalta e o divergenta de raportat (asa au fost gasite `52` si `24` in aceasta
-sesiune).
-
----
-
-## 9. Ce nu se poate testa headless
-
-- **Titlul, capul de coloana, mesajul de stoc ca text afisat efectiv pe ecran** — verificabile
- headless doar ca *proprietati setate* (`This.lb_titlu_alb_b121.Caption` dupa `Init()`, apelat direct
- cu un `poDate` de test), nu ca randare vizuala. Diferenta conteaza: o proprietate corect setata pe
- un control care nu exista (`lb_titlu_alb_b121` lipsa din prototip azi) ar trece "headless" fara sa
- arate nimic real — de confirmat mai intai ca ambele controale exista in formularul unificat.
-- **Coloanele de grid (`grd_articole`/`grd_factura`, coloana `cSerie` noua)** — capcana deja cunoscuta
- pe acest proiect: sub `-A -T` (rulare headless), `ColumnCount=0`/`RecordSource` raman artefacte,
- coloanele nu se materializeaza. Exista un harness UI **vizibil** care le citeste corect — orice
- verificare a `are_serie`/coloanelor trebuie sa treaca prin acela, nu prin `-A -T`.
-- **Tip 30 — fluxul complet fara `Show()`** — se poate rula headless (nu deschide nicio fereastra prin
- constructie), dar verificarea "rezultatul in Oracle e identic inainte/dupa" cere date de test reale
- (un NIR cu articole), nu doar apelul metodei.
-- **Popup-ul/dialogul viitor din S4b (`xmenu()`, `cauta_alfa`)**, daca `grup_sursa` din tabelul de
- configurare (§5/§6) ajunge sa-l alimenteze direct — mostenit ca limitare de la raportul S4b (`§8`
- de acolo): continutul `lcMeniu` verificabil ca text, popup-ul afisat nu.
-- **Comportamentul real al meniurilor `politica.mn2`/`contracte.mn2`** pentru tipurile 45/48/49/52 —
- se poate confirma ca exista intrarea de meniu (citire `.mn2`, facuta in aceasta cercetare), dar nu
- ca apasarea ei in productie deschide exact formularul asteptat, fara o rulare UI vizibila.
-
----
-
-## 10. Riscuri si ce ramane de decis de Marius
-
-1. **Continutul exact (titlu/mesaj) pentru cele patru tipuri azi netratate (45,48,49,52)** — codul nu
- ofera niciun precedent vizual (n-au fost vazute niciodata corect pe ecran), deci textele propuse in
- Pasul 2 (§7) sunt o **propunere**, nu o recuperare a unui text existent. **Recomandare**: 45 langa
- grupul "lista de preturi fara stoc" (e exclus explicit din bookkeeping de stoc, `:12871`); 48/49 cu
- titlu care mentioneaza "custodie" (singurul lucru care le distinge conceptual azi, in afara de
- coeficientul K, invizibil la acest nivel); 52 **identic cu 2/6** ("FACTURA PE CTR. ..."), pentru
- coerenta cu gruparea deja facuta corect in `frm_date_factura.Init` (`:9530,9632,9670`, grupul
- `2,6,52`).
-2. **Daca 23 trece pe `cursor_gestiune` pe calea unificata, comportamentul vizibil pentru operator se
- schimba** (sursa de articole devine stocul din gestiune, nu lista de preturi) — **decizie de produs,
- nu doar tehnica**, deja semnalata de S4/S4b, dar repetata aici pentru ca afecteaza direct §5/§7
- (tabelul de configurare trebuie sa reflecte alegerea finala, nu ambele variante). **Recomandare**:
- `cursor_gestiune`, argumentat de coerenta cu titlul "TRANSFER INTRE SUBUNITATI" pe care insusi
- standardul il afiseaza azi pentru 23 (titlul spune "transfer", cursorul azi spune "lista de
- preturi" — inconsistenta interna de rezolvat, nu de pastrat).
-3. **Daca 43,44,46,50,51 raman permanent neconectate la `factureaza()`, sau exista planuri sa fie
- activate** — nu s-a gasit nicio dovada de cod ca ar fi in curs, dar nici o confirmare ca sunt
- abandonate definitiv (in afara de `50`, marcat explicit "in lucru" in sursa). **De intrebat pe
- Marius direct**, pentru ca raspunsul schimba daca tabelul de configurare (§5) trebuie sa le includa
- preventiv sau poate ramane cu 23 de randuri.
-4. **Coloana `cSerie` pe gridul unificat — cost de adaugare** — prototipul n-are azi conceptul deloc;
- adaugarea ei presupune modificari de grid (nu doar de cod), posibil in afara perimetrului text-only
- (`.vc2`/`.sc2` prin `txt2vcx.ps1`) daca structura de coloane a gridului cere editare in IDE — **de
- confirmat la implementare**, nu presupus ca e o simpla proprietate.
-5. **Tabel de configurare ca `DBF` static vs. `INSERT`-uri in cod** — recomandarea (§5) e DBF, pentru
- editabilitate fara recompilare, dar suita foloseste azi predominant cod pentru acest fel de
- configurare (niciun precedent de DBF static de configurare gasit in `frm_facturare_articole`/
- `frm_date_factura`) — **de validat cu Marius daca abaterea de la conventia existenta merita
- beneficiul**, sau daca un cursor generat in cod (mai aproape de stilul actual, dar mai putin
- editabil) e preferat.
-
-## Handoff
-
-Cercetare + proiectare incheiata in aceasta sesiune, fara sa fie nevoie de predare de context.
-Toate cele zece sectiuni cerute de misiune sunt completate, cu `fisier:linie` verificat direct pe
-fisierele text reale (`ofacturare.vc2`, `ofacturare.prg`, nu `.bak`), plus meniurile `.mn2` si
-raportul S4/S4b/S4_punct2 citate ca sursa pentru punctele deja stabilite (nereinvestigate).
-
-Descoperiri dincolo de cerinta explicita a misiunii, semnalate clar in text: (1) patru tipuri lipsa
-din `Do Case`, nu unul (45/48/49/52, sectiunea 2); (2) prototipul (`frm_facturare_articole2.Init`)
-e aproape complet gol pe diferentiere de tip, nu doar incomplet (sectiunea 3) — cea mai mare
-descoperire a acestei sesiuni, cu impact direct asupra efortului de implementare estimat pentru S5;
-(3) doua divergente noi de rutare a cursorului (52, 24), pe langa cea deja cunoscuta (23) (sectiunea
-3); (4) tipurile 26 si 52 confirmate fara niciun bookkeeping `crsarticole`, inchizand punctul lasat
-deschis de raportul S4 punctul 2 (sectiunea 1, nota de subsol pe tabel).
-
-Niciun fisier de cod atins, niciun `git_sync.ps1`/`txt2vcx.ps1` rulat, nicio scriere pe Oracle (numai
-`Read`/`Grep`/`vfp_symbols.ps1` pe fisiere de pe disc).
diff --git a/docs/cercetare/s5b_proforma_descarcare_gestiune.md b/docs/cercetare/s5b_proforma_descarcare_gestiune.md
deleted file mode 100644
index f773c17..0000000
--- a/docs/cercetare/s5b_proforma_descarcare_gestiune.md
+++ /dev/null
@@ -1,321 +0,0 @@
-# Cercetare — Verificarea 4: descarcare de gestiune pe proforma (Oracle)
-
-Investigatie read-only, 10.08.2026. Nicio modificare de cod, niciun `git_sync.ps1`. Continua
-`docs\cercetare\proforma_copiere_puncte_intrare.md` (nu il reia) si raspunde punctual la
-"Necunoscute ramase" #1 de acolo.
-
-**Nota sursa Oracle**: `docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (mentionat in brief) nu
-exista in `docs\`. Fisierul real e la
-`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (823 337 octeti,
-confirma marimea asteptata). Am semnalat discrepanta catre team-lead prin mesaj si am continuat pe
-acest fisier — **toate citatele `PACK:linie` de mai jos sunt pe fisierul din `DATABASE`, nu pe unul
-din `docs\`**, pentru ca al doilea nu exista.
-
-## Verdict (raspuns la intrebarea 2)
-
-**NU — la emiterea unei proforme, gestiunea nu se descarca**, pentru niciun articol, indiferent daca
-articolul e cu adevarat gestionabil in nomenclator sau nu. Blocajul e prin design: VFP marcheaza
-toate liniile unei proforme "negestionabile" inainte de compunerea documentului, ceea ce le trimite
-la server cu sentinela `id_gestiune = -1000` (dedus, nu confirmat linie-cu-linie — vezi sectiunea
-"Ce nu s-a putut stabili"), iar pe Oracle `contabilizeaza_articol` sare apelul catre
-`descarca_gestiune` exact pe acest sentinel. Concluzia se sprijina si pe intentia de business
-explicita din changelog (12.03.2021 / 2.7.x): *"Proforma. Articolele din proforma sunt marcate
-'negestionabile', astfel incat nu mai este necesara existenta articolelor in stoc pentru a genera
-proforma."* — adica cerinta initiala a fost explicit "proforma trebuie sa mearga si fara stoc",
-nu doar "nu arata plafonul".
-
----
-
-## 1. Tipurile de document "proforma"
-
-Deja stabilit in `proforma_copiere_puncte_intrare.md` §1 si reconfirmat aici pe partea Oracle:
-proforma **nu** e o valoare in `TIP` (`pack_facturare.ntip`, 1-52) — e un atribut ortogonal.
-
-- **VFP**: `poDate.nIdTipDoc = 23` (fata de `5` = FACTURA), setat din combo-ul "Tip document"
- (`COMUN\clase\ofacturare.vc2:9396-9403`, `:8745-8754`). Setter-ul deriva boolean-ul
- `poDate.eProforma`: `COMUN\programe\ofacturare_comun.prg:593-599` —
- `This.eProforma = IIF(m.tnIdTipDoc = This.nIdTipDocProforma, 1, 0)`.
-- **Oracle**: nu exista `nIdTipDoc` — documentul se scrie in `VANZARI` cu `TIP` normal (business
- type, 1-52), iar `EPROFORMA` e o coloana separata pe `VANZARI`. Dovada directa:
- `PACK:5637-5671` (`PROCEDURE scrie_proforma`) — scrie intai antetul cu `scrie_in_vanzari` (acelasi
- helper ca la o factura normala), apoi:
- ```
- PACK:5666-5669
- -- completez vanzari.eproforma
- update vanzari
- set eproforma = 1
- where id_vanzare = pack_facturare.nid_vanzare;
- ```
- Deci pe Oracle, proforma **e** o factura normala in `VANZARI`/`VANZARI_DETALII`, cu un flag in
- plus.
-- Exista si un mecanism **legacy**, tabele separate `PROFORME`/`PROFORME_DETALII`
- (`PACK:5674-5767`, `PROCEDURE scrie_proforma_old` / `sterge_proforma_old`, `:5413-5429`) — nefolosit
- de fluxul curent (VFP apeleaza `scrie_proforma`, nu `scrie_proforma_old`; nu am gasit niciun apel
- VFP catre varianta `_old` in `COMUN\programe\*.prg`). Tratati ca schela moarta, nu ca mecanism activ.
-- `V_TIP = -102` in `citeste_setari_document` (`PACK:1960-1994`, ramura `:1985-1987`,
- `V_VARNAME := 'ID_FDOC_PROFORMA'`) e un cod folosit **doar** pentru alocarea de serie/numar
- (`id_fdoc`), apelat din VFP la `initializeaza_setari_document(-102)`
- (`COMUN\clase\ofacturare.vc2:9415`, deja in cercetarea anterioara) — nu are legatura cu
- `pack_facturare.ntip`, care ramane tipul de business real al documentului.
-
-## 2. Descarcarea de gestiune la proforma — DA/NU si mecanismul exact
-
-**NU.** Trasat pe trei straturi, VFP si Oracle:
-
-### 2.1 VFP: articolele devin "negestionabile" inainte sa intre pe document
-
-`COMUN\programe\ofacturare.prg:330-336` (in `factureaza`, imediat dupa incarcarea cursorului sursa
-`crsarticole`, indiferent de sursa — lista de preturi, comanda, contract, aviz, retur):
-```
-* Daca este o proforma, consider toate articolele negestionabile, pentru a nu mai alege din stoc
-* 12.03.2021
-IF poDate.eProforma = 1
- UPDATE (m.lcCursor) SET gestionabil = 0
- GO TOP IN (m.lcCursor)
-ENDIF
-```
-`gestionabil = 0` se propaga in `crsfactura` prin `prelucreaza_facturacrs`
-(`COMUN\programe\ofacturare_comun.prg:1801-1810`, coloana `gestionabil` e in lista de INSERT).
-
-La adaugarea/editarea unei linii pe formular, ramura pe `gestionabil` decide dialogul:
-`COMUN\clase\ofacturare.vc2:13803-13809`:
-```
-Case (poArticol.gestionabil = 0 Or gnScadereStoc = 0 Or poDate.tip = 45) && 45 = ROARESTAURANT
- ofrmadarticol = Createobject("frm_articol_factura", lnCantitateMax, .F.)
-```
-adica **acelasi dialog folosit pentru orice articol negestionabil in restul aplicatiei** (nu unul
-proforma-specific), care ocoleste `do_alege_stoc` (dialogul de alegere lot din stoc). Pentru
-articolele care intra pe `frm_articol_factura`, `id_gestiune` implicit e sentinela `-1000`
-(`COMUN\clase\ofacturare.vc2:13618-13623`, `do_initializeaza_articol`:
-`If Type('toArticol.id_gestiune') = "U" THEN AddProperty(toArticol,'id_gestiune',-1000)`; acelasi
-tipar la `:17836-17837`). La scriere, `poArt.id_gestiune` se trimite direct ca parametru
-`V_ID_GESTIUNE` catre `pack_facturare.adauga_articol_factura`
-(`COMUN\clase\ofacturare.vc2:14069-14073`: `... + Nvl(Alltrim(Str(poArt.id_gestiune)),[NULL]) + ...`).
-
-### 2.2 Oracle: `id_gestiune = -1000` e sentinela care blocheaza descarcarea
-
-`adauga_articol_factura` (`PACK:4989-5284`), primeste `V_ID_GESTIUNE` si il traduce:
-```
-PACK:5032-5034
-IF V_ID_GESTIUNE <> -1000 THEN
- V_ID_GESTIUNE2 := V_ID_GESTIUNE;
-END IF;
-```
-`V_ID_GESTIUNE2` (necompletat, deci `NULL`, cand `V_ID_GESTIUNE = -1000`) e cel scris efectiv in
-`VANZARI_DETALII_TEMP.ID_GESTIUNE` (`PACK:5237,5267`).
-
-La emitere, `contabilizeaza_articol` (`PACK:7173-7547`) parcurge liniile din
-`VANZARI_DETALII_TEMP` si apeleaza `descarca_gestiune` doar aici:
-```
-PACK:7472-7476
-IF pack_facturare.ntip <> 4 THEN
- IF pack_facturare.nscadere_stoc = 1 AND
- detalii_articol.id_gestiune <> -1000 AND
- detalii_articol.in_stoc = 1 THEN
- pack_facturare.descarca_gestiune(...)
-```
-`NULL <> -1000` evalueaza la `NULL` in PL/SQL (nu `TRUE`), deci conditia pica indiferent de
-`in_stoc` — **liniile de pe o proforma nu ajung niciodata la `descarca_gestiune`**, cata vreme
-`id_gestiune` a intrat ca `-1000`.
-
-Exista si o a treia bariera, independenta, **in interiorul** lui `descarca_gestiune`
-(`PACK:7648-7797`), dar aceasta priveste articolul insusi, nu documentul:
-```
-PACK:7789-7797
--- NU SE DESCARCA GESTIUNEA PENTRU ARTICOLELE NEGESTIONABILE
--- ASTFEL INCAT SA SE POATA FACE OPERATII GEN AVIZ DIN CUSTODIE INCLUSIV CU ARTICOLE NEGESTIONABILE
-SELECT MAX(IN_STOC) INTO lnInStoc FROM NOM_ARTICOLE WHERE ID_ARTICOL = V_ID_ARTICOL;
-IF lnInStoc = 0 THEN GOTO SFARSIT; END IF;
-```
-Aceasta verifica `NOM_ARTICOLE.IN_STOC` real (nomenclator), nu flagul de proforma — protejeaza un
-articol cu adevarat negestionabil, indiferent de tipul documentului. **Nu** e mecanismul care
-protejeaza proforma; mecanismul de proforma e strict gate-ul `id_gestiune <> -1000` de la 2.1-2.2.
-
-### 2.3 `in_stoc` trimis de VFP: uneori ignorat de Oracle, dar nu e el gate-ul decisiv
-
-`V_IN_STOC_TEMP` (parametrul care ajunge in `VANZARI_DETALII_TEMP.IN_STOC`) e **fie** preluat direct
-de la VFP (`V_IN_STOC := V_IN_STOC_TEMP`, ramurile implicita si restaurant, `PACK:5200-5203,
-5111-5112`), **fie recalculat de Oracle din nomenclator/contract**, ignorand ce a trimis VFP, pe
-ramurile comenzi (`PACK:5061-5066`), avize (`:5086-5091`) si contract cu pret de contract
-(`:5153-5158, 5184`). Asta inseamna ca pentru o proforma facuta din comanda/aviz/contract, campul
-`IN_STOC` scris efectiv poate reveni la valoarea reala din nomenclator (`1` pentru un articol
-gestionabil), **dar** asta nu conteaza — gate-ul din 2.2 cere `id_gestiune <> -1000 AND in_stoc = 1`
-cu **AND**, iar `id_gestiune` ramane blocat la `-1000`/`NULL` indiferent de sursa documentului
-(sentinela vine din UI, la nivelul liniei, nu din cursorul de incarcare). Deci recalcularea lui
-`in_stoc` de catre Oracle pe aceste ramuri nu redeschide descarcarea.
-
-## 3. De la proforma la factura
-
-Nu exista o rutina de "transformare" dedicata — mecanismul e **copierea**, deja documentata complet
-in `proforma_copiere_puncte_intrare.md` §2 (tooltip explicit `COMUN\clase\ofacturare_comun.vc2:1409`:
-*"Se foloseste si pentru generarea unei facturi din proforma prin copiere"*).
-
-- **Punct de intrare VFP**: `frm_facturi.But_copiaza1.Click -> do_copiaza` (degradeaza tipul de
- business, `COMUN\clase\ofacturare_comun.vc2:3628-3713`) `-> copiere_factura`
- (`COMUN\programe\oproceduri_facturare.prg:150-153`) `-> factureaza(tip_degradat, toFactura)`.
-- **Punct de intrare Oracle**: acelasi `pack_facturare.adauga_articol_factura` / `scrie_in_vanzari`
- ca la orice document nou — nu exista un `pack_facturare.transforma_proforma` sau echivalent.
- Singurul apel Oracle specific copierii e cursorul de precompletare,
- `pack_facturare.cursor_retur_document` (vezi §4), apelat cu `V_COPIERE = 1`
- (`COMUN\programe\ofacturare.prg:267-268`).
-- `completeaza_setari_document(toDateAnterior, .T.)` (`COMUN\programe\ofacturare_comun.prg:362-412`)
- **nu propaga `nIdTipDoc`** (linia comentata, `:370`) — documentul nou porneste cu `nIdTipDoc`
- implicit (`5`=FACTURA sau `6`=AVIZ, dupa `tnTip` degradat, `COMUN\programe\ofacturare.prg:187-196`),
- deci **`poDate.eProforma = 0` pentru documentul nou**, indiferent ca sursa era proforma.
-
-## 4. Ce se intampla cu stocul intre proforma si factura
-
-**Nimic de reconciliat, pentru ca proforma nu a atins niciodata stocul** (§2). Nu exista concept de
-"rezervare de stoc" pe proforma:
-- tabelele legacy `PROFORME`/`PROFORME_DETALII` (§1) nu au coloane de rezervare si oricum nu sunt pe
- calea activa;
-- nu am gasit, in `PACK_FACTURARE`, niciun apel care sa insereze in `RUL` sau sa actualizeze
- `STOC` la `scrie_proforma` — funcita se limiteaza la `scrie_in_vanzari` + `UPDATE vanzari SET
- eproforma=1` (§1, `PACK:5637-5671`);
-- cautare directa in fisierul PACK pentru orice mentiune de rezervare pe proforma (`rezerv`,
- `blocheaza stoc`) nu a dat rezultate relevante (v. "Ce nu s-a putut stabili" pentru limitele
- cautarii text simple pe un fisier de 823 KB).
-
-**La copiere (transformarea efectiva in factura)**, gestionabilitatea reala se **restaureaza**:
-cursorul de precompletare la copiere, `cursor_retur_document`
-(`PACK:3949-4000`), calculeaza `GESTIONABIL` asa:
-```
-PACK:3993-4000
-(case
- when V_PROFORMA = 1 then 0
- when V_COPIERE = 1 then B.IN_STOC -- NOM_ARTICOLE.IN_STOC, articolul real
- else A.GESTIONABIL
- end) AS GESTIONABIL,
-```
-La copiere, `V_COPIERE = 1` e hardcodat (`COMUN\programe\ofacturare.prg:267-268`:
-`cursor_retur_document(?poDate.in_valuta,?poDate.listaid,1,?poDate.eProforma,?gnIdUtil)` — al treilea
-parametru pozitional `1` e `V_COPIERE`), iar `V_PROFORMA` trimis e `poDate.eProforma` **al
-documentului nou**, care e `0` (§3) — deci ramura `V_PROFORMA=1` nu se activeaza la copiere, si
-`GESTIONABIL = B.IN_STOC` (flagul real din nomenclator). Rezultat: liniile copiate dintr-o proforma
-redevin gestionabile normal daca articolul chiar e in stoc, trec prin `do_alege_stoc` la editare
-(`ofacturare.vc2:13804`, ramura `Otherwise`), primesc un `id_gestiune` real, si **descarcarea de
-gestiune se face normal la emiterea facturii rezultate din copiere** — exact ca la orice factura noua,
-nu printr-un pas separat de "transformare".
-
-## 5. Ce verifica serverul la descarcare, si cu ce eroare
-
-Verificari observate direct in `PACK_FACTURARE`, toate independente de proforma (se aplica oricarei
-descarcari reale de gestiune):
-- **Gestiune inexistenta/stearsa**: `PACK:7847-7858` — `SELECT ... FROM NOM_GESTIUNI WHERE
- ID_GESTIUNE = V_ID_GESTIUNE AND STERS = 0`; `NO_DATA_FOUND -> FACT-007`.
-- **Stoc epuizat / lot inexistent**: `PACK:7860-8493` — construieste `tab_stoc` din `RUL`/`STOC` dupa
- criterii (articol, gestiune, cont, serie, pret etc.) si, daca nu gaseste nimic
- (`SQL%ROWCOUNT = 0`): `FACT-008` ("Articolul ... nu mai e in stoc") sau, daca nici macar
- denumirea nu se gaseste, `FACT-009`.
-- Ramuri similare mai jos in acelasi fisier pentru alte cazuri de gestiune/combinatii invalide:
- `FACT-010` (`:10001`), `FACT-011` (`:10323`), `FACT-014` combinatie invalida de gestiuni
- (`:12127`), `FACT-019` gestiune (`:10449`), `FACT-020`/`FACT-021` variante "nu mai e in stoc"
- (`:10748,10752`).
-- **Optiune globala de bypass**: `RF_FACTURARE_FARA_STOC` (`PACK:7783-7784`,
- `lnFacturareFaraStoc`) — permite facturarea peste cantitatea disponibila pentru articole
- gestionabile; **nu e specifica proformei**, e o optiune de firma generala.
-- **Cota TVA lipsa / articol fara politica de pret** — nu sunt verificari de stoc, dar sunt cele mai
- frecvente erori vecine (`FACT-024` la `contabilizeaza_articol`, `PACK:7278-7302`; `FACT-018`,
- `FACT-012`, `FACT-013` la cautarea cotei TVA in `adauga_articol_factura`, deja semnalate in
- `plan_13_unificare_formular_facturare.md` §G). O proforma cu `id_gestiune=-1000` **nu trece deloc**
- prin verificarile de stoc de mai sus (FACT-007/008/009/010/011/014/019/020/021), pentru ca nu ajunge
- la `descarca_gestiune` — dar tot trece prin verificarea de politica de pret / cota TVA, care nu are
- legatura cu stocul.
-
-## 6. Consecinte pentru S5b — constrangeri de proiectare
-
-1. **Formularul unificat trebuie sa reproduca exact mecanismul `gestionabil=0` la incarcarea
- liniilor cand `poDate.eProforma = 1`** — nu doar sa ascunda vizual plafonul. Fara acest pas,
- articolele gestionabile ar intra pe document cu `id_gestiune` real si ar declansa
- `descarca_gestiune` la emitere, contrazicand comportamentul de azi si cerinta de business
- ("proforma merge fara stoc").
-2. **Nu se apeleaza `do_alege_stoc` (dialogul de alegere lot) pentru liniile unei proforme.** Traseul
- corect e cel al articolului negestionabil (`frm_articol_factura`/`do_initializeaza_articol`), care
- garanteaza `id_gestiune = -1000` pe linie.
-3. **`id_gestiune = -1000` trebuie sa ajunga efectiv in parametrul `V_ID_GESTIUNE` trimis catre
- `pack_facturare.adauga_articol_factura`** — verificarea de gate e strict pe aceasta valoare
- (`<> -1000`), nu pe un flag de document. Daca formularul unificat schimba felul in care
- construieste liniile (de ex. reutilizeaza un obiect de linie comun facturii si proformei), acest
- `-1000` trebuie sa fie explicit setat pe ramura `eProforma=1`, nu mostenit implicit.
-4. **`in_stoc`/`gestionabil` trimis de VFP nu e suficient de la sine** — pe unele surse (comanda,
- aviz, contract cu pret de contract) Oracle il **rescrie** din nomenclator/contract (§2.3). Gate-ul
- real e `id_gestiune`, deci formularul unificat nu poate conta pe faptul ca a trimis `in_stoc=0`;
- trebuie sa garanteze `id_gestiune=-1000`.
-5. **La copiere proforma -> factura, comportamentul trebuie sa fie opus**: liniile trebuie sa-si
- recapete gestionabilitatea reala (`B.IN_STOC` din nomenclator), nu sa ramana blocate la
- negestionabil. Decizia deja luata in plan ("degradarea de tip din `do_copiaza` ramane pentru
- copiere si nu se aplica la regenerare") e consistenta cu asta, dar merita spus explicit: **regula
- `eProforma=1 -> gestionabil=0` se aplica doar la incarcarea/compunerea unei proforme noi, nu si la
- copierea din ea** — documentul nou pleaca cu `eProforma=0` (§3-4) si trebuie sa lase Oracle sa
- recalculeze `GESTIONABIL` normal.
-6. **Formularul unificat nu trebuie sa implementeze nicio logica de "eliberare stoc rezervat" la
- trecerea proforma -> factura** — nu exista rezervare de stoc pe proforma (§4), deci nu exista
- nimic de eliberat. Riscul tehnic real ramane cel deja semnalat in plan §G (ordinea
- stergere-inaintea-reemiterii in aceeasi tranzactie la regenerare), care e independent de proforma.
-7. **Verificarile de stoc (`FACT-007/008/009/010/011/014/019/020/021`) nu se vor manifesta niciodata
- pentru o linie de proforma** cata vreme regula #1-#3 e respectata — formularul unificat nu are
- nevoie de tratament special pentru aceste coduri de eroare pe ramura proforma (nu pot aparea
- acolo), dar tot trebuie sa trateze erorile de politica de pret/TVA (`FACT-012/013/018/024`), care
- raman valabile si pe proforma.
-
-## 7. Copierea proformei in formularul unificat — ce lipseste
-
-Plecand de la `proforma_copiere_puncte_intrare.md` §2 (traseul general de copiere, deja complet
-documentat) si de la S5b din plan (`plan_13_unificare_formular_facturare.md:1674-1689`):
-
-- **Ce exista deja si se reutilizeaza neschimbat**: `do_copiaza` (degradarea de tip),
- `copiere_factura`, `factureaza(tip, toFactura)`, `completeaza_setari_document`,
- `cursor_retur_document` cu `V_COPIERE=1`. Niciunul din aceste puncte de intrare nu are legatura
- speciala cu proforma dincolo de parametrul `V_PROFORMA` deja tratat corect (§4) — nu trebuie
- adaugat nimic nou aici pentru ca formularul unificat sa suporte copierea unei proforme.
-- **Ce lipseste, specific formularului unificat, nu copierii in sine**: mecanismul `crsarticole`
- intreg (incarcarea de masa + `UPDATE ... SET gestionabil=0`, §2.1) presupune un cursor complet
- incarcat inainte de afisare. Planul (`plan_13_unificare_formular_facturare.md:1470`) stabileste deja
- ca `crsarticole` **nu se mai incarca in masa** in formularul unificat — deci pasul "seteaza
- gestionabil=0 pe toate liniile cand eProforma=1" **trebuie reimplementat linie-cu-linie**, la
- momentul in care fiecare linie e adaugata pe formularul unificat (fie la copiere, fie la compunere
- noua), nu ca un singur `UPDATE` de masa pe un cursor care nu mai exista. Constrangerea #1-#3 de mai
- sus (sectiunea 6) e exact specificatia acestui pas lipsa.
-- **Combo-ul de tip document si realocarea de serie** — deja acoperite de decizia S5b din plan
- (`Ct_clb_fdoc` ramane, realocare la comutare); nu am gasit nimic suplimentar de adaugat aici fata
- de ce e deja scris in plan.
-
-## Ce nu s-a putut stabili
-
-1. **Linia exacta unde `poArt.id_gestiune` devine efectiv `-1000` pentru o linie de proforma**, in
- loc de a ramane la valoarea implicita de camp (`0`, cursorul `crsfactura` creat cu `id_gestiune
- N(20)` fara `NULL`, iar `prelucreaza_facturacrs` nu include `id_gestiune` in lista sa de INSERT —
- `COMUN\programe\ofacturare_comun.prg:1801-1810`). Am gasit sentinela `-1000` setata **conditionat**
- ("daca proprietatea lipseste") in `do_initializeaza_articol`
- (`COMUN\clase\ofacturare.vc2:13618-13623`), dar nu am confirmat ca proprietatea chiar "lipseste"
- (`Type = 'U'`) in momentul in care `frm_articol_factura` proceseaza o linie de proforma provenita
- din `Scatter` pe `crsfactura`. **Argument indirect, nu dovada directa**: daca `id_gestiune` ar
- ajunge `0` (nu `-1000`) la server, `descarca_gestiune` ar cauta `NOM_GESTIUNI WHERE ID_GESTIUNE=0`
- si ar arunca `FACT-007` la fiecare emitere de proforma cu articol gestionabil din comanda/aviz —
- eroare care ar fi vizibila si raportata de ani (proforma exista din 2014+ in changelog); absenta
- oricarei asemenea raportari sustine indirect ca sentinela `-1000` chiar ajunge la server, dar nu e
- o dovada pe cod.
-2. **Nicio verificare pe date vii** — tot ce e mai sus e trasare de cod static (VFP text + PL/SQL
- text), nu rulare/log real. Nu am rulat nimic, conform mandatului read-only.
-3. **Cautarea de "rezervare de stoc pe proforma"** (§4) s-a facut prin grep text simplu pe
- `PACK_FACTURARE` dupa cuvinte cheie (`rezerv`, `PROFORMA`) — nu e o dovada de completitudine
- pentru intreaga baza de date Oracle (declanșatoare/triggere pe `VANZARI`/`VANZARI_DETALII`,
- proceduri din alte pachete). Zero rezultate nu inseamna cu certitudine ca nu exista niciun
- mecanism de rezervare in alta parte a schemei.
-4. **Fisierul `docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`** nu a fost creat de mine — am lucrat
- pe originalul din `DATABASE\SCRIPTURI_CLAR`. Daca cineva copiaza ulterior fisierul in `docs\` cu
- alta numerotare de linii, citatele `PACK:linie` din acest raport trebuie re-verificate pe copia
- noua.
-
-## Verificari recomandate pe date vii (daca raman intrebari)
-
-- Emis o proforma de test cu un articol **cu adevarat gestionabil si cu stoc real**, sursa = comanda
- (ramura unde Oracle rescrie `IN_STOC`, §2.3) — confirma ca `RUL`/`STOC` nu se modifica dupa emitere
- si ca `VANZARI_DETALII.ID_GESTIUNE` a fost scris `NULL` pentru acea linie.
-- Acelasi test, sursa = lista de preturi (ramura unde Oracle are incredere in `V_IN_STOC_TEMP`) —
- pentru comparatie.
-- Copiaza proforma de mai sus in factura si confirma ca `VANZARI_DETALII.ID_GESTIUNE` al facturii
- rezultate e populat cu o gestiune reala si ca `RUL` inregistreaza descarcarea la emiterea facturii.
-- Interogare directa pe schema pentru triggere/joburi legate de `EPROFORMA` sau de rezervare de stoc,
- daca exista suspiciunea din punctul 3 de mai sus:
- `SELECT trigger_name, table_name FROM user_triggers WHERE table_name IN ('VANZARI','VANZARI_DETALII','STOC','RUL');`
diff --git a/docs/cercetare/s5b_proiectare_proforma_copiere.md b/docs/cercetare/s5b_proiectare_proforma_copiere.md
deleted file mode 100644
index cc39bd6..0000000
--- a/docs/cercetare/s5b_proiectare_proforma_copiere.md
+++ /dev/null
@@ -1,610 +0,0 @@
-# Proiectare S5b — proforma si copierea pe formularul unificat
-
-Cercetare + proiectare READ-ONLY (fara editari de cod, fara `git_sync.ps1`/`txt2vcx.ps1`, fara
-commit, fara scriere Oracle — numai `SELECT`), pentru povestea **S5b** din
-`docs\plan_13_unificare_formular_facturare.md` (sectiunea `#### S5b`, liniile 2507-2530), deciziile
-10 si 11. Continua, fara sa reia, `docs\cercetare\s5b_proforma_descarcare_gestiune.md` (sursa de
-adevar pentru mecanismul `gestionabil=0` / `id_gestiune=-1000`) si foloseste rezultatele din
-`docs\cercetare\s4e_lista_preturi_pe_sursa.md` (coliziunea `id_c`) si
-`docs\cercetare\s4_punct2_registru_cantitate_ramasa.md` (Rol A/B ale `crsarticole`).
-
-**Status: cercetare + proiectare incheiate.**
-
-Nu se ating `COMUN\clase\ofacturare_comun.vc2` si `COMUN\programe\ofacturare_editare.prg`
-(perimetrul altei sarcini). `COMUN\programe\ofacturare.prg` si `ofacturare_comun.prg` sunt citite,
-nu editate — la fel `COMUN\clase\ofacturare.vc2` si `COMUN\clase\ofacturare_comun.vc2` (citire, nu
-editare; scriere interzisa doar pe al doilea).
-
----
-
-## Descoperire centrala, care rescrie premisa de risc a lui S5b
-
-Sursa de adevar anterioara (`s5b_proforma_descarcare_gestiune.md`) a stabilit ca gate-ul pentru
-proforma e sentinela `id_gestiune = -1000`, verificata **in interiorul** lui
-`contabilizeaza_articol` (`PACK:7472-7476`). Cercetarea de fata a gasit un strat **mai devreme si
-mai tare**: la `Termina`, `do_scrie_factura` **alege intre doua proceduri Oracle diferite** dupa
-`poDate.eProforma`, inainte sa se uite la `poDate.tip` (`COMUN\clase\ofacturare.vc2:14282-14300`):
-
-```
-Do Case
- Case poDate.eProforma = 1
- * scrie_proforma are aceiasi parametri ca scrie_factura2
- * salveaza doar in vanzari, nu si in contabilitate
- lcSql = [{call pack_facturare.scrie_proforma(...)}]
- Case poDate.Tip = 4
- ... lcSql = [{call pack_facturare.scrie_factura_avize(...)}]
- Case Inlist(poDate.Tip,3,21,25,28,42,47)
- ... lcSql = [{call pack_facturare.scrie_factura2(...)}]
- Otherwise
- ... lcSql = [{call pack_facturare.scrie_factura2(...)}]
-Endcase
-```
-
-Comentariul din cod ("salveaza doar in vanzari, nu si in contabilitate") e literal adevarat, verificat
-pe corpul Oracle: `pack_facturare.scrie_proforma` (`PACK:5637-5671`) cheama **doar**
-`scrie_in_vanzari` (`PACK:13488-13760`) — care face `INSERT INTO VANZARI` (antet) **si**
-`INSERT INTO VANZARI_DETALII ... SELECT FROM VANZARI_DETALII_TEMP` (liniile, cu `ID_GESTIUNE` asa
-cum a ajuns in `TEMP`) — apoi marcheaza `VANZARI.EPROFORMA=1`. **`scrie_proforma` nu cheama
-niciodata `contabilizeaza_articol`.** `scrie_factura2`/`scrie_factura_avize`/`scrie_aviz_retur` sunt
-singurele trei proceduri care cheama `contabilizeaza_articol` (confirmat si in
-`docs\plan_13_unificare_formular_facturare.md:298-310`, runda 11) — si niciuna din ele nu ruleaza
-pentru `eProforma=1`.
-
-**Consecinta:** pentru o proforma, `scrie_nota` (care scrie `NOTE_CONTABILE`) si `descarca_gestiune`
-nu ruleaza **deloc** — nu pentru ca sentinela `-1000` le blocheaza pe fiecare linie (desi si asta
-ramane adevarat, ca plasa suplimentara), ci pentru ca **intreaga functie care le cheama nu se
-executa**. Sentinela `-1000` din `contabilizeaza_articol` conteaza doar cand `contabilizeaza_articol`
-chiar ruleaza — adica exact pe drumul invers (vezi sectiunea 5), nu pe proforma insasi.
-
-**De ce conteaza pentru S5b**: alegerea `scrie_proforma` vs. `scrie_factura2` se face **o singura
-data, la Termina**, citind `poDate.eProforma` **in acel moment** — nu depinde de cand/cum a fost
-comutat combo-ul, nici de valorile `gestionabil`/`id_gestiune` de pe liniile individuale. Asta e o
-veste buna pentru un sens al comutarii (proforma -> ramane proforma la salvare: corect, indiferent ce
-au liniile), dar **nu acopera** sensul opus (liniile marcate negestionabil sub proforma, apoi
-documentul comutat inapoi la factura inainte de Termina) — acolo `scrie_factura2` **chiar** ruleaza,
-si atunci sentinela `-1000` de pe liniile ramase de la proforma **chiar blocheaza** `descarca_gestiune`
-pe un document care ar trebui sa descarce. Vezi sectiunea 5.
-
----
-
-## 1. Fluxul de azi al proformei, cap-coada
-
-**1.1 Alegerea tipului.** Proforma nu e o valoare in `pack_facturare.ntip` (tipul de business,
-1-52) — e un atribut ortogonal, `poDate.nIdTipDoc` (5=FACTURA, 23=PROFORMA, 3=BON FISCAL,
-6=AVIZ), setat din combo-ul "Tip document" (`Ct_clb_fdoc._combobox1`,
-`RowSource = "FACTURA,PROFORMA,BON FISCAL"`, `ofacturare.vc2:8745-8754`). Setter-ul
-`nIdTipDoc_Assign` (`COMUN\programe\ofacturare_comun.prg:593-600`) deriva boolean-ul in acelasi
-moment: `This.eProforma = IIF(m.tnIdTipDoc = This.nIdTipDocProforma, 1, 0)`.
-
-**1.2 Marcarea in masa la incarcarea cursorului.** In `factureaza()` (`COMUN\programe\ofacturare.prg`),
-dupa ce cursorul sursa (indiferent care — lista de preturi, comanda, contract, aviz, retur) e adus in
-`crsarticole` (Do Case pe `tnTip`, `:266-311`), **daca** `poDate.eProforma = 1`, se face un `UPDATE`
-de masa peste tot cursorul (`:330-334`):
-```
-* Daca este o proforma, consider toate articolele negestionabile, pentru a nu mai alege din stoc
-IF poDate.eProforma = 1
- UPDATE (m.lcCursor) SET gestionabil = 0
- GO TOP IN (m.lcCursor)
-ENDIF
-```
-Acest pas ruleaza **o singura data**, la incarcare, **inainte** ca formularul de linii sa se
-deschida — pentru ca la momentul lui `poDate.eProforma` e deja finala: combo-ul traieste in
-`frm_date_factura`/`frm_date_aviz`, un dialog modal care se **inchide** (`ofrmceredate.Show()` la
-`:235`, urmat de `Release ofrmceredate` la `:248`) **inainte** ca `Do Case`-ul de incarcare a
-cursorului sa ruleze (`:266` e dupa `:248`). Tipul nu se mai poate schimba dupa acest punct, azi.
-
-**1.3 Ce face `gestionabil=0` la nivel de linie.** Cand operatorul adauga o linie, ramura care alege
-dialogul citeste exact acest camp (`ofacturare.vc2:13803-13809`):
-```
-Do Case
- Case (poArticol.gestionabil = 0 Or gnScadereStoc = 0 Or poDate.tip = 45)
- ofrmadarticol = Createobject("frm_articol_factura", lnCantitateMax, .F.)
- Otherwise
- Thisform.do_alege_stoc(...)
-Endcase
-```
-`frm_articol_factura` e dialogul generic pentru orice articol negestionabil din toata aplicatia
-(nu unul specific proformei) — ocoleste `do_alege_stoc` (alegerea lotului din stoc).
-`do_initializeaza_articol` (`ofacturare.vc2:13618-13623`) seteaza `id_gestiune=-1000` **doar daca
-proprietatea lipseste** pe obiectul articol (`Type(...) = "U"`):
-```
-If Type('toArticol.id_gestiune') = "U"
- AddProperty(toArticol,'id_gestiune',-1000)
-Endif
-```
-La scriere, `poArt.id_gestiune` merge direct ca `V_ID_GESTIUNE` catre
-`pack_facturare.adauga_articol_factura` (`ofacturare.vc2:14069-14073`), care il traduce
-(`PACK:5032-5034`: `IF V_ID_GESTIUNE <> -1000 THEN V_ID_GESTIUNE2 := V_ID_GESTIUNE; END IF;` —
-altfel ramane `NULL`), scris in `VANZARI_DETALII_TEMP.ID_GESTIUNE`.
-
-**Nota de incertitudine, mostenita din raportul-sursa**: linia exacta unde proprietatea
-`id_gestiune` "lipseste" (`Type='U'`) pentru o linie de proforma scatter-uita din `crsfactura` nu a
-fost confirmata direct pe date vii — `crsfactura` are `id_gestiune` ca si camp cu valoare implicita,
-nu absent. Ramane argument indirect (fara `FACT-007` raportat in productie de ani), nu dovada de
-executie. **De verificat cu prioritate la implementare**, pentru ca proiectarea de mai jos (sectiunea
-4) muta acest mecanism dintr-un `UPDATE` de masa intr-o marcare per-linie, si trebuie sa stie exact
-ce camp seteaza.
-
-**1.4 Routingul la Termina.** Vezi "Descoperirea centrala" de mai sus: `scrie_proforma`, nu
-`scrie_factura2`/`scrie_factura_avize` — fara nota contabila, fara descarcare de gestiune, indiferent
-de tipul de business original.
-
-**1.5 Raportul propriu.** `listeaza_ofacturare` alege raportul dupa `poDate.eProforma`
-(`ofacturare.prg:1638-1643`):
-```
-Case (Between(poDate.tip, 1, 20) Or Inlist(poDate.tip, -1,-2,-3,-4,-8,-11,44,45,48,49,50,51,52)) And poDate.eProforma = 1
- lcRaport = [PROFORMA]
- lcRaportVal = [PROFORMA_VAL]
- lcSetare = [PROFORMA]
-```
-Independent de forma formularului (unificat sau nu) — declansat de `poDate.eProforma` la momentul
-listarii, care e populata corect din `nIdTipDoc_Assign` daca antetul reflecta starea finala.
-
-**1.6 Garzile `eProforma = 0` pe atasamente (nu pe nota contabila).** Cinci guarde separate in
-`listeaza_ofacturare`, toate de forma `poDate.nRelistare = 0 And poDate.eProforma = 0 ...`, controland
-salvarea PDF-ului ca atasament arhivat (`export2pdf(..., poDate.cDocAtasate)` si
-`poDate.scrieAtasamente()`), **nu** scrierea notei contabile (care e blocata la alt nivel, sectiunea
-precedenta): `ofacturare.prg:1960` (factura in lei), `:1996` (aviz retur), `:2052` (factura in
-valuta), `:2063` (recapitulatie), `:2103` (`scrieAtasamente()`, arhivarea propriu-zisa). **Corectie
-fata de formularea din plan** (`plan_13_unificare_formular_facturare.md:548-549`, "fara nota
-contabila si fara atasamente, prin garzile `eProforma=0`"): cele doua efecte sunt reale amandoua, dar
-prin **mecanisme diferite** — nota contabila prin routing-ul `scrie_proforma`/`scrie_factura2`
-(sectiunea "Descoperire centrala"), atasamentele prin aceste cinci guarde explicite. Nu schimba nimic
-pentru proiectare, dar conteaza pentru cine cauta "garda de nota contabila" in cod si nu o gaseste la
-liniile citate de plan.
-
-**1.7 Relistarea pe cale separata.** `frm_facturi.do_listare` (`COMUN\clase\ofacturare_comun.vc2:7233-`)
-reconstruieste `poDate` de la zero pentru un document deja emis, cu `poDate.eProforma = 1` setat
-explicit (`:7262`) cand se relisteaza o proforma din grid — nu refoloseste obiectul `poDate` din
-sesiunea de facturare curenta.
-
----
-
-## 2. Fluxul de azi al copierii, cap-coada
-
-**2.1 Degradarea de tip in `do_copiaza`.** `frm_facturi.do_copiaza`
-(`COMUN\clase\ofacturare_comun.vc2:3628-3713`) mapeaza **orice** tip de business catre unul din
-cinci "simple" — `T1` (lista de preturi), `T10` (lista de preturi valuta), `T5` (invoice),
-`T22` (aviz din lista de preturi), sau `T1`/`T10` pentru transfer/altele — pe un `Do Case` explicit
-peste `loFactura.tip` (`:3693-3708`). Factura/avizul din contract sau din comanda **nu se copiaza ca
-atare** — devine o factura simpla din lista de preturi. Apoi `DO copiere_factura WITH loFactura IN
-oproceduri_facturare.prg` (`:3710`).
-
-**2.2 `copiere_factura` -> `factureaza(tip, toFactura)`.** `copiere_factura`
-(`COMUN\programe\oproceduri_facturare.prg:150-153`) cheama `factureaza(loFactura.tip, loFactura)` —
-`toFactura` (obiectul scatter-uit din `crsFacturi`) devine parametrul opțional al lui `factureaza`
-(`COMUN\programe\ofacturare.prg:81-82`), care seteaza `llCopiere = (Type('toFactura') = 'O')`
-(`:111`).
-
-**2.3 Antetul precompletat, dar `nIdTipDoc` NU se propaga.**
-`poDate.completeaza_setari_document(toFactura, .T.)` (`ofacturare.prg:204`, apelat cand `m.llCopiere`)
-cheama `oDateFactura::completeaza_setari_document`
-(`COMUN\programe\ofacturare_comun.prg:362-412`), ramura `tlFactura=.T.` (`:368-390`): copiaza delegat,
-masina, sectie, agent, client, referinta la documentul sursa (`listaid = toDateAnterior.id_vanzare`) —
-dar **linia `.nIdTipDoc = toDateAnterior.nIdTipDoc` e comentata** (`:370`,
-`*.nIdTipDoc = toDateAnterior.nIdTipDoc`), deliberat. Documentul nou primeste `nIdTipDoc` implicit
-dupa tipul degradat (`Do Case` la `ofacturare.prg:187-196`: `tnTip < 21` sau in
-`{45,48,49,51,52}` => `5` FACTURA, altfel `6` AVIZ) — pentru tipurile degradate ale copierii (`T1=1`,
-`T5=5`, `T10=10`, `T22=22`), toate `<21`, deci **`nIdTipDoc=5` (FACTURA) intotdeauna**, ceea ce prin
-`nIdTipDoc_Assign` face **`poDate.eProforma = 0` pe documentul nou, indiferent daca sursa era
-proforma**. Confirma direct pe cod ce raportul-sursa dedusese din trasare (`s5b_proforma_descarcare_gestiune.md` §3).
-
-**2.4 Numar nou, intotdeauna.** `poGeneratorNumere.creeaza_cursor_serii(poDate.nIdTipDoc)` (`:211`)
-ruleaza neconditionat, indiferent de copiere — copierea nu mosteneste numarul documentului sursa,
-alege intotdeauna un numar nou din seria tipului nou (`FACTURA`).
-
-**2.5 Cursorul de linii candidate — intotdeauna `cursor_retur_document`.** `Do Case`-ul care alege
-cursorul Oracle de incarcat in `crsarticole` (`ofacturare.prg:266-308`) verifica **`Case m.llCopiere`
-primul**, inaintea oricarei ramuri pe `tnTip`:
-```
-Case m.llCopiere
- lcSqlCursor = [{call pack_facturare.cursor_retur_document(?poDate.in_valuta,?poDate.listaid,1,?poDate.eProforma,?gnIdUtil)}]
-```
-al treilea parametru pozitional `1` e `V_COPIERE`. Documentul sursa (proforma sau nu) intra prin
-`?poDate.listaid` (setat la `toDateAnterior.id_vanzare` in §2.3). `poDate.eProforma` trimis e cel al
-**documentului nou** (`0`, per §2.3), nu al sursei.
-
-**2.6 Gestionabilitatea se restaureaza la copiere.** `cursor_retur_document`
-(`PACK_FACTURARE:3949-4000`) calculeaza `GESTIONABIL` cu exact aceasta expresie (`:3993-4000`):
-```sql
-(case
- when V_PROFORMA = 1 then 0
- when V_COPIERE = 1 then B.IN_STOC -- NOM_ARTICOLE.IN_STOC, articolul real
- else A.GESTIONABIL
- end) AS GESTIONABIL,
-```
-Cu `V_PROFORMA=0` (documentul nou nu e proforma) si `V_COPIERE=1`, ramura activa e
-`GESTIONABIL = B.IN_STOC` — valoarea reala din nomenclator, **indiferent daca documentul sursa era o
-proforma cu toate liniile fortate `gestionabil=0`**. Liniile copiate dintr-o proforma redevin
-gestionabile normal (daca articolul chiar e in stoc), trec prin `do_alege_stoc` la adaugare, primesc
-`id_gestiune` real, si descarca gestiune normal la emiterea facturii rezultate.
-
-**2.7 Nimic auto-adaugat.** Comentariu explicit in cod (`ofacturare.prg:97-99`, in ramura
-`m.llCopiere` de mai jos in aceeasi functie):
-```
-* Nu adaug automat articolele din factura originala, ca sa dau posibilitate de modificare a cantitatilor, pretului, explicatiei
-* ofrmdetaliifactura.do_adauga_tot()
-```
-Liniile documentului sursa raman doar **candidate** in `crsarticole` (populat de `cursor_retur_document`
-la §2.5) — operatorul le adauga manual (sau cu "adauga tot"), la fel ca la orice document nou.
-
-**2.8 Lista de preturi se adauga peste, doar la copiere.** Imediat dupa, tot in `factureaza()`
-(`ofacturare.prg:454-473`, citat integral in `docs\cercetare\s4e_lista_preturi_pe_sursa.md` §1):
-`pack_facturare.cursor_preturi(...)` intr-un cursor separat `crsArticoleTemp`, apoi
-`SELECT crsArticole / APPEND FROM DBF(lcCursorTemp)` — lipeste lista de preturi completa peste
-candidatii din documentul sursa, ca operatorul sa poata adauga si articole noi la copiere/modificare.
-Vezi sectiunea 6 pentru siguranta acestui pas.
-
----
-
-## 3. Combo-ul `Ct_clb_fdoc` si realocarea de serie/numar la comutare
-
-**Azi, combo-ul traieste exclusiv in dialogul separat `frm_date_factura`/`frm_date_aviz`**
-(clasa continuta in acelasi fisier text `ofacturare.vc2`, dar formular distinct de
-`frm_facturare_articole`/`frm_facturare_articole2`, care contin gridul de linii). Handler-ul e legat
-pe `LostFocus`, nu pe `InteractiveChange`:
-```
-PROCEDURE Ct_clb_fdoc._combobox1.LostFocus && ofacturare.vc2:9857-9859
- thisform.do_schimba_tipdoc()
-ENDPROC
-```
-`do_schimba_tipdoc` (`ofacturare.vc2:9396-9438`), pas cu pas:
-1. Determina `lnIdTipDoc` din textul combo-ului (`FACTURA`/`PROFORMA`/`BON FISCAL`/altfel `FACTURA`).
-2. Cheama neconditionat `poDate.initializeaza_setari_document(...)` cu un cod special (`-101` bon
- fiscal, `-102` proforma, sau `poDate.Tip` altfel) — realoca setarile de document (serie/numar)
- pentru noul tip, inainte sa stie daca tipul chiar s-a schimbat.
-3. **Iesire timpurie daca tipul nu s-a schimbat**: `IF poDate.nIdTipDoc = m.lnIdTipDoc THEN RETURN`.
-4. Daca s-a schimbat: `poDate.nract = 0`, `poDate.serie_act = ""` (curata selectia locala, nesalvata
- nicaieri inca), `poGeneratorNumere.dezaloca_numar(poDate.nIdTipDoc)` (**elibereaza in pool numarul
- vechi**, rezervat pe tipul vechi — nu se pierde, devine disponibil pentru alt document/alta sesiune;
- documentul nu are inca niciun numar scris in baza, fiind pre-Termina), apoi
- `poDate.nIdTipDoc = m.lnIdTipDoc` (declanseaza `nIdTipDoc_Assign`, care actualizeaza
- `eProforma`/`eBonFiscal`), si `poGeneratorNumere.creeaza_cursor_serii(poDate.nIdTipDoc)` reincarca
- seriile disponibile pentru noul tip, populand `clb_serie_act`.
-5. **Numarul vechi nu se "reia" automat** — utilizatorul trebuie sa aleaga din nou serie/numar pentru
- noul tip din controlul `clb_serie_act`, care s-a reincarcat la pasul 4.
-
-**Ce NU atinge `do_schimba_tipdoc` azi**: `crsarticole`, `crsfactura`, `gestionabil`, `id_gestiune` —
-nimic legat de linii. **Motivul e structural, nu o omisiune**: azi comutarea e posibila **doar**
-inaintea oricarei linii, pentru ca `frm_date_factura` (unde traieste combo-ul) e un dialog modal
-care se inchide (`Release ofrmceredate`, `ofacturare.prg:248`) **inainte** ca Do Case-ul de incarcare
-a cursorului de linii sa ruleze (`:266`) — comutarea si incarcarea liniilor nu pot fi simultane azi.
-
-**Ce se schimba cand combo-ul traieste in formularul unificat, cu gridul deja prezent**: exact
-premisa care dispare — combo-ul devine comutabil **si dupa** ce linii exista deja in `crsfactura`.
-`do_schimba_tipdoc` ramane corect pentru partea de serie/numar (pasii 1-5 de mai sus se aplica
-identic, indiferent daca gridul are linii sau nu — realocarea de serie e independenta de continutul
-documentului). **Ce lipseste e pasul 1.2/1.3 de mai sus (marcarea `gestionabil=0`/`id_gestiune=-1000`),
-care azi nu are nevoie sa fie legat de comutare pentru ca nu poate fi comutare cu linii deja
-prezente.** Vezi sectiunea 4.
-
----
-
-## 4. Ce se rupe la unificare
-
-**4.1 Marcarea negestionabil nu mai are un singur moment de executie.** Azi exista un singur loc
-(`ofacturare.prg:330-334`, dupa incarcarea cursorului, inaintea deschiderii gridului) unde
-`eProforma=1` implica `gestionabil=0` in masa. In formularul unificat, cu combo-ul viu in acelasi
-ecran cu gridul (decizia 10), sunt **trei momente distincte** care trebuie sa garanteze acelasi
-invariant, nu unul:
- a. **La deschiderea initiala**, daca formularul porneste direct pe tip Proforma (echivalent cu azi
- — se poate pastra `UPDATE` de masa pe cursorul candidat, daca inca exista un cursor de masa
- pentru sursa respectiva dupa S4/S4e; pe sursele deja mutate pe cautare filtrata/`APPEND BLANK`
- — S4e — nu mai exista cursor de masa de actualizat, marcarea trebuie facuta la construirea
- fiecarui rand).
- b. **La adaugarea unei linii noi cat timp `poDate.eProforma=1`** — deja identificat ca gol de
- proiectare in `s5b_proforma_descarcare_gestiune.md` §7 ("trebuie reimplementat linie-cu-linie,
- la momentul in care fiecare linie e adaugata"), confirmat aici ca valabil si pentru cazul in
- care operatorul a **pornit** documentul ca proforma inainte de a adauga prima linie (nu doar
- dupa un switch).
- c. **La comutarea combo-ului DUPA ce linii exista deja in `crsfactura`** (cazul explicit cerut de
- brief) — scenariu care azi nu poate exista, deci nu are cod de reutilizat. `do_schimba_tipdoc`
- trebuie extins (sau o metoda noua chemata din el) sa parcurga liniile deja prezente in
- `crsfactura` si sa aplice acelasi tratament ca la 1.2-1.3: `gestionabil=0`,
- `id_gestiune=-1000`, pe fiecare linie existenta, **cand comutarea intra pe Proforma**.
- *Corolarul necesar, netratat de nicio decizie/raport anterior*: pentru fiecare linie deja
- adaugata prin `do_alege_stoc` (gestionabila, cu `id_gestiune` real ales de operator), acea
- alegere de gestiune/lot devine irelevanta odata marcata negestionabil — de decis daca se
- **pastreaza tacit** valoarea veche (inofensiv, pentru ca `id_gestiune=-1000` o inlocuieste
- oricum in parametrul trimis la scriere) sau se **sterge explicit** din obiectul liniei, ca sa nu
- induca in eroare un ecran care ar afisa gestiunea aleasa pe o linie acum negestionabila.
-
-**4.2 Combo-ul viu tot timpul inseamna ca `eProforma` poate flutura de mai multe ori inainte de
-Termina.** Azi tipul se alege o singura data, ireversibil (dialogul se inchide). In formularul
-unificat, operatorul poate comuta Factura -> Proforma -> Factura de mai multe ori inainte de a apasa
-`Termina`. Routing-ul de la Termina (sectiunea "Descoperire centrala") citeste `poDate.eProforma`
-**doar la momentul apasarii** — corect pentru starea finala — dar **starea liniilor** (marcate sau nu
-negestionabil, dupa istoricul comutarilor) nu se "reseteaza" singura la fiecare comutare, daca 4.1.c
-nu implementeaza si drumul invers. Vezi sectiunea 5.
-
-**4.3 Realocarea de serie/numar (sectiunea 3) ramane corecta ca atare**, dar UX-ul ei (curatarea
-`clb_serie_act`, cererea catre operator sa aleaga din nou seria) trebuie sa functioneze si cu gridul
-de linii vizibil pe acelasi ecran — nu identificat niciun cod care sa presupuna ca gridul e ascuns in
-timpul realocarii; e o verificare vizuala, nu o problema de proiectare gasita in cod.
-
----
-
-## 5. Drumul invers: proforma comutata inapoi in factura
-
-**Acesta e riscul cel mai serios gasit in aceasta cercetare, nesemnalat explicit in rapoartele
-anterioare.**
-
-Scenariu: operatorul porneste documentul ca Proforma (sau comuta pe Proforma la un moment dat),
-adauga linii — care, daca 4.1 e implementat corect, ajung marcate `gestionabil=0`/`id_gestiune=-1000`
-pe `crsfactura`. Apoi, **inainte de Termina**, comuta combo-ul inapoi pe Factura.
-
-- **`poDate.eProforma` devine `0`** prin `nIdTipDoc_Assign`, corect.
-- **La Termina, routing-ul alege `scrie_factura2`/`scrie_factura_avize`** (sectiunea "Descoperire
- centrala") — care **chiar cheama** `contabilizeaza_articol` pentru fiecare linie.
-- **`contabilizeaza_articol` verifica exact sentinela `id_gestiune <> -1000`** (`PACK:7472-7476`)
- inainte de a chema `descarca_gestiune`. Liniile ramase marcate `-1000` de cand documentul era
- proforma **nu vor descarca gestiune**, desi documentul final e o factura reala, nu o proforma.
-- **Nu exista azi niciun mecanism care sa refaca `gestionabil`/`id_gestiune`** cand tipul revine la
- Factura in aceeasi sesiune. Singurul loc din tot codul citit unde gestionabilitatea se
- "restaureaza" e `cursor_retur_document` la **copiere** (`GESTIONABIL = B.IN_STOC` cand
- `V_COPIERE=1`, sectiunea 2.6) — mecanism legat de incarcarea unui cursor **nou**, la deschiderea
- unui document **nou**, nu de o comutare in acelasi document, in aceeasi sesiune, pe linii deja
- existente in `crsfactura`.
-
-**Consecinta pe date**: o factura reala, emisa din formularul unificat dupa un du-te-vino prin
-Proforma, poate iesi din sesiune cu stocul nedescarcat pentru articole care ar fi trebuit sa-l
-descarce — silentios, fara eroare Oracle (sentinela `-1000` e o valoare valida pentru
-`contabilizeaza_articol`, nu declanseaza nicio exceptie).
-
-**Ce trebuie proiectat, obligatoriu, pentru ca decizia 10 sa fie sigura**: la comutarea **dinspre**
-Proforma **catre** orice alt tip, liniile care au fost marcate negestionabil **exclusiv din cauza
-proformei** (nu articole real negestionabile in nomenclator) trebuie sa-si recapete
-`gestionabil`/`id_gestiune` reale, inainte de a ajunge la `Termina`. Doua variante, niciuna aleasa
-inca:
- a. **Re-interogare per linie** la comutare (analog cu `cursor_retur_document.GESTIONABIL`, dar
- aplicat pe liniile deja din `crsfactura`, nu la incarcarea unui cursor nou) — cere un apel
- Oracle (sau citire din nomenclator local, daca exista deja incarcat) per linie afectata, si
- re-deschiderea alegerii de gestiune/lot pentru cele gestionabile (echivalentul lui
- `do_alege_stoc`, care nu a rulat cand linia a fost adaugata sub Proforma).
- b. **Blocarea comutarii inapoi** cand exista deja linii adaugate sub Proforma — cere confirmare
- sau refuza tranzitia, obligand operatorul sa stearga liniile si sa le re-adauge sub noul tip.
- Mai simplu de implementat, cu cost UX (utilizatorul pierde munca de introducere).
-
-**Nu e o decizie de proiectare pe care raportul o ia in locul lui Marius** — vezi sectiunea 11,
-punctul 1.
-
----
-
-## 6. `id_c` la copiere — raspuns cu dovada
-
-**Nu exista coliziune cu efect observabil pe drumul de copiere, azi.** Motivul, verificat direct pe
-cod (nu presupus, extras din `s4e_lista_preturi_pe_sursa.md` §1, reconfirmat aici pentru S5b):
-
-`ofacturare.prg:454-473` face `APPEND FROM` peste `crsArticole`, lipind lista de preturi
-(`crsArticoleTemp`, numerotata `id_c` independent, cu `ROWNUM` propriu Oracle) peste continutul deja
-prezent (documentul copiat, incarcat la §2.5 din `cursor_retur_document`, cu propriul `id_c`
-independent). Cele doua seturi de `id_c` **se pot suprapune la nivel de valoare** — asta e adevarat,
-tehnic. Dar coliziunea **nu are efect**, pentru doua motive independente, ambele verificate:
-
-1. **`Case m.llCopiere` e prima ramura verificata** in Do Case-ul de incarcare a cursorului
- (`ofacturare.prg:266-268`) — pentru orice document copiat, cursorul de baza e **intotdeauna**
- `cursor_retur_document`, indiferent de tipul original. Un document copiat nu (mai) e niciodata de
- tip `3` (comanda) dupa degradarea din `do_copiaza` (sectiunea 2.1: degradare catre
- `1,5,7,10,22,23` — **CORECTIE runda 13**, cifra veche `1,5,10,22` era gresita; setul real e citit
- din primul `CASE`, `ofacturare_comun.vc2:3693-3694`) —
- deci **nu poate ajunge** in ramura `Inlist(poDate.Tip,3,21,25,28,42,47)` a lui `do_scrie_factura`
- (`ofacturare.vc2:14332-14338`), care e singurul loc unde `id_c` conteaza pentru "cantitate
- ramasa" (Rol A, per `s4_punct2_registru_cantitate_ramasa.md`).
-2. **`do_sterge` potriveste pe `id_c`** (`ofacturare.vc2:14652-14655`), dar aceasta potrivire conteaza
- doar daca ceva citeste `crsarticole` ca registru dupa aceea — ceea ce nu se intampla pe tipurile
- rezultate din copiere (`1,5,7,10,22,23`, toate in ramura `Otherwise` a Do Case-ului de scriere, fara
- `Calculate Sum(cantitate)`).
-
-**Concluzie, cu aceeasi rezerva ca in raportul-sursa**: coliziunea de `id_c` exista **tehnic** in
-datele din `crsArticole` dupa copiere, dar **nu are cale prin care sa produca un efect gresit**, atata
-timp cat tipul rezultat din copiere ramane in setul degradat (`1,5,7,10,22,23` — niciodata
-`3,21,25,28,42,47`).
-**Aceasta concluzie ramane valabila neschimbata si in formularul unificat**, pentru ca nu depinde de
-forma formularului — depinde doar de faptul ca `do_copiaza` degradeaza tipul inaintea oricarei
-incarcari de cursor, mecanism care nu se propune sa fie schimbat de S5b (sectiunea 7).
-
-**O singura conditie de pastrat, explicit**: daca vreo poveste viitoare schimba `do_copiaza` sa NU
-mai degradeze tipul catre grupul "simplu" (de exemplu, sa permita copierea unei comenzi ca o comanda
-noua, nu ca factura din lista de preturi), concluzia de mai sus **trebuie re-verificata** — riscul de
-coliziune `id_c` descris in `s4e_lista_preturi_pe_sursa.md` verdict/punctul 1 ar deveni real.
-
----
-
-## 7. Ce NU se atinge — lista explicita
-
-Confirmate ca deja corecte si suficiente, fara nicio schimbare necesara pentru S5b:
-
-1. **Sentinela `id_gestiune = -1000`** in `contabilizeaza_articol` (`PACK:7472-7476`) — ramane gate-ul
- de aparare pentru orice linie care ajunge totusi la contabilizare cu aceasta valoare (drumul
- invers, sectiunea 5, o foloseste ca sa NU descarce gestiune — ceea ce e exact problema de acolo,
- nu ceva de "reparat" in sentinela insasi).
-2. **Routing-ul `scrie_proforma` vs. `scrie_factura2`/`scrie_factura_avize`**
- (`ofacturare.vc2:14282-14300`) — corect prin constructie, citeste `poDate.eProforma` la momentul
- potrivit (Termina), nu are nevoie de nicio schimbare.
-3. **Cele cinci garzi `eProforma=0` pe atasamente** (`ofacturare.prg:1960,1996,2052,2063,2103`) —
- raman neschimbate, nu au legatura cu formularul (grid vs. dialog separat), doar cu momentul
- listarii/salvarii PDF, care ramane acelasi apel indiferent de forma UI.
-4. **Raportul propriu** (`PROFORMA`/`PROFORMA_VAL`, `ofacturare.prg:1638-1643`) — alegerea ramane pe
- `poDate.eProforma`, neschimbata.
-5. **`do_copiaza` (degradarea de tip)** — ramane exact cum e, decizia S5b (D) o cere explicit
- ("degradarea de tip din `do_copiaza` ramane pentru copiere si nu se aplica la regenerare").
-6. **`copiere_factura` -> `factureaza(tip, toFactura)`** — punctul de intrare ramane neschimbat.
-7. **`completeaza_setari_document`** — comentariul de la `:370` (`nIdTipDoc` necopiat) e deliberat si
- ramane corect: documentul nou pleaca mereu ca Factura, indiferent de sursa, exact ce cere decizia
- S5b (copierea deschide "document nou", cu antetul editabil, nu proforma mostenita).
-8. **`cursor_retur_document` cu `V_COPIERE=1`** (`PACK:3949-4000`) — restaurarea `GESTIONABIL = B.IN_STOC`
- la copiere ramane corecta si suficienta pentru cazul "copiere", fara nicio schimbare (nu e acelasi
- mecanism cu comutarea in-sesiune de la sectiunea 5, care ramane un gol real).
-9. **Numarul alocat la copiere e intotdeauna nou** (`ofacturare.prg:208,211`, neconditionat de
- `llCopiere`) — nimic de schimbat.
-10. **Alocarea de serie/numar a lui `do_schimba_tipdoc`** (sectiunea 3) — mecanismul de dealocare +
- realocare ramane corect si reutilizabil ca atare in formularul unificat; doar absenta lui legata
- de linii (sectiunile 4-5) e golul de acoperit.
-
----
-
-## 8. Pasi de implementare, ordonati
-
-1. **Confirma pe date reale linia exacta unde `id_gestiune` devine `-1000`** pentru o linie de
- proforma (incertitudinea de la sectiunea 1.3) — headless, cu un `crsfactura` construit manual din
- `Scatter` pe o linie de proforma reala, inainte de orice alta schimbare de cod.
- *Gata cand:* se confirma cu certitudine (nu argument indirect) fie linia din
- `do_initializeaza_articol`, fie alt punct, unde proprietatea `id_gestiune` a liniei devine
- efectiv `-1000`.
-2. **Extrage marcarea "linie negestionabila pentru proforma" intr-o metoda proprie**, reutilizabila
- din trei locuri (sectiunea 4.1: incarcare initiala, adaugare linie noua, comutare combo pe linii
- existente) — un singur loc de intretinut pentru regula `eProforma=1 => gestionabil=0,
- id_gestiune=-1000`, nu trei copii.
- *Gata cand:* toate cele trei puncte de intrare cheama aceeasi metoda, verificat prin grep pe
- codul nou.
-3. **Leaga metoda de la pasul 2 de `do_schimba_tipdoc`**, pe ramura care duce spre Proforma, aplicata
- pe toate liniile deja prezente in `crsfactura` la momentul comutarii (sectiunea 4.1.c).
- *Gata cand:* pe un document cu linii deja adaugate ca Factura, comutarea combo-ului pe Proforma
- marcheaza `gestionabil=0`/`id_gestiune=-1000` pe fiecare linie existenta, verificabil prin citirea
- directa a `crsfactura` dupa comutare.
-4. **Proiecteaza si implementeaza drumul invers** (sectiunea 5) — varianta (a) sau (b), decizie a lui
- Marius (sectiunea 11, punctul 1). *Gata cand:* pe un document cu linii adaugate sub Proforma,
- comutat inapoi pe Factura inainte de Termina, fie liniile isi recapata `gestionabil`/`id_gestiune`
- reale (varianta a, verificabil prin `descarca_gestiune` apelat corect la emitere — vezi sectiunea
- 9), fie comutarea inapoi e refuzata/necesita confirmare explicita (varianta b).
-5. **Verifica riscul de la sectiunea 4.1, corolarul**: decide daca `id_gestiune`/lotul ales anterior pe
- o linie acum negestionabila se pastreaza tacit sau se sterge din obiectul liniei — implementeaza
- alegerea si documenteaz-o in cod (un rand de comentariu, per conventia proiectului).
-6. **Regresie pe copiere**, fara nicio schimbare de cod asteptata (sectiunile 2, 6, 7) — pas de
- verificare, nu de implementare: confirma ca formularul unificat, rulat pe drumul de copiere, produce
- acelasi rezultat ca azi (sectiunea 9).
-7. **Regresie pe proforma simpla** (fara comutare, document pornit direct ca Proforma) — confirma ca
- pasii 2-3 nu au schimbat comportamentul cazului deja corect azi.
-
-*Depinde de:* S5 (acoperirea tipurilor), S4/S4e (forma finala a incarcarii liniilor — pasul 2 trebuie
-sa stie daca opereaza pe un cursor de masa sau pe randuri individuale, dupa ce alte povesti decid
-asta pentru fiecare sursa).
-
----
-
-## 9. Cum se verifica
-
-**Proba ceruta de plan**: o proforma emisa din formularul unificat nu produce nota contabila si se
-listeaza pe raportul ei; o copie produce un document nou cu numar nou si acelasi continut.
-
-**Interogari SQL concrete** (numai `SELECT`, rulate cu unealta PowerShell + `sqlplus.exe`, per
-mediul de proiect):
-
-```sql
--- 1. Proforma emisa din formularul unificat: fara nota contabila, fara descarcare de gestiune
-SELECT id_vanzare, tip, eproforma, sters FROM vanzari WHERE id_vanzare = :ID_TEST;
--- eproforma trebuie sa fie 1
-
-SELECT COUNT(*) FROM vanzari_detalii WHERE id_vanzare = :ID_TEST;
--- trebuie sa coincida cu numarul de linii adaugate (liniile SE scriu, doar nu se contabilizeaza)
-
-SELECT id_vanzare_det, id_articol, id_gestiune FROM vanzari_detalii WHERE id_vanzare = :ID_TEST;
--- id_gestiune trebuie sa fie NULL pe fiecare linie (sentinela -1000 tradusa de adauga_articol_factura)
-
-SELECT COUNT(*) FROM note_contabile nc
- JOIN act a ON a.id_fact = nc.id_fact -- sau echivalentul legaturii act/nota folosite in schema
-WHERE a.cod = (SELECT cod FROM vanzari WHERE id_vanzare = :ID_TEST);
--- trebuie sa fie 0 -- nicio nota contabila generata
-
--- 2. Fara descarcare de gestiune: RUL nu are miscare noua dupa emiterea proformei
-SELECT COUNT(*) FROM rul WHERE dataora >= :MOMENT_EMITERE AND id_articol IN (:articolele_testate);
--- trebuie sa fie identic cu inainte de emitere (0 randuri noi legate de acest document)
-
--- 3. Copie: document nou, numar nou, acelasi continut
-SELECT id_vanzare, numar_act, serie_act, eproforma FROM vanzari WHERE id_vanzare = :ID_COPIE;
--- eproforma = 0; numar_act/serie_act diferite de documentul sursa
-
-SELECT vd.id_articol, vd.cantitate, vd.pret, vd.id_gestiune
- FROM vanzari_detalii vd WHERE vd.id_vanzare = :ID_COPIE
- ORDER BY vd.id_articol;
--- comparat linie cu linie cu vanzari_detalii al documentului sursa (:ID_TEST) -- acelasi articol/cantitate/pret;
--- id_gestiune insa REAL (nu NULL), daca articolul e gestionabil -- confirma restaurarea de la sectiunea 2.6
-
--- 4. Drumul invers (sectiunea 5, dupa ce varianta e implementata): factura emisa dupa un du-te-vino prin Proforma
--- descarca gestiune normal, ca orice factura
-SELECT id_vanzare, eproforma FROM vanzari WHERE id_vanzare = :ID_TEST_INVERS;
--- eproforma = 0
-SELECT id_gestiune FROM vanzari_detalii WHERE id_vanzare = :ID_TEST_INVERS;
--- NU mai e NULL pe liniile gestionabile -- confirma ca varianta aleasa la pasul 4 (sectiunea 8) functioneaza
-SELECT COUNT(*) FROM rul WHERE dataora >= :MOMENT_EMITERE_INVERS AND id_articol IN (:articolele_testate);
--- trebuie sa arate miscare noua -- gestiunea s-a descarcat
-```
-
-**Protocol**: fiecare interogare rulata **inainte si dupa** implementare, pe date de test resetate
-identic, per memoria de proiect "zero cazuri in date nu e dovada" — minim un caz per scenariu descris
-mai sus (proforma simpla, proforma cu switch la comutare, copiere din proforma, drumul invers),
-nu doar "a mers o data".
-
----
-
-## 10. Ce nu se poate testa headless
-
-- **Comutarea combo-ului `Ct_clb_fdoc` cu gridul de linii vizibil in acelasi ecran** — capcana deja
- confirmata pe acest proiect (`grid-coloane-nu-se-materializeaza-headless`, memorie de proiect):
- sub `-A -T`, `ColumnCount`/`RecordSource` raman artefacte, comportamentul real al `LostFocus`
- pe combo si al reincarcarii `clb_serie_act` cere harnessul UI vizibil.
-- **Dialogul `frm_articol_factura` vs. `do_alege_stoc`** (sectiunea 1.3, decizia de dialog dupa
- `gestionabil`) — depinde de randare de formular modal, nu apelabil direct fara UI.
-- **Verificarea vizuala ca liniile deja adaugate isi schimba starea la comutare** (sectiunea 4.1.c) —
- daca implementarea alege sa arate un indicator vizual (de exemplu, o coloana/culoare care marcheaza
- "negestionabil"), acel indicator nu se verifica headless; **continutul** `crsfactura` (valorile
- `gestionabil`/`id_gestiune`) **se poate** verifica headless, cu apeluri directe la metoda noua din
- pasul 2 (sectiunea 8), fara sa deschida formularul.
-- **Realocarea vizuala a seriei/numarului in `clb_serie_act`** — control de UI, comportamentul lui de
- reincarcare (`do_initializeaza`) nu se verifica fara randare.
-- **Ce se poate verifica headless, direct**: continutul `crsfactura`/`poDate` dupa apeluri directe
- (nu prin click) la metoda de marcare (pasul 2), la `do_schimba_tipdoc`, si la rutina drumului
- invers (pasul 4) — cu date de test pregatite manual (un `crsfactura` cu 2-3 linii, `poDate.eProforma`
- comutat programatic inainte si dupa) — confirma `gestionabil`, `id_gestiune`, `poDate.eProforma`,
- fara sa deschida formularul. La fel, toate interogarile SQL din sectiunea 9 sunt verificabile
- headless (SQL direct, fara UI).
-
----
-
-## 11. Riscuri si decizii ramase lui Marius
-
-1. **Drumul invers (sectiunea 5) — varianta (a) sau (b).** Cel mai important punct deschis al acestui
- raport: fara o decizie explicita aici, decizia 10 din plan ("proforma foloseste acelasi formular")
- ramane incompleta — un document care trece prin Proforma si revine la Factura in aceeasi sesiune
- poate iesi cu stocul nedescarcat, silentios. **Recomandare**: varianta (a) (re-interogare si
- re-deschidere a alegerii de gestiune la comutarea inapoi), pentru ca varianta (b) (blocarea
- comutarii) contrazice explicit decizia 10 ("combo-ul ramane in antetul unificat", implicit
- liber de folosit in ambele sensuri) si ar surprinde operatorul cu o pierdere de munca fara
- avertisment prealabil la momentul comutarii spre Proforma.
-2. **Ce se intampla cu `id_gestiune`/lotul ales anterior pe o linie marcata ulterior negestionabil**
- (sectiunea 4.1, corolarul) — pastrare tacita (mai simplu, fara cod nou) sau stergere explicita
- (mai clar pentru un ecran viitor care ar afisa gestiunea). **Recomandare**: pastrare tacita — nu
- ajunge niciodata la server oricum (sentinela `-1000` trimisa explicit ignora orice valoare veche),
- iar stergerea ar cere cod suplimentar fara beneficiu functional, doar cosmetic.
-3. **Incertitudinea ramasa din raportul-sursa** (sectiunea 1.3: linia exacta unde `id_gestiune` devine
- `-1000`) — necesara inainte de a scrie codul pasului 2 (sectiunea 8), nu doar o curiozitate.
- Nu e o decizie de produs, e o verificare tehnica obligatorie inaintea implementarii.
-4. **Indicator vizual pentru liniile marcate negestionabil la comutare** (mentionat la sectiunea 10) —
- optional, nu cerut explicit de plan; de decis daca merita un semnal in grid (culoare/iconita) sau
- ramane invizibil pana la emitere. Nu blocheaza nimic, dar afecteaza UX-ul comutarii repetate.
-5. **Testarea pe date reale a `FACT-007`** (mentionata in raportul-sursa ca argument indirect,
- nu dovada) — daca Marius vrea certitudine completa inainte de implementare, un test manual pe
- mediu de dezvoltare (proforma cu articol gestionabil din comanda, verificare directa
- `VANZARI_DETALII.ID_GESTIUNE IS NULL`) inchide definitiv acest gol, in afara perimetrului
- read-only al acestei cercetari.
-
----
-
-## Handoff
-
-Cercetare + proiectare incheiate intr-o singura sesiune, fara sa fie nevoie de predare de context.
-Toate cele 11 sectiuni cerute de brief sunt complete, cu `fisier:linie` verificat direct pe fisierele
-text reale (`ofacturare.vc2`, `ofacturare_comun.vc2`, `ofacturare.prg`, `ofacturare_comun.prg` — nu
-`.bak`) si pe corpul `PACK_FACTURARE` de pe `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`.
-
-**Descoperirea centrala** (sectiunea "Descoperire centrala"): mecanismul care blocheaza nota
-contabila pe proforma nu e (doar) sentinela `-1000` din `contabilizeaza_articol`, ci alegerea
-`scrie_proforma` (fara contabilizare deloc) vs. `scrie_factura2`/`scrie_factura_avize` (cu
-contabilizare) in `do_scrie_factura`, facuta dupa `poDate.eProforma` la Termina. Aceasta descoperire
-schimba unde trebuie sa se concentreze grija de proiectare: nu pe "cum ajunge `-1000` la server"
-(deja acoperit corect de codul existent), ci pe **ce se intampla cu liniile deja marcate `-1000` cand
-documentul nu mai e proforma la Termina** — exact riscul din sectiunea 5, singurul loc unde sentinela
-chiar conteaza si azi nu exista nicio plasa.
-
-Niciun fisier de cod atins, niciun `git_sync.ps1`/`txt2vcx.ps1` rulat, niciun commit, nicio scriere pe
-Oracle (doar `SELECT`/`Read`/`Grep` pe fisiere de pe disc).
diff --git a/docs/cercetare/s5c_factura_din_proforma.md b/docs/cercetare/s5c_factura_din_proforma.md
deleted file mode 100644
index d6e6dcd..0000000
--- a/docs/cercetare/s5c_factura_din_proforma.md
+++ /dev/null
@@ -1,374 +0,0 @@
-# S5C — Factura din proforma (proiectare)
-
-Status: INCHEIAT
-
-## Sarcina
-Cerinta noua (decizia 43, runda 12): dintr-o proforma emisa sa se poata genera o
-FACTURA ca document NOU (nu prin comutarea tipului pe acelasi document — comutarea
-PROFORMA -> FACTURA cu linii e deja blocata cu mesaj). Mecanismul pare sa existe deja
-pe calea de copiere (`do_copiaza`).
-
-## (a) Poate fi azi o proforma aleasa ca sursa de copiere?
-
-**Da, fara nicio excludere.** Trei dovezi convergente:
-
-1. `COMUN\clase\ofacturare_comun.vc2:4964-4974` — `frm_facturi.IsCopy(tnTip)`:
- ```
- RETURN .T. && POT SA COPIEZ ORICE, TRATEZ TIPURILE IN DO_COPIAZA
- *!* RETURN INLIST(m.lnTip, 1,5,7,10,22,23,43) && pot sa copii doar avize si facturi pret de lista, ...
- ```
- Varianta veche (restrictiva, comentata) verifica doar `tip` (1-52) — niciodata `eproforma`. Varianta
- activa returneaza necondiționat `.T.`. Nu exista, si n-a existat vreodata in acest cod, o excludere
- pe `eproforma`.
-2. `COMUN\clase\ofacturare_comun.vc2:5110` — vizibilitatea butonului de copiere pe randul selectat:
- `Thisform.but_copiaza1.Visible = Thisform.IsCopy(crsFacturi.tip)` — acelasi apel, acelasi rezultat
- necondiționat.
-3. `COMUN\clase\ofacturare_comun.vc2:5082-5083` — gridul de facturi are un filtru dedicat pe
- `eproforma`, cu proforma tratata ca subset normal, nu ascuns:
- ```
- "Facturi&Avize\nofiled\E\(eproforma = 0)\" + crlf + ;
- "Proforme\nofiled\E\(eproforma=1)\" + crlf + ;
- ```
- Chiar filtrul "Proforme" arata explicit ca proformele sunt navigabile si selectabile normal in
- acelasi grid — butonul de copiere ramane vizibil identic pe orice rand selectat din acest filtru.
-
-**Concluzie**: azi orice utilizator poate selecta o proforma in grid si apasa "Copiere (CTRL+K)"
-(tooltip-ul insusi anunta explicit acest caz de folosire — vezi citatul din
-`s5b_proiectare_proforma_copiere.md` §"1.4"/`proforma_copiere_puncte_intrare.md:41-47`). Nu exista
-nicio garda de blocat, la niciun nivel (`IsCopy`, vizibilitate buton, filtru grid).
-
-## (b) Ce tip rezulta din copierea unei proforme?
-
-**Rezultatul e intotdeauna `nIdTipDoc=5` (FACTURA)** — corect pentru o factura fiscala — dar tipul de
-business (`VANZARI.TIP`, 1-52) degradeaza dupa tabelul deja existent din `do_copiaza`, **nemodificat
-pentru cazul proforma**: nu exista nicio ramura speciala pe `eproforma` in `do_copiaza`
-(`COMUN\clase\ofacturare_comun.vc2:3628-3713`) — degradarea se face **strict dupa `loFactura.tip`**,
-indiferent daca documentul sursa era proforma sau nu.
-
-**Pasul 1 — degradarea de tip business** (`:3693-3708`, tabel deja confirmat in
-`s5b_proiectare_proforma_copiere.md` §2.1):
-- Proforma poate exista doar pe tipuri "de factura" (combo-ul `Ct_clb_fdoc` traieste in
- `frm_date_factura`, nu si in `frm_date_aviz` — cf. `proforma_copiere_puncte_intrare.md` §1). Setul
- posibil de `loFactura.tip` pentru o proforma e deci printre `{1,2,3,4,5,6,7,8,9,10,43,44,45,47,48,49,51}`
- (grupul "Facturi" din `COMUN\docs\tipuri_documente_facturare.md`).
-- Din acest set: `{1,5,7,10}` raman neschimbate (`CASE INLIST(loFactura.tip,T1,T5,T7,T10,T22,T23)`,
- `:3694`); `{2,3,4,8,43,44,45,47,48,49,51}` degradeaza la `T1` (`:3696-3697`); `{6}` la `T10`
- (`:3698-3699`); `{9}` la `T5` (`:3700-3701`).
-- Deci, pentru orice proforma emisa astazi (indiferent de tipul de business original), documentul
- copiat va avea `TIP` in `{1,5,7,10}` — nucleul "lista de preturi" (lei/valuta) sau credit note.
-
-**Pasul 2 — `nIdTipDoc` NU se propaga** (confirmat deja in
-`s5b_proiectare_proforma_copiere.md` §2.3, `COMUN\programe\ofacturare_comun.prg:370`:
-`*.nIdTipDoc = toDateAnterior.nIdTipDoc` — comentata). Documentul nou primeste `nIdTipDoc` implicit
-dupa tipul degradat: `Do Case` la `COMUN\programe\ofacturare.prg:187-196`, toate valorile din
-`{1,5,7,10}` cad sub `5` (FACTURA) → `poDate.eProforma = 0` pe documentul nou, **indiferent ca sursa
-era proforma**.
-
-**Concluzie pentru (b)**: mecanismul de copiere transforma azi orice proforma intr-o **FACTURA reala
-(`nIdTipDoc=5`, `eproforma=0`)**, de tip business `1` (lista de preturi, cel mai frecvent caz — orice
-tip din `{2,3,4,8,43,44,45,47,48,49,51}` cade tot pe `T1`), `5`/`10` (daca sursa era deja pe lista de
-preturi in valuta/factura valuta), sau `7` (credit note, ramas neschimbat). Tipul rezultat **e cel bun
-pentru o factura fiscala** din perspectiva `nIdTipDoc`/`eproforma` (nu ramane proforma), dar tipul de
-business e intotdeauna **degradat catre "lista de preturi"** — proforma emisa dintr-o comanda (`tip=3`)
-sau dintr-un aviz (`tip=4`) devine, dupa copiere, o factura "banala" `tip=1`, **la fel ca la orice alta
-copiere non-proforma** (comportament deja documentat si acceptat in S5b §7 punctul 5: "degradarea de
-tip din `do_copiaza` ramane pentru copiere si nu se aplica la regenerare" — nicio schimbare ceruta aici
-fata de acel raport).
-
-## (c) Legatura proforma -> factura (VANZARI_CORESP.TIP)
-
-### Structura tabelei (confirmata pe schema vie, `MARIUSM_AUTO`)
-```
-ID_VANZARE_CORESP NUMBER NOT NULL (PK, populat de trigger BEFORE INSERT din SEQ_VANZARI_CORESP)
-ID_VANZARE_FACT NUMBER NOT NULL
-ID_VANZARE_AVIZ NUMBER NOT NULL (nume generic mostenit — nu neaparat un aviz, vezi mai jos)
-STERS NUMBER NULL
-TIP NUMBER NOT NULL
-```
-Singurul trigger gasit pe tabela (`TRG_VANZARI_CORESP_BEFOINS`, prezent identic in schemele `ACN` si
-`MARIUSM_AUTO`) doar genereaza PK-ul din secventa — nu atinge/valideaza `TIP`.
-
-### Cine scrie in tabela — un singur punct, in tot codul Oracle
-`grep` pe `all_source` (schema vie) dupa `VANZARI_CORESP` gaseste **un singur writer**:
-`pack_facturare.scrie_corespondente_vanzari` (`PACK_FACTURARE:15481-15516`, singurul `INSERT INTO
-VANZARI_CORESP` din toata baza). Nu exista alt pachet, trigger sau produs ROA (ROAGEST, ROAIMOB,
-ROACONTRACTE, ROAACNPRO etc.) care sa scrie in aceasta tabela — `PACK_FACTURARE` traieste in `COMUN`,
-partajat de toata suita, deci **orice** consumator ar trece prin acelasi punct.
-
-### Valorile de `TIP` deja folosite — confirmate cod + date
-**Cod** (singurele 3 apeluri la `scrie_corespondente_vanzari` din tot `PACK_FACTURARE`,
-`:14818-14839`, in `finalizeaza_factura`):
-- `TIP=1`: `WHEN pack_facturare.ntip = 4 THEN ... scrie_corespondente_vanzari(1)` — factura scrisa
- dintr-un aviz (`ntip=4` = "FACT. DIN AVIZ"). Foloseste `pack_facturare.clistaid_avize` (lista
- separata, populata pentru facturare-din-aviz cu selectie multipla).
-- `TIP=2`: `WHEN pack_facturare.ntip = 24 THEN ... scrie_corespondente_vanzari(2)` — aviz de retur
- (`ntip=24`).
-- `TIP=3`: `WHEN pack_facturare.ntip IN (8, 9) THEN ... scrie_corespondente_vanzari(3)` — factura de
- retur.
-Toate trei folosesc `pack_facturare.nid_vanzare` (documentul curent, tocmai scris) ca
-`ID_VANZARE_FACT`; pentru `TIP=1` sursa vine din `clistaid_avize`, pentru `TIP=2`/`TIP=3` (ramura
-`ELSE` din `scrie_corespondente_vanzari`, `:15490-15491`) din `pack_facturare.clistaid` generic.
-
-**Date** (schema `MARIUSM_AUTO`, interogare directa `SELECT tip, COUNT(*) FROM vanzari_coresp GROUP BY
-tip`): `TIP=1` → 6 randuri, `TIP=2` → 1, `TIP=3` → 1. **Zero randuri cu alt `TIP`.** Coerent cu codul
-(nu exista alt loc care sa scrie alte valori) — dovada dubla (cod + date), nu doar una din ele (per
-memoria de proiect "zero cazuri in date nu e dovada": aici avem *si* absenta din date, *si* absenta
-structurala in cod, ceea ce e o dovada tare, nu doar un data point izolat).
-
-### Valoare noua libera
-**`TIP=4` e liber**, confirmat pe ambele fronturi (cod: niciun apel existent la
-`scrie_corespondente_vanzari(4)`; date: zero randuri `TIP=4` in schema testata). Recomandare: **`TIP=4`
-= "factura scrisa dintr-o proforma"**, urmatorul numar disponibil in secventa deja folosita (1,2,3),
-fara conflict cu niciun consumator existent (nu exista alt produs ROA care sa scrie sau sa citeasca
-`VANZARI_CORESP` in afara de `PACK_FACTURARE`). Structura tabelei **nu se schimba** — doar o noua
-valoare de enum in coloana `TIP`, exact cum a cerut misiunea.
-
-### Unde s-ar scrie corespondenta — punct de intrare, cu rezerva importanta
-Tiparul de azi (`TIP=1/2/3`) scrie corespondenta **din interiorul** `finalizeaza_factura`, intr-un
-`CASE` cheie **`pack_facturare.ntip`** — semnalul de business-type al documentului nou scris. Aceasta
-cheie **nu poate distinge** "factura rezultata dintr-o copiere de proforma" de "orice alta factura
-obisnuita cu acelasi tip degradat" (vezi (b): rezultatul copierii unei proforme cade intotdeauna in
-`{1,5,7,10}`, niciodata `4`/`24`/`8`/`9` — deci nu exista azi nicio ramura `WHEN` pe care s-o extinda,
-si niciuna nu s-ar putea scrie corect doar din `ntip`, pentru ca acelasi `ntip=1` rezulta si dintr-o
-copiere obisnuita de factura, nelegata de nicio proforma). Vezi Capcana (i) pentru raspunsul complet la
-"de unde stie Oracle ca sursa a fost o proforma" si propunerea de proiectare pentru rezolvare.
-
-## Capcana (i): supravietuieste id_fact/id_vanzare al sursei pana la scrierea corespondentei?
-
-**Da, `id_vanzare` al proformei supravietuieste — dovedit pas cu pas — dar faptul ca sursa "era o
-proforma" (nu doar "era un document oarecare") NU supravietuieste nicaieri azi. Asta e golul real.**
-
-**Partea care functioneaza deja, neschimbata:**
-1. `do_copiaza` (`COMUN\clase\ofacturare_comun.vc2:3690-3691`): `SELECT crsFacturi / SCATTER NAME
- loFactura MEMO` — `loFactura` e o copie completa a randului sursa din grid, **inclusiv
- `loFactura.id_vanzare`** (campul cheie) si `loFactura.eproforma` (coloana de grid confirmata la
- `ofacturare_comun.vc2:2494`, `Column37.ControlSource = "eproforma"`) — **ambele disponibile in
- acest moment**, inainte ca degradarea de tip (`:3693-3708`) sa ruleze.
-2. `copiere_factura` (`COMUN\programe\oproceduri_facturare.prg:150-153`) → `factureaza(loFactura.tip,
- loFactura)` — `loFactura` intreg (cu `id_vanzare` si `eproforma` inca pe el) devine `toFactura`,
- parametrul opțional.
-3. `completeaza_setari_document(toDateAnterior, .T.)`
- (`COMUN\programe\ofacturare_comun.prg:362-412`), ramura de copiere: **`.listaid =
- toDateAnterior.id_vanzare`** (`:387`) — **aici** `id_vanzare` al proformei ajunge in `poDate`,
- proprietate care **nu e atinsa de degradarea de tip** (aceea opereaza doar pe `loFactura.tip`,
- variabila locala din `do_copiaza`, complet separata de `poDate`).
-4. `poDate.listaid` calatoreste neschimbat prin toata sesiunea (folosit si la §2.5 din
- `s5b_proiectare_proforma_copiere.md` pentru `cursor_retur_document`), pana la scriere:
- `do_scrie_articole` (`COMUN\clase\ofacturare.vc2:6104`): `Alltrim(Nvl(poDate.listaid,''))` e trimis
- ca parametru `V_LISTAID` catre `pack_facturare.initializeaza_date_factura`, care il pune in
- `pack_facturare.clistaid := V_LISTAID` (`PACK_FACTURARE:1883`) — **inainte** ca `do_scrie_factura`
- sa aleaga `scrie_factura2`/`finalizeaza_factura`. La momentul in care `scrie_corespondente_vanzari`
- ar rula, `pack_facturare.clistaid` **este deja** `id_vanzare`-ul proformei (ca text), exact valoarea
- pe care ramura `ELSE` a lui `scrie_corespondente_vanzari` (`:15490-15491`, folosita azi de `TIP=2` si
- `TIP=3`) o citeste.
-
-**Partea care NU exista azi — golul real:** `completeaza_setari_document` (pasul 3 de mai sus) copiaza
-explicit `id_lucrare`, `nrord`, `id_sectie`, `sectie`, `id_agent`, `nume_agent`, `id_delegat`,
-`nume_delegat`, `BIdelegat`, `CNPdelegat`, `nrinmat`, `id_masina`, `listaid`, `descriere`, `id_client`,
-`nume_client` de pe `toDateAnterior` — **dar niciodata `.eproforma`**. Documentul nou stie "din ce
-`id_vanzare` a fost copiat" (`.listaid`), dar **nu stie daca acel document sursa era o proforma sau o
-factura obisnuita** — informatia se pierde exact la acest pas, inainte sa ajunga la Oracle.
-
-**De ce conteaza**: `finalizeaza_factura` (Oracle) decide azi ce `TIP` de corespondenta sa scrie
-uitandu-se **doar** la `pack_facturare.ntip` (business-type-ul documentului nou). Cum am stabilit la
-(b), rezultatul unei copieri de proforma cade intotdeauna in `{1,5,7,10}` — **acelasi interval** in
-care cade si o copiere obisnuita (proforma sau nu). Oracle **nu poate reconstitui** din `ntip` singur
-daca documentul curent a fost copiat dintr-o proforma sau dintr-o factura normala — nu exista niciun
-semnal in `pack_facturare` care sa poarte aceasta distinctie.
-
-**Ce trebuie adaugat, minimal** (propunere, nu implementare):
-1. **VFP**: la `completeaza_setari_document:387`, langa `.listaid = toDateAnterior.id_vanzare`, adauga
- o proprietate noua, de exemplu `.lProformaSursa = (toDateAnterior.eproforma = 1)` — un simplu boolean
- client-side, capturat in acelasi moment si din acelasi obiect sursa unde `listaid` e deja capturat
- (zero risc suplimentar de "se pierde intre timp", pentru ca foloseste exact acelasi tipar dovedit la
- pasul 3-4 de mai sus).
-2. **Scrierea corespondentei, NU prin `finalizeaza_factura`/`ntip`**: pentru ca `ntip` nu poate purta
- distinctia (vezi mai sus), cea mai sigura ruta e un apel Oracle **explicit, separat**, facut din VFP
- imediat dupa ce `do_scrie_factura` confirma succesul scrierii documentului nou, gardat de
- `poDate.lProformaSursa`:
- ```
- IF poDate.lCopiere AND poDate.lProformaSursa
- lcSql = [{call pack_facturare.scrie_corespondente_vanzari(4)}]
- * ... goExecutor.oExecute(lcSql) ...
- ENDIF
- ```
- Aceasta reutilizeaza **exact** procedura Oracle existenta, neschimbata (ramura `ELSE`,
- `pack_facturare.clistaid`/`pack_facturare.nid_vanzare` inca valide in sesiune la acel moment, per
- pasul 4 de mai sus) — **zero cod PL/SQL nou**, doar un nou punct de apel VFP si o noua valoare de
- `TIP`. Alternativa (adaugarea unei ramuri noi in `CASE`-ul din `finalizeaza_factura`, cheie pe un
- parametru nou trimis prin `V_PARAMETRU_ADITIONAL` sau similar) ar fi mai fragila: acel `CASE` e
- punctul comun al **oricarei** facturi/aviz/retur scrise in tot codul, folosit de toate produsele ROA
- prin `PACK_FACTURARE` partajat — o ramura noua acolo, keyed pe o combinatie de `ntip` + un flag nou,
- ar creste suprafata unui switch deja incarcat, pentru un caz care oricum nu poate fi exprimat corect
- doar din `ntip`. Apelul explicit izolat e mai simplu si nu atinge deloc `finalizeaza_factura`.
-3. **Ordinea conteaza**: apelul explicit trebuie sa ruleze **inainte** ca orice alt cod Oracle din
- aceeasi sesiune sa resetteze `pack_facturare.nid_vanzare`/`clistaid` (de exemplu, o alta scriere de
- document in acelasi batch) — de plasat imediat dupa `do_scrie_factura`, inainte de listare/atasamente
- (care oricum nu ating Oracle pentru partea de scriere). Daca se prefera robustete completa (fara
- dependenta de stare de sesiune Oracle), varianta alternativa e sa se paseze explicit
- `V_ID_VANZARE_FACT` (= `poDate.id_vanzare`, cunoscut client-side dupa scriere) si
- `V_ID_VANZARE_PROFORMA` (= `poDate.listaid`, deja cunoscut) direct ca parametri, printr-o mica
- procedura Oracle noua care ocoleste `clistaid`/`nid_vanzare` cu totul — cost: un nou obiect PL/SQL in
- loc de zero, beneficiu: independenta de ordinea altor apeluri din sesiune. **Alegere ramasa lui
- Marius** (vezi propunerea finala).
-
-## Capcana (ii): `marcheaza_facturat` pe proforma — corect sau nu?
-
-**Nu trebuie chemat pe proforma. Confirmat cu dovada, pe patru argumente convergente.**
-
-**Ce face, exact** (`PACK_FACTURARE:15381-15418`):
-```sql
-PROCEDURE marcheaza_facturat(V_VERIFICARE IN NUMBER) IS
-BEGIN
- IF V_VERIFICARE = 0 THEN
- UPDATE VANZARI SET FACTURAT = 1, ID_UTILFACT = pack_facturare.nid_util
- WHERE ID_VANZARE IN (SELECT id_vanzare_aviz FROM vanzari_coresp
- WHERE id_vanzare_Fact = pack_facturare.nid_vanzare
- AND sters = 0 AND tip <> 3)
- AND FACTURAT = 0;
- ELSE
- -- varianta "verificare cantitate ramasa": marcheaza FACTURAT=1 doar daca toata cantitatea
- -- din VANZARI_DETALII a documentului sursa a fost deja consumata in VANZARI_CANTITATI
- ...
- END IF;
-END;
-```
-Flipeaza `VANZARI.FACTURAT=1` (+`ID_UTILFACT`) pe **documentul(ele) sursa** legate prin
-`VANZARI_CORESP` de documentul tocmai scris — fie neconditionat (`V_VERIFICARE=0`), fie doar cand
-cantitatea documentului sursa a fost epuizata (`V_VERIFICARE=1`, mecanismul de **facturare partiala** a
-avizelor, bazat pe `VANZARI_CANTITATI`).
-
-**Argumentul 1 — nu exista un `TIP` cu care sa se cupleze corect azi.** `marcheaza_facturat` se cheama
-azi **doar** din `finalizeaza_factura`, in aceleasi doua ramuri `WHEN pack_facturare.ntip = 4` si
-`WHEN pack_facturare.ntip = 24` care scriu si corespondenta (`:14823-14831`) — cuplate mereu impreuna cu
-`scrie_corespondente_vanzari(1)`/`(2)`, niciodata separat. Cum am stabilit la Capcana (i), calea propusa
-pentru `TIP=4` (factura din proforma) e un **apel explicit separat**, in afara acestui `CASE` — deci
-n-ar exista niciun loc "natural" unde `marcheaza_facturat` sa se agate fara sa introduca exact acelasi
-tip de cod nou-scris ca la corespondenta insasi.
-
-**Argumentul 2 — mecanismul de "cantitate ramasa" (`V_VERIFICARE=1`) nu are pe ce sa opereze pentru o
-proforma.** Verificarea citeste `VANZARI_CANTITATI` (populat **doar** de
-`scrie_cantitati_vanzari_avize`, apelata **doar** in ramura `ntip=4` a lui `finalizeaza_factura`).
-Proforma nu trece niciodata prin `finalizeaza_factura` (confirmat in
-`s5b_proiectare_proforma_copiere.md`, "Descoperire centrala": `scrie_proforma` cheama doar
-`scrie_in_vanzari`) — deci **nu exista niciodata randuri `VANZARI_CANTITATI` pentru o proforma**.
-Varianta `V_VERIFICARE=1` a lui `marcheaza_facturat` ar gasi mereu "cantitate ramasa = cantitate totala"
-(nimic consumat), fie nu ar marca niciodata `FACTURAT=1` (comportament inutil), fie (daca s-ar folosi
-gresit `V_VERIFICARE=0`) ar marca neconditionat, ca la punctul urmator.
-
-**Argumentul 3 — asimetrie la stergere: proforma ar ramane blocata `FACTURAT=1` definitiv.**
-`sterge_factura` (`PACK_FACTURARE:5501-5533`) reface `FACTURAT=0` pe documentele sursa **doar** pentru
-`V_TIP=24` (aviz retur, `:5502-5510`) si `V_TIP=4` (factura din aviz, `:5525-5533`) — tipurile care azi
-chiar cheama `marcheaza_facturat`. Rezultatul copierii unei proforme cade intotdeauna in `{1,5,7,10}`
-(per (b)) — **niciuna din aceste valori nu are ramura in `CASE`-ul de stergere**. Daca s-ar chema
-`marcheaza_facturat` la scrierea facturii din proforma, iar utilizatorul ar sterge ulterior acea
-factura, **proforma sursa ar ramane cu `FACTURAT=1` pentru totdeauna** — o stare orfana, fara niciun
-cod care s-o repare, introdusa exact de acest apel. Corespondenta `VANZARI_CORESP` insasi nu are aceeasi
-problema (nimic n-o citeste ca sa se strice daca ramane "orfana" dupa stergerea facturii — cel mult
-devine o legatura catre un document sters, inofensiv).
-
-**Argumentul 4 — nimic nu filtreaza azi proformele dupa `FACTURAT`, deci n-ar exista niciun beneficiu
-de blocat.** Spre deosebire de avize (`cursor_avize`/candidatii de facturat, filtrati implicit prin
-fluxul dedicat "Factura din aviz") si comenzi (`VCOMENZI.FACTURAT=0`, folosit explicit in
-`cauta_date_comanda`/`cauta_date_comanda_gest`, `PACK_FACTURARE:15659,15685`, ca sa nu ofere din nou o
-comanda deja facturata), **nimic in codul citit** filtreaza dupa `FACTURAT` cand se alege o proforma ca
-sursa de copiere — confirmat la (a): `IsCopy`/vizibilitatea butonului/filtrul de grid nu se uita
-niciodata la `facturat`. Marcarea n-ar preveni nicio re-copiere accidentala a aceleiasi proforme (care
-oricum ramane posibila, vezi propunerea finala, punctul de decizie 2).
-
-**Concluzie**: `marcheaza_facturat` **nu trebuie chemat** pentru "factura din proforma". Se scrie
-**doar** corespondenta (`VANZARI_CORESP`, `TIP=4`), fara actualizare de `VANZARI.FACTURAT` pe proforma.
-Confirma explicit suspiciunea din misiune ("proforma nu e document de livrare") cu evidenta concreta:
-proforma n-are urma in `VANZARI_CANTITATI` (Argumentul 2), n-are ramura de reversare la stergere
-(Argumentul 3), si n-are niciun consumator care sa citeasca `FACTURAT` pe ea (Argumentul 4).
-
-## Propunere de proiectare
-
-Mecanismul de baza **ramane copierea existenta** (`do_copiaza`/`copiere_factura`/`factureaza`,
-neschimbata in structura ei) — cerinta "document nou, nu comutare pe acelasi document" e deja
-satisfacuta de calea de azi (confirmat la (a)/(b)). Ce lipseste e strict **legatura persistata**
-proforma → factura si excluderea explicita a lui `marcheaza_facturat`. Pasi, in ordine:
-
-1. **Captureaza `eproforma` al sursei la copiere.** In `completeaza_setari_document`
- (`COMUN\programe\ofacturare_comun.prg:387`, ramura `tlFactura=.T.`), langa
- `.listaid = toDateAnterior.id_vanzare`, adauga o proprietate noua pe `poDate`
- (ex. `.lProformaSursa`), citind `toDateAnterior.eproforma` — singurul loc unde informatia mai e
- disponibila, inainte sa se piarda (Capcana (i)). *Gata cand:* dupa copierea unei proforme,
- `poDate.lProformaSursa = .T.`; dupa copierea oricarui alt document, `.F.`.
-2. **Rezerva `TIP=4`** in `VANZARI_CORESP` pentru "factura scrisa dintr-o proforma" — doar o conventie
- documentata (ca la 1/2/3), zero schimbare de schema (confirmat la (c): tabela ramane
- `ID_VANZARE_FACT, ID_VANZARE_AVIZ, TIP, STERS`).
-3. **Scrie corespondenta cu un apel Oracle explicit, separat de `finalizeaza_factura`.** Imediat dupa
- ce `do_scrie_factura` confirma succesul (acelasi punct unde azi se decid listarea/atasamentele),
- daca `poDate.lCopiere AND poDate.lProformaSursa`: `{call
- pack_facturare.scrie_corespondente_vanzari(4)}` — **reutilizeaza procedura Oracle existenta,
- neschimbata** (ramura `ELSE`, deja scrisa pentru `TIP=2`/`3`). Zero cod PL/SQL nou pentru scriere.
- *Alternativa mai robusta, cu cost:* o mica procedura Oracle noua care primeste explicit
- `V_ID_VANZARE_FACT`/`V_ID_VANZARE_PROFORMA` ca parametri (nu se bazeaza pe
- `pack_facturare.clistaid`/`nid_vanzare` inca valide in sesiune) — de ales intre simplitate (varianta
- de mai sus) si robustete fata de ordinea apelurilor (varianta cu parametri expliciti); vezi punctul
- de decizie 1 mai jos.
-4. **NU cheama `marcheaza_facturat`.** Confirmat cu 4 argumente independente la Capcana (ii) — proforma
- nu are `VANZARI_CANTITATI`, nu are ramura de reversare la stergere, nimic n-o filtreaza dupa
- `FACTURAT`, si oricum n-ar exista un `WHEN pack_facturare.ntip=...` natural de unde s-o cheme (calea
- aleasa la pasul 3 e explicit separata de `finalizeaza_factura`).
-5. **Afisare optionala "provine din proforma X"** pe factura noua — se poate construi din
- `VANZARI_CORESP` (`TIP=4`) la fel ca tiparul deja folosit pentru retur (`legatura_linie_retur.md`
- §5): la nivel de **document**, nu de linie (nicio schimbare fata de tiparul deja acceptat pentru
- retur — nu exista niciun tabel de legatura la nivel de linie in tot codul citit, per acelasi raport).
- Nu e cerut explicit de misiune, dar e disponibil "gratis" din legatura scrisa la pasul 3.
-
-**Ce NU se schimba** (confirmat, fara nevoie de atingere):
-- `IsCopy`, vizibilitatea `But_copiaza1`, filtrul de grid "Facturi&Avize / Proforme" — proforma ramane
- selectabila ca sursa exact ca azi (a).
-- Degradarea de tip din `do_copiaza` (`{1,5,7,10}` pentru orice proforma) si alocarea de numar nou —
- raman neschimbate, deja produc `nIdTipDoc=5`/`eproforma=0` corect pentru documentul nou (b).
-- `cursor_retur_document`, restaurarea `GESTIONABIL=B.IN_STOC` la copiere — neschimbat, mecanism deja
- corect pentru orice copiere (mostenit din `s5b_proiectare_proforma_copiere.md` §7).
-- `scrie_corespondente_vanzari` insasi — zero cod PL/SQL nou (varianta recomandata la pasul 3).
-
-### Riscuri si ce ramane de decis de Marius
-
-1. **Apel explicit pe stare de sesiune (`clistaid`/`nid_vanzare`) vs. procedura noua cu parametri
- expliciti** (pasul 3) — simplitate (zero cod Oracle nou, dar depinde ca nimic altceva sa nu resetteze
- starea pachetului intre scrierea facturii si apelul de corespondenta) vs. robustete (un obiect
- PL/SQL nou, insensibil la ordine). Recomandare: varianta simpla, **daca** apelul se plaseaza imediat
- dupa `do_scrie_factura`, inainte de orice alt apel Oracle din acelasi flux (listare/atasamente nu
- ating Oracle pentru scriere) — de verificat pe cod exact la implementare ca nu exista un apel Oracle
- intercalat care ar reseta `pack_facturare.nid_vanzare`.
-2. **Poate fi copiata de mai multe ori aceeasi proforma?** Azi nu exista nicio garda (FACTURAT nu se
- marcheaza — decizia de la Capcana (ii)), deci un utilizator poate genera N facturi din aceeasi
- proforma, fiecare cu propriul rand `TIP=4` in `VANZARI_CORESP` catre aceeasi proforma sursa. E
- comportamentul implicit al oricarei copieri azi (nimic n-o limiteaza nici pentru facturi/avize
- normale) — de confirmat daca e acceptabil sau daca se doreste un avertisment (nu o blocare, pentru
- ca ar contrazice tiparul existent de copiere liber-repetabila).
-3. **Guard simetric la stergere?** `sterge_factura` blocheaza azi stergerea unui aviz/unei facturi care
- are deja o factura de retur legata (`TIP=3`) sau facturi/avize-retur legate (`TIP IN (1,2)`,
- `PACK_FACTURARE:5450-5476`). Nu exista cerinta explicita in misiune pentru un guard simetric pe
- `TIP=4` (ex. "nu poti sterge o proforma care are deja o factura generata din ea") — de decis daca se
- doreste, sau daca proforma ramane liber stersa oricand (comportament actual, neschimbat daca nu se
- adauga nimic).
-4. **Afisarea "provine din proforma X"** (pasul 5) — optionala, nu ceruta explicit; de decis daca
- merita implementata acum sau ramane pentru o poveste ulterioara (costul e mic, data fiind legatura
- deja scrisa la pasul 3).
-5. **`TIP=4` ca valoare aleasa** — libera si fara conflict azi (confirmat cod+date), dar e o alocare
- ireversibila din punct de vedere al datelor odata folosita in productie; de confirmat explicit de
- Marius inainte de implementare (nu doar acceptata tacit).
-
-## STARE / CE RAMANE
-
-**Cercetare + proiectare incheiate.** Toate cele trei intrebari (a/b/c) si ambele capcane (i/ii) au
-raspuns cu dovada `fisier:linie`, verificat pe fisierele text reale (`ofacturare_comun.vc2`,
-`ofacturare.vc2`, `ofacturare_comun.prg`, `ofacturare.prg` — nu `.bak`) si pe `PACK_FACTURARE`
-(`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`), plus verificare directa pe schema Oracle vie
-(`MARIUSM_AUTO`: structura `VANZARI_CORESP`, distributia `TIP` din date, singurul trigger existent).
-
-Descoperirea centrala a acestei cercetari: mecanismul de copiere de azi rezolva deja "document nou" si
-"tip corect" (a, b) fara nicio schimbare, dar **pierde tacit** informatia "sursa era o proforma" chiar
-in metoda care ar trebui s-o pastreze (`completeaza_setari_document:387`, care copiaza `listaid` dar nu
-si `eproforma`) — motiv pentru care legatura `VANZARI_CORESP` nu se poate agata de `CASE`-ul existent
-din `finalizeaza_factura` (cheie doar pe `ntip`, care nu poarta aceasta distinctie) si are nevoie de un
-semnal nou, client-side, plus un apel Oracle explicit separat (pasii 1 si 3 din propunere).
-
-Niciun fisier de cod atins, niciun `git_sync.ps1`/`txt2vcx.ps1` rulat, niciun commit, nicio scriere pe
-Oracle (doar `SELECT`, rulat cu `sqlplus.exe` pe schema `MARIUSM_AUTO`).
diff --git a/docs/cercetare/s8_incarcare_document.md b/docs/cercetare/s8_incarcare_document.md
deleted file mode 100644
index 2f09502..0000000
--- a/docs/cercetare/s8_incarcare_document.md
+++ /dev/null
@@ -1,720 +0,0 @@
-# S8 — Proiectare: incarcarea documentului existent in formularul unificat
-
-Livrabilul povestii **S8** din `docs\plan_13_unificare_formular_facturare.md:2944-2962` (etapa II,
-deciziile 5, 8, 9, 19, 35, 50). Cercetare **READ-ONLY** — zero editari de cod, zero write-back, zero
-`git_sync.ps1` / `txt2vcx.ps1`, zero commit. Pe Oracle **numai `SELECT`** pe dictionar
-(`all_tab_columns` pentru `VANZARI`, `VANZARI_DETALII`, `FACT_VFACTURI`, `FACT_VFACTURI_DETALII`).
-`COMUN\clase\ofacturare_comun.vc2` si `COMUN\programe\ofacturare_editare.prg` (perimetrul #6) doar
-citite, neatinse.
-
-**Conventie de marcare**, folosita peste tot in raport:
-- **[V]** = verificat direct pe cod / pe dictionarul Oracle, cu `fisier:linie` sau nume de coloana;
-- **[D]** = dedus din cod verificat, dar concluzia insasi n-a fost executata / observata;
-- **[N]** = nestabilit, cu motivul scris.
-
----
-
-## 0. Verdict (rezumat)
-
-Schita din plan — *„`completeaza_setari_document` pentru antet + `cursor_retur_document(V_COPIERE = 1)`
-pentru linii, fara degradarea de tip din `do_copiaza`"* — e corecta ca directie, dar **niciuna dintre
-cele doua piese nu incarca documentul**, si asta nu e o nuanta de implementare:
-
-1. **`completeaza_setari_document(toFactura, .T.)` copiaza 16 proprietati din ~120 [V]**
- (`COMUN\programe\ofacturare_comun.prg:361-411`). Nu copiaza **niciunul** dintre cei 14 parametri de
- identitate/antet ai lui `modifica_date_factura`, in afara de `id_delegat` / `id_masina` / `id_agent`.
- Serie, numar, data, scadenta, `text_aditional`, `id_facturare`, `id_ruta`, `tip_saft`, `efactura`,
- `listare_detaliata`, `dataora_exp`, discountul de document, `discount_evidentiat`, `eproforma`,
- valuta, cursul — **toate lipsesc**. Sectiunea 1.2 le da pe toate, cu sursa.
-2. **`cursor_retur_document(V_COPIERE = 1)` nu umple gridul documentului, ci gridul-sursa.** Pe calea de
- copiere, rezultatul lui intra in `crsarticole` (selectorul din stanga), iar `crsfactura` (documentul)
- se creeaza **gol** si ramane gol — comentariul e explicit: *„Nu adaug automat articolele din factura
- originala, ca sa dau posibilitate de modificare"* (`COMUN\programe\ofacturare.prg:455-457`,
- `:338` `creeaza_facturacrs([crsfactura])`) **[V]**. Transferul in document se face **numai** prin
- `do_adauga_tot` → `do_adauga_articol`, care pentru articolele gestionabile trece prin
- **dialogul de alegere din stoc** (`do_alege_stoc`). Sectiunea 4.3.
-3. **`cursor_retur_document` nu intoarce `ID_VANZARE_DET` si nu intoarce `TAXCODE` [V]**
- (lista completa de coloane: `PACK_FACTURARE:3949-4054`). Fara `ID_VANZARE_DET`:
- - **cheia de linie presupusa de S8b (§1.2 al raportului S8b) nu exista** pe calea propusa;
- - **ruta ieftina `modifica_explicatie_articol` devine neapelabila** — primul ei parametru **este**
- `V_ID_VANZARE_DET` (`PACK_FACTURARE:14511-14519`) **[V]**.
- Fara `TAXCODE`, cerinta explicita a planului („explicatia si `taxcode` pe fiecare linie") nu e
- acoperita.
-
-**Recomandarea centrala a acestei proiectari:** S8 **nu** se construieste pe perechea din schita, ci pe
-**precedentul care exista deja si face exact acest lucru** — `relisteaza_ofacturare_stoc`
-(`COMUN\programe\ofacturare_stoc.prg:456-742`) **[V]**, care reconstituie `poDate` + cursorul de linii
-dintr-un document salvat, prin `FACT_VFACTURI` (antet) + `FACT_VFACTURI_DETALII` (linii), pentru
-relistare. `FACT_VFACTURI_DETALII` **are** `ID_VANZARE_DET` si `TAXCODE` **[V]**. Detaliile,
-compromisurile si ce ramane totusi de completat — sectiunea 1.3 si 4.
-
----
-
-## 1. Inventarul complet a ce se incarca, camp cu camp
-
-### 1.1 Cele doua canale de citire, comparate pe coloane [V]
-
-Sursa: `PACK_FACTURARE:3949-4054` (`cursor_retur_document`) si `all_tab_columns` pentru
-`FACT_VFACTURI_DETALII` / `VANZARI_DETALII`.
-
-| Ce trebuie pe linie | `cursor_retur_document(V_COPIERE=1)` | `FACT_VFACTURI_DETALII` | Exista pe `VANZARI_DETALII`? |
-|---|---|---|---|
-| `ID_VANZARE_DET` (cheia liniei) | **NU** | **DA** | DA |
-| `TAXCODE` | **NU** | **DA** | DA |
-| `EXPLICATIE` | DA | DA | DA |
-| `ID_POL` (politica de pret pe linie) | DA | **NU** (doar `NUME_LISTA_PRETURI`) | DA |
-| `PRETD` / `ID_VALUTAD` | DA (`PRETD`) | **NU** | DA |
-| `GESTIONABIL` (flag calculat) | DA (calculat, vezi 1.4) | **NU** | — (derivat din `ID_GESTIUNE`) |
-| `DIFERENTA` | pliata in `PRET` (vezi 1.4) | **NU** | DA |
-| `ID_GESTIUNE`, `LOT`, `SERIE`, `CANTITATE`, `PRET`, `PRET_CU_TVA`, `PROC_TVAV`, `ID_JTVA_COLOANA`, `ID_JTVA_COLOANA_EX`, `PRET_ACHIZITIE`, `DISCOUNT_UNITAR`, `ID_VALUTA`, `CURS`, `MULTIPLICATOR` | DA | DA | DA |
-| `ID_CTR` / `NUMAR_CONTRACT` | **NU** | **DA** | DA (`ID_CTR`) |
-
-**Concluzia operationala: niciunul dintre cele doua canale nu e suficient singur [V].** Cele doua
-coloane care lipsesc din `cursor_retur_document` (`ID_VANZARE_DET`, `TAXCODE`) exista **amandoua pe
-`VANZARI_DETALII`**, deci sunt disponibile fara nicio schimbare de structura — lipseste doar din lista
-`SELECT`.
-
-**Trei variante, cu recomandare:**
-
-| Varianta | Ce cere | Risc |
-|---|---|---|
-| **(A)** adaugarea celor doua coloane in `SELECT`-ul lui `cursor_retur_document` | doua randuri in PL/SQL, plus `A1.ID_VANZARE_DET, A1.TAXCODE` in subselectul intern | Procedura e folosita si de **copiere** si (prin `cursor_retur`) de **retur**. Coloanele in plus ajung in `crsarticole` → `Scatter Name poArticol` → si `taxcode` **s-ar gathera** in `crsfactura` (campul exista deja acolo, `creeaza_facturacrs`, `ofacturare_comun.prg:1785`) **[V]**. Adica **copierea ar incepe sa transporte `taxcode`** — probabil o corectie, dar e o **schimbare de comportament pe o cale existenta**, nu una inerta. |
-| **(B) procedura noua**, `cursor_editare_document`, clona cu cele doua coloane in plus — **RECOMANDAT** | o procedura noua in `pack_facturare`, zero atingere pe cele existente | Duplicare de SQL (~100 randuri). Costul e intretinerea, nu regresia. Garantie de regresie zero **prin constructie**, in acelasi spirit ca solutia `SET_IDFACT` din S9. |
-| **(C)** citire din `FACT_VFACTURI_DETALII` (calea `relisteaza_ofacturare_stoc`) | zero cod Oracle nou | Pierde `ID_POL`, `PRETD`/`ID_VALUTAD`, `GESTIONABIL` si tratamentul `DIFERENTA`/valuta din `cursor_retur_document` — adica exact partea grea. Ar cere refacerea ei in VFP. |
-
-*Recomandare:* **(B)**, cu `SELECT`-ul copiat identic din `cursor_retur_document` plus
-`A1.ID_VANZARE_DET` si `A1.TAXCODE`, si cu ramura `GESTIONABIL` decisa explicit (1.4).
-
-### 1.2 Antetul — ce se incarca, si de unde [V]
-
-`poDate` e `oDateFactura` (`COMUN\programe\ofacturare_comun.prg:99-320`). Coloana „sursa" e coloana din
-`FACT_VFACTURI` (view-ul din spatele `crsFacturi`, folosit deja de `do_modifica`
-`ofacturare_comun.vc2:4560-4568` si de `relisteaza_ofacturare_stoc` `ofacturare_stoc.prg:504-509`),
-sau `VANZARI` direct.
-
-Legenda coloanei „azi": **CSD** = acoperit de `completeaza_setari_document(…, .T.)`; **GOL** = nimeni
-nu-l incarca azi pe calea de copiere, deci e **gol de umplut in S8**.
-
-#### (a) Identitatea documentului — antetul vizibil
-
-| `poDate.` | Sursa | Azi | Nota |
-|---|---|---|---|
-| `nIdTipDoc` (FACTURA/PROFORMA/BON) | derivat din `tip` + `eproforma` | **GOL** — linia e **comentata explicit** in CSD (`ofacturare_comun.prg:366`) | vezi 3.2 |
-| `tip` | `FACT_VFACTURI.TIP` | **GOL** (si azi **degradat** de `do_copiaza`) | S8 il pastreaza, per plan |
-| `eProforma` | `FACT_VFACTURI.EPROFORMA` | **GOL** — `eproforma` nu apare deloc in `ofacturare_comun.prg` (rezultatul 1 al rundei 13) | |
-| `serie_act` | `FACT_VFACTURI.SERIE_ACT` | **GOL** (CSD il pune doar in `.descriere`, ca text) | vezi 4.2 — conflict cu `poGeneratorNumere` |
-| `nract` | `FACT_VFACTURI.NUMAR_ACT` | **GOL** (idem) | idem |
-| `dataact` | `FACT_VFACTURI.DATA_ACT` | **GOL** (`Init` pune **azi**) | |
-| `datascad` | `FACT_VFACTURI.DATA_SCAD` | **GOL** (`Init` calculeaza din `gnZileScadentaFact`) | |
-| `zi_curs` | **NU EXISTA COLOANA** — vezi 1.5 | **GOL, si nerecuperabil** | raspuns la intrebarea deschisa din S8b §5.2 |
-| `in_valuta` / `id_valuta` / `nume_valuta` | `FACT_VFACTURI.IN_VALUTA` / `ID_VALUTA` / `NUME_VAL` | **GOL** (`Init` deriva `in_valuta` din `tip`) | |
-| `Curs` / `multiplicator` | `FACT_VFACTURI.CURS` / `MULTIPLICATOR` | **GOL** | pe linii, din `VANZARI_CURSURI` |
-
-#### (b) Partener si sursa
-
-| `poDate.` | Sursa | Azi |
-|---|---|---|
-| `id_client` / `nume_client` | `ID_PART` / `CLIENT` | **CSD** |
-| `cod_fiscal` | `FACT_VFACTURI.COD_FISCAL` | **GOL** |
-| `sold_lei` / `sold_valuta` | recalculate la deschidere (derivate, read-only) | **GOL** — se recalculeaza, nu se restaureaza |
-| `listaid` (id comanda / contract / lista avize) | vezi 1.6 | **CSD, dar cu valoare GRESITA pentru editare** — CSD scrie `.listaid = toDateAnterior.id_vanzare` (`ofacturare_comun.prg:383`) **[V]** |
-| `descriere` (nr. comanda/contract/avize) | `FACT_VFACTURI.ALTELE` / `COMANDA` / `CONTRACT` / `AVIZE` | **CSD, dar cu serie+numarul documentului insusi**, nu al sursei (`:384`) |
-| `id_gestiune_init` | `FACT_VFACTURI.ID_GESTIUNE` | **GOL** |
-| `id_pol` / `nume_politica` | **NU EXISTA pe `VANZARI`** — doar `VANZARI_DETALII.ID_POL` | **GOL** — vezi 1.5 |
-| `id_ctr` / `contract` | `VANZARI.ID_CTR` / `VANZARI.CONTRACT` | **GOL** |
-
-#### (c) Pliat — analitice (grupul A, read-only in #13, decizia 26)
-
-| `poDate.` | Sursa | Azi |
-|---|---|---|
-| `id_sectie` / `sectie` | `FACT_VFACTURI.ID_SECTIE` / `SECTIE` | **CSD** |
-| `id_lucrare` / `nrord` | `ID_LUCRARE` / `LUCRARE` | **CSD** |
-| `id_responsabil` / `responsabil` | **NU EXISTA pe `VANZARI`** | **GOL, si nerecuperabil din `VANZARI`** — liniile sunt **comentate** in CSD (`:369-370`) **[V]** |
-| `id_venchelt` / `venchelt` | **NU EXISTA pe `VANZARI`** | **GOL** — idem, comentate (`:373-374`) **[V]** |
-
-> Faptul ca `ID_RESPONSABIL` si `ID_VENCHELT` **nu sunt coloane pe `VANZARI`** (verificat pe
-> `all_tab_columns`) e **dovada structurala** ca grupul A traieste la nivel de **linie de nota**, nu de
-> antet — exact ce spunea `rute_scriere_antet.md`, dar acum cu argument de schema, nu de cautare. **[V]**
-
-#### (d) Pliat — alte date (`frm_alte_date`) si cei 14 parametri
-
-| `poDate.` | Sursa | Azi |
-|---|---|---|
-| `id_delegat` / `nume_delegat` / `BIdelegat` / `CNPdelegat` | `ID_DELEGAT` / `DELEGAT` / `BIDELEGAT` / `CNPDELEGAT` | **CSD** |
-| `id_masina` / `nrinmat` | `ID_MASINA` / `NRINMAT` | **CSD** |
-| `id_agent` / `nume_agent` | `ID_AGENT` / `NUME_AGENT` | **CSD** |
-| `id_facturare` / `adresa_facturare` | `ID_FACTURARE` / `ADRESA_FACTURARE` | **GOL** |
-| `dataora_exp` | `DATAORA_EXP` | **GOL** |
-| `text_aditional` | `TEXT_ADITIONAL` | **GOL** — plus capcana de la 1.7 |
-| `nListareDetaliata` | `LISTARE_DETALIATA` | **GOL** |
-| `tip_saft` | `TIP_SAFT` | **GOL** (`Init` pune `380`) |
-| `eFactura` | `EFACTURA` | **GOL** (`Init` pune `0`) |
-| *`id_ruta`* | `ID_RUTA` | **GOL, si nu exista proprietate pe `oDateFactura`** — vezi 1.5 |
-| `afisare_scadenta` | `AFISARE_SCADENTA` | **GOL** (`Init` pune `1`; ROACONTRACTE il recalculeaza) |
-| `tva_incasare` | `TVA_INCASARE` | **GOL** (`Init` ia `goCalendar.tva_incasare`) |
-| `institutie_publica` | `FACT_VFACTURI.INSTITUTIE_PUBLICA` | **GOL** |
-| `nTipFactura` | `TIP_FACTURA` | **GOL** |
-| `nIdBeneficiar` | `ID_BENEFICIAR` | **GOL** |
-| `id_ordl` | `ID_ORDL` | **GOL** |
-| `coeficient_k` | `VANZARI.COEFICIENT_K` | **GOL** |
-| grupul C (`ntip_incasare`, `serie_chit`, `nr_incasare`, `incasat`, `id_casa`) | `TIP_INCASAT`, `SERIE_INCASAT`, `NR_INCASAT`, `SUMA_INCASAT` | **GOL** — blocat in etapa I, dar vezi 2.3 |
-
-#### (e) Discountul de document — nu e in `poDate`
-
-**[V]** Discountul de document **nu are proprietate pe `oDateFactura`**: traieste in proprietatile
-formularului `frm_facturare_articole.ndiscfactron` / `.ndiscfactval`
-(`ofacturare.vc2:5286-5287` declaratie `*p:`, `:5317-5318` initializare la `0`,
-`:11325`/`:11337` `ControlSource` pe cele doua textbox-uri, `:14272-14274` citirea la scriere).
-
-| Ce | Sursa | Cum se incarca |
-|---|---|---|
-| discount de document, lei | `VANZARI.DISCOUNT` (in lei cand `IN_VALUTA=0`) | `Thisform.ndiscfactron` |
-| discount de document, valuta | `VANZARI.DISCOUNT` (in valuta cand `IN_VALUTA=1`) | `Thisform.ndiscfactval`, plus `ndiscfactron = Round(ndiscfactval * Curs / multiplicator, …)` |
-| `discount_evidentiat` | `VANZARI.DISCOUNT_EVIDENTIAT` | `poDate.discount_evidentiat` (`ControlSource` la `ofacturare.vc2:11305` si `:15968`) |
-
-**Precedentul exact exista** si trateaza deja bifurcatia lei/valuta:
-`ofacturare_stoc.prg:553-561` **[V]** — `lnDiscountVal = discount` cand `in_valuta = 1`, altfel
-`lnDiscount = discount`. S8 copiaza acest tipar.
-
-**Atentie [V]:** `oDateFactura.Init` pune `.discount_evidentiat = IIF(TYPE('gnDiscountEvidentiat')='N',
-gnDiscountEvidentiat, 1)` (`ofacturare_comun.prg:238`) — **optiunea de firma, nu valoarea documentului**.
-Daca S8 nu suprascrie, un document emis pe alta setare apare cu discountul evidentiat altfel decat a
-fost emis, si — pentru ca `discount_evidentiat` **atinge sumele** (e parametru al lui `scrie_factura2`,
-`ofacturare.vc2:14358`) — ar declansa **regenerare la simpla deschidere**. Fals pozitiv de acelasi tip
-cu lookup-ul delegatului, dar cu efect mai scump.
-
-### 1.3 Liniile — inventar
-
-Coloanele intoarse de `cursor_retur_document(V_COPIERE=1)`, in ordinea din `SELECT`
-(`PACK_FACTURARE:3963-4022`) **[V]**: `ID_C` (=`ROWNUM`), `ID_ARTICOL`, `LOT`, `SERIE`, `ID_POL`,
-`ID_VALUTA`, `DISCOUNT_UNITAR`, `DISCOUNT_UNITAR_VAL`, `CODMAT`, `CODBARE`, `DENUMIRE`, `UM`,
-`GESTIONABIL`, `CANTITATE`, `PROC_TVAV`, `ID_JTVA_COLOANA`, `PRETURI_CU_TVA`, `CURS`, `MULTIPLICATOR`,
-`PRET`, `PRET_VAL`, `TIP_VALUTA`, `NUME_VAL`, `EXPLICATIE`, `ID_GESTIUNE`, `PRET_ACHIZITIE`, `PRETD`,
-`ID_JTVA_COLOANA_EX`.
-
-**Lipsesc, si sunt necesare pentru S8/S8b:** `ID_VANZARE_DET`, `TAXCODE`, `ID_CTR`, `CODMATC`,
-`COD_UM_ISO`, `CONT`. Ultimele trei sunt in `crsfactura` si vin azi pe alte cai
-(`do_adauga_articol` cere `codmatf` cu un `SELECT` separat, `ofacturare.vc2:12932-12934` **[V]**).
-
-### 1.4 Doua capcane in `cursor_retur_document`, ambele verificate direct
-
-**(i) `GESTIONABIL` cu `V_COPIERE = 1` vine din nomenclatorul CURENT, nu din document [V]**
-(`PACK_FACTURARE:3990-3997`):
-
-```
-(case when V_PROFORMA = 1 then 0
- when V_COPIERE = 1 then B.IN_STOC -- NOM_ARTICOLE, starea de AZI
- else A.GESTIONABIL -- NVL2(A1.ID_GESTIUNE,1,0), starea DOCUMENTULUI
- end) AS GESTIONABIL
-```
-
-Pentru **copiere** e corect (documentul nou se emite cu regulile de azi). Pentru **editare** e o
-divergenta tacuta: un articol care a fost facturat gestionabil si intre timp a fost trecut pe
-`IN_STOC = 0` (sau invers) se incarca cu **alt regim** decat cel cu care e scris in `VANZARI_DETALII`.
-Efectul practic: articolul trece pe alta ramura in `do_adauga_articol` (dialog de stoc vs. fara),
-deci se schimba si ce se descarca la reemitere. **Recomandare: pe calea de editare se foloseste
-`A.GESTIONABIL` (ramura `else`), adica adevarul documentului** — argument suplimentar pentru varianta
-(B) din 1.1. **Aceasta e a cincea valoare din rezultatul 6 al handoff-ului (`IN_STOC` din nomenclator),
-regasita pe calea de CITIRE, nu doar pe cea de scriere.**
-
-**(ii) `PRET` vine rotunjit si cu `DIFERENTA` pliata inauntru [V]** (`PACK_FACTURARE:4008-4014`):
-`ROUND(...) + A.DIFERENTA`. Confirma rezultatul 6 din handoff. Consecinta directa pentru **S8b**:
-comparatia de pret la confirmare trebuie facuta pe **aceasta forma** (rotunjita + `DIFERENTA`), nu pe
-`VANZARI_DETALII.PRET` brut — altfel orice document cu `DIFERENTA <> 0` apare modificat la deschidere.
-
-### 1.5 Trei campuri de antet care nu au unde sa fie salvate — deci nu se pot restaura [V]
-
-Verificat pe `all_tab_columns` pentru `VANZARI`:
-
-| Camp | Constatare | Ce inseamna pentru S8 |
-|---|---|---|
-| **`zi_curs`** | **Nu exista coloana `ZI_CURS` pe `VANZARI`.** Se stocheaza rezultatul (`CURS`, `MULTIPLICATOR`, si `VANZARI_CURSURI` pe linie), nu ziua de la care s-a luat cursul. | **Inchide intrebarea deschisa din S8b §5.2.** Nu e „S8 trebuie sa suprascrie implicitul cu valoarea salvata" — **nu exista valoare salvata**. Se incarca `Curs`/`multiplicator` din document, iar `zi_curs` **se exclude din comparatie** si (recomandat) **se ascunde pe calea de editare**, ca sa nu sugereze o valoare pe care documentul n-o are. Ascunderea are precedent in acelasi `Do Case` (`ofacturare.vc2:9720-9725`, tipurile 8 si 9). |
-| **`id_pol`** (politica de preturi, antet) | Nu exista pe `VANZARI`; exista **pe linie** (`VANZARI_DETALII.ID_POL`). | Antetul nu are ce sa afiseze ca „politica documentului". Recomandat: pe editare se afiseaza politica **doar daca e unica pe toate liniile**, altfel gol — si e oricum **blocat** (grupul B, 3.1). |
-| **`id_ruta`** | Exista pe `VANZARI` (`ID_RUTA`) si e **unul din cei 14**, dar **`oDateFactura` nu are proprietate `id_ruta`** (verificat pe lista completa de proprietati, `ofacturare_comun.prg:99-218`). Azi valoarea circula prin `poRec` (`Scatter` din `crsfacturi`), nu prin `poDate` (`ofacturare_comun.vc2:4601`). | **Proprietate noua pe `oDateFactura`**, altfel `but_modifica` (S8c) n-are de unde sa citeasca ruta. Gol de umplut, semnalat aici pentru ca S8c il presupune existent. |
-
-### 1.6 Legatura cu sursa — `id_comanda`, `id_ctr`, lista de avize
-
-Ce exista, verificat:
-
-| Sursa | Unde e salvata | Citibila? |
-|---|---|---|
-| comanda | `VANZARI.ID_COMANDA` (+ `VANZARI.COMANDA`, text) **[V]** | **DA**, direct din `FACT_VFACTURI.ID_COMANDA` |
-| contract | `VANZARI.ID_CTR` (+ `VANZARI.CONTRACT`, text) **[V]** | **DA**, direct din `FACT_VFACTURI.ID_CTR` |
-| avize | `VANZARI_CORESP(ID_VANZARE_FACT, ID_VANZARE_AVIZ, TIP)` + `VANZARI.AVIZE` (text redundant) **[V]** (`PACK_FACTURARE:15494-15516`) | **DA ca date, NU ca procedura** — vezi mai jos |
-
-**[V] Nu exista in `pack_facturare` nicio procedura care sa CITEASCA lista sursa a unui document.**
-Cele 9 aparitii ale lui `VANZARI_CORESP` in export sunt: 6 in garzile lui `sterge_factura`
-(`:5454-5530`), 1 `UPDATE ... STERS = 1` tot acolo (`:5582`), 1 subselect in
-`scrie_cantitati_vanzari_avize` (`:6319`), 1 `INSERT` in `scrie_corespondente_vanzari` (`:15494`).
-**Citirea e cod nou** — un `SELECT` simplu, dar de scris:
-
-```sql
-SELECT ID_VANZARE_AVIZ FROM VANZARI_CORESP
- WHERE ID_VANZARE_FACT = :id AND STERS = 0 AND TIP = 1
-```
-
-**Semantica lui `TIP` nu e stabilita in acest raport [N]** — `scrie_corespondente_vanzari(V_TIP)`
-comuta doar sursa listei (`clistaid_avize` pentru `TIP = 1`, `clistaid` altfel, `:15485-15493`), iar
-valorile efective (`1/2/3`) vin din `CASE`-ul lui `finalizeaza_factura`, necitit aici. Handoff-ul
-rundei 13 le da ca `1/2/3` folosite, `4` liber. **De confirmat ramura cu ramura la implementare**, nu
-de preluat din raport — e exact tiparul care a produs cifra gresita a rundei 13.
-
-**Nota de proiectare:** `poDate.listaid` e **suprasolicitat**. Pe calea de copiere/editare el trebuie sa
-fie `id_vanzare`-ul documentului (ca `cursor_retur_document` sa-i citeasca liniile), dar pentru
-reemitere `pack_facturare.clistaid` / `clistaid_avize` trebuie sa contina **lista sursei originale**.
-Sunt **doua valori diferite in acelasi camp**, la momente diferite. Precedentul din
-`relisteaza_ofacturare_stoc` arata ca problema e veche si **nerezolvata**: acolo
-`poDate.listaid = Iif(poDate.tip = 3, Alltrim(Str(id_comanda)), [0])` **[V]**
-(`ofacturare_stoc.prg:531`) — cu ramura de **contract comentata** la `:529`, deci nici acel precedent
-nu restaureaza sursa pentru contracte sau avize. **S8 are nevoie de un camp separat**
-(propunere: `poDate.cListaSursa` + `poDate.cListaSursaAvize`), nu de o a doua semnificatie a lui
-`listaid`. Vezi si sectiunea 6.
-
-### 1.7 `text_aditional` — trei transformari intre ce se vede si ce se salveaza [V]
-
-1. **Truncat la 100 de caractere** la scriere: `LEFT(Nvl(poDate.text_aditional,[]),100)`
- (`ofacturare.vc2:14356`, identic pe toate ramurile `scrie_*`).
-2. **`CR+LF` inlocuit cu `Chr(170)`** imediat inainte:
- `poDate.text_aditional = Strtran(poDate.text_aditional, Chr(13)+Chr(10), Chr(170), 1, 100, 1)`
- (`:14281`) — **si atribuirea e pe `poDate` insusi**, deci obiectul ramane modificat dupa scriere.
-3. Pe calea `modifica_date_factura` **nu exista** nici truncare, nici substitutie
- (`ofacturare_comun.vc2:4608` trimite `?poRec.text_aditional` ca parametru legat) **[V]** —
- deci **cele doua rute salveaza forme diferite ale aceluiasi camp**.
-
-**Consecinte pentru S8:** la incarcare, `Chr(170)` trebuie convertit inapoi in `CR+LF` (altfel textul
-apare pe un rand cu caractere ciudate), iar comparatia din S8b trebuie facuta pe forma **normalizata**
-(vezi 5.2). Fara asta, orice document emis cu text pe mai multe randuri apare „modificat" la
-deschidere. **Nesemnalat pana acum in niciun raport.**
-
----
-
-## 2. Initializarile „pentru document nou" care trebuie sarite la editare
-
-Cerinta obligatorie din S8b, rezultatul 5, plus inventarul cerut de briefing.
-
-### 2.1 Lookup-ul „ultimul delegat / ultima masina" — **garda exista deja** [V]
-
-`frm_alte_date.Init`, `COMUN\clase\ferestre_cere_date.vc2:3105-3208`. Codul real
-(`:3110-3136`) — si aici raportul S8b si planul descriu situatia **incomplet**:
-
-```
-If poDate.eProforma = 0
- If Empty(Nvl(poDate.id_delegat,0)) And Empty(Nvl(poDate.id_masina,0)) && :3111
- poDate.id_delegat = 0
- poDate.id_masina = 0
- ... cauta_date_ultima_factura[_tip](...) && :3118-3124
-```
-
-**Lookup-ul e deja conditionat de „ambele goale".** Deci:
-
-- pentru un document care **are** delegat sau masina salvate, e suficient ca **S8 sa populeze
- `poDate.id_delegat` / `id_masina` INAINTE de construirea lui `frm_alte_date`** — lookup-ul nu mai
- ruleaza, fara niciun cod nou. `completeaza_setari_document` le pune deja (1.2.d), deci pe calea de
- editare conditia e indeplinita **din ordinea de apel**, nu dintr-un semnal;
-- **riscul real ramane, dar e mai ingust decat il descrie S8b:** el se manifesta **exact pe documentele
- care n-au nici delegat, nici masina salvate** — un caz frecvent (multe facturi se emit fara delegat).
- Pentru acelea, lookup-ul umple `poDate` cu ultimul delegat al clientului, si atunci: ori documentul
- apare modificat, ori `modifica_date_factura` scrie **un delegat pe care documentul nu l-a avut
- niciodata**. Sub `modifica_date_factura` campul se scrie **neconditionat** (`ID_DELEGAT = V_ID_DELEGAT`,
- `PACK_FACTURARE:14462`) **[V]**, deci scrierea gresita e certa, nu probabila.
-
-**Mecanismul propus (minim, si in acord cu tiparul existent):** parametru nou pe `frm_alte_date.Init`
-sau — mai ieftin si mai greu de ratat — **o proprietate pe `poDate`**, `poDate.lEditare`, citita in
-conditia de la `:3111`:
-
-```
-If !poDate.lEditare And Empty(Nvl(poDate.id_delegat,0)) And Empty(Nvl(poDate.id_masina,0))
-```
-
-Argumentul pentru proprietate pe `poDate` si nu parametru: `frm_alte_date` **nu e singurul** formular
-care are initializari de acest tip (2.2), `poDate` e deja obiectul citit de toate, si e acelasi tipar
-cu `lCopiere`, care exista deja pe `oDateFactura` (`ofacturare_comun.prg:212`) **[V]**.
-
-**„Ce se intampla cand documentul chiar n-are delegat salvat":** cu garda de mai sus, `poDate.id_delegat`
-ramane `.NULL.` (valoarea implicita din declaratia de clasa), campul se afiseaza gol, iar la salvare
-`modifica_date_factura` primeste `NULL` si scrie `NULL` — **identic cu starea din baza**. Adica exact
-comportamentul dorit: documentul ramane cum a fost. Fara garda, valoarea devine `0` (atribuirea de la
-`:3112-3113`) **si apoi** rezultatul lookup-ului.
-
-> **Diferenta fata de S8b, spusa explicit:** S8b cerea „sarirea explicita a lookup-ului"; codul real
-> arata ca sarirea e **deja implicita** pentru documentele cu delegat, si e **necesara explicit** doar
-> pentru cele fara. Concluzia lui S8b (S8 trebuie sa faca ceva) ramane valida; **motivul si perimetrul
-> se schimba**, iar asta reduce riscul de la „primul document editat al unui client cu activitate
-> recenta" la „primul document **fara delegat** al unui client cu activitate recenta".
-
-### 2.2 Alte initializari de acelasi tip — inventar cu `fisier:linie` [V]
-
-Cautate in `oDateFactura.Init`, `frm_alte_date.Init`, `frm_date_factura.Init`, `frm_date_aviz.Init`.
-
-| # | Loc | Ce face | Efect pe calea de editare | Gravitate |
-|---|---|---|---|---|
-| 1 | `ofacturare_comun.prg:232-236` | `.Data`, `.dataireg`, `.dataact` = azi (sau ultima zi a lunii de lucru); `.datascad` din `gnZileScadentaFact`; `.zi_curs` = azi | Documentul apare cu **data de azi** si scadenta recalculata | **Mare** — atinge 2 din cei 4 campuri de identitate |
-| 2 | `ofacturare_comun.prg:238` | `.discount_evidentiat` = `gnDiscountEvidentiat` (optiune de firma) | Vezi 1.2.e — poate declansa **regenerare** la simpla deschidere | **Mare** |
-| 3 | `ofacturare_comun.prg:233` | `.tva_incasare` = `goCalendar.tva_incasare` (starea de azi a firmei) | Un document emis in alt regim se incarca cu regimul curent | Medie |
-| 4 | `ofacturare_comun.prg:237` | `.in_valuta = 1` pentru `tnIdSet` / `tnTip` din lista | Derivat din tip, nu din document — coincide de obicei, dar nu prin constructie | Mica |
-| 5 | `ofacturare_comun.prg:241-243` | `.initializeaza_politica_pret()` pentru tipurile 23, 30, 41 — apel `actualizeaza_politica_pret` | Politica **curenta**, nu cea a documentului | Medie (tipuri de transfer) |
-| 6 | `ofacturare_comun.prg:240` | `.initializeaza_setari_document()` → `actualizeaza_document(tip)` → `id_fdoc` / `fdoc` | Reconfigureaza tipul de document din setarile curente | Medie |
-| 7 | `ofacturare_comun.prg:245-283` | ramura **ROACONTRACTE** (`goContract`): suprascrie `id_client`, `nume_client`, `cod_fiscal`, `listaid`, `descriere`, `id_sectie`, `id_responsabil`, `id_valuta`, **si `.datascad = .dataact + lnScadentaIncasare`**, **si `.afisare_scadenta`** | Daca `goContract` exista in sesiune, **suprascrie antetul documentului editat cu datele contractului** | **Mare**, conditionata de context |
-| 8 | `ofacturare_comun.prg:288-316` | ramura **ROACOMENZI** (`goComanda`, `tnTip = 3`): idem, `id_client`, `listaid`, `descriere`, `id_sectie`, `sectie` | Idem | **Mare**, conditionata |
-| 9 | `ferestre_cere_date.vc2:3177-3179` | `If This.opt_incasat.Value = 2 → poDate.incasat = poDate.totalctva` | Suprascrie suma incasata cu totalul documentului | Medie (grup C, blocat in etapa I) |
-| 10 | `ferestre_cere_date.vc2:3166-3171` | `poDate.id_casa = gnid_part_casa` (casa implicita a firmei) | Suprascrie casa documentului | Medie (grup C) |
-| 11 | **`ferestre_cere_date.vc2:3183-3185`** | `IF poDate.tip = 2 AND poDate.afisare_scadenta = 0 AND AT([Scadenta la ], poDate.text_aditional) = 0` → **prefixeaza** `text_aditional` cu `„Scadenta la N zile."` | **A doua instanta a exact aceluiasi defect ca lookup-ul delegatului**, si pe un camp din cei 14: modifica `text_aditional` la `Init`, fara actiune a utilizatorului | **Mare** |
-| 12 | `ferestre_cere_date.vc2:3150` | `If poDate.incasat <> 0 → Thisform.opt_incasat.Value = 2` — atribuire programatica pe `opt_incasat` | Declanseaza `ProgrammaticChange` → `actualizeaza_tipincasare()` → alocare/dezalocare de numere de chitanta (riscul deja documentat in `s3b_alte_date_analitice.md` §4.3) | Medie |
-| 13 | `ofacturare.prg:207-209` | `poGeneratorNumere.ResetNumere()` + `creeaza_cursor_serii(nIdTipDoc)`, la fiecare trecere prin `factureaza` | **Aloca un numar nou** pe calea de emitere | **Mare** — vezi 4.2 |
-| 14 | `ofacturare.prg:184-193` | `Do Case` pe `tnTip` care forteaza `poDate.nIdTipDoc` (5 = FACTURA / 6 = AVIZ) **inainte** de `completeaza_setari_document` | Pe editare, `nIdTipDoc` trebuie sa vina din document (proforma = 23, bon = 3), nu din tip | Medie |
-
-**Nr. 11 merita subliniat**: garda lui (`AT([Scadenta la ], text_aditional) = 0`) il face inert pe un
-document de contract emis **cu acelasi numar de zile de scadenta**. Devine activ exact cand
-scadenta s-a schimbat de la emitere — adica precis cazul in care textul e cel vechi si trebuie
-pastrat. **Metoda `Destroy`/`Unload` face si operatia inversa** (`:3037-3038`: `Strtran(...,[])`),
-ceea ce inseamna ca pe calea normala prefixul e adaugat si scos in aceeasi sesiune; pe o cale de
-editare care **nu** trece prin acelasi `Unload`, prefixul ar ramane. **[D]** — n-am urmarit toate
-caile de iesire ale formularului.
-
-### 2.3 Regula generala propusa
-
-> **Orice camp al lui `poDate` populat prin apel Oracle sau dintr-o variabila globala/`go*` in
-> `Init`/`Load` e o sugestie pentru document nou, nu o valoare de document.** Pe calea de editare,
-> ordinea trebuie sa garanteze ca aceste sugestii **nu ajung sa se execute** (garda), nu doar ca sunt
-> **suprascrise dupa** (ceea ce ar merge pentru valori, dar **nu** pentru efectele secundare — nr. 12
-> si nr. 13 aloca numere, nu doar seteaza campuri).
-
----
-
-## 3. Ce se blocheaza la editare, si de ce
-
-### 3.1 Blocate — schimbarea lor ar insemna alt document
-
-| Camp / control | De ce | Ruta care ar lipsi oricum |
-|---|---|---|
-| **Tipul documentului** (`Ct_clb_fdoc`, `poDate.tip` / `nIdTipDoc`) | Tipul decide ce sursa se consuma, ce nota se scrie si ce garzi se aplica. `do_copiaza` il **degradeaza** tocmai pentru ca un document copiat nu mai poate reconsuma sursa (`ofacturare_comun.vc2:3694-3711`) **[V]**; la editare degradarea e interzisa prin plan, deci tipul e fix. | grupul B — nicio ruta de scriere pe loc |
-| **Sursa** (`Ct_clb_altele`) | Vezi 3.2 | grupul B |
-| **Clientul** (`Ct_clb_nume_client`) | Schimbarea partenerului rescrie `IREG_PARTENERI`, `ACT`, soldurile — alt document | grupul B |
-| **Valuta, `zi_curs`, gestiunea sursa, politica de preturi** | grupul B, decizia 25; in plus `zi_curs` si `id_pol` **n-au valoare salvata** (1.5) | grupul B |
-| **Grupul C** (incasare) | decizia 25; in plus `opt_incasat` are efect secundar de alocare (2.2 nr. 12) | grupul C |
-| **Grupul A** (venit/cheltuiala, sectie, responsabil, lucrare) | decizia 26 — read-only permanent in #13; in plus doua din patru **nu exista pe `VANZARI`** (1.2.c) | editarea e a lui #6 |
-
-### 3.2 `Ct_clb_altele` — verificarea ceruta explicit, cu doua corectii la plan [V]
-
-Planul (`:2952-2955`) spune: *„eticheta schimbata pe tip de `do_schimba_explicatia` („Nr. contract" /
-„Nr. comanda" / „Nr. factura" / „Nr. facturi" / „Locatie", `ofacturare.vc2:9633-9643`), eliminat azi
-din formular cand `gnScadereStoc = 0` si tipul e 1/5/10 fara copiere."*
-
-Citit ramura cu ramura din `frm_date_factura.Init` (`ofacturare.vc2:9563-9796`), `Do Case`-ul de la
-`:9615-9722`:
-
-**Corectia 1 — lista de etichete e incompleta.** Intervalul `9633-9643` din plan e corect ca interval,
-dar contine **sase** apeluri, nu cinci: `Nr. contract` (`:9633`, tip 2/6/52), `Nr. comanda` (`:9635`,
-tip 3), **`Nr. aviz / avize` (`:9637`, tip 4)**, `Nr. factura` (`:9639`, tip 7), `Nr. facturi`
-(`:9641`, tip 8/9), `Locatie` (`:9643`, tip 45). **Planul omite exact tipul 4** — cel pentru care
-`Ct_clb_altele` tine **lista de avize**, adica singura sursa care trebuie refurnizata lui S9
-(sectiunea 6). Omisiunea nu e cosmetica.
-
-**Corectia 2 — conditia de eliminare e mai larga decat cea din plan.** `ct_clb_altele` e scos
-(`RemoveObject`) in **trei** situatii, nu una:
-
-| Ramura | Conditie | Ce face |
-|---|---|---|
-| `:9616-9628` | `gnScadereStoc = 0 And Inlist(poDate.tip, 1, 5, 10, **48, 49**)` | daca `llCopiere` → eticheta `Nr. factura` (`:9623`); altfel **`RemoveObject('ct_clb_altele')`** (`:9627`) |
-| `:9651-9660` | **`gnScadereStoc = 1`** `And Inlist(poDate.tip, 1, 5, 10)` | idem (`:9653` / `:9658`) |
-| `:9705-9712` (in `Otherwise`) | `Inlist(poDate.tip, 48, 49)` | **`RemoveObject('ct_clb_altele')`** neconditionat |
-
-Deci: tipurile sunt **1, 5, 10, 48, 49** (nu doar 1/5/10), si eliminarea are loc si cand
-**`gnScadereStoc = 1`**, nu doar cand e `0`. Formularea din plan („`gnScadereStoc = 0` si tipul e
-1/5/10") descrie **una** din trei ramuri.
-
-**Consecinta pentru S8, si e in favoarea noastra:** pe ramurile 1 si 2, `llCopiere = .T.` **pastreaza**
-controlul si ii pune eticheta `Nr. factura`. Calea de editare, care va avea acelasi semnal ridicat
-(`lCopiere` sau `lEditare`), **mosteneste automat pastrarea controlului** — nu e nimic de adaugat, doar
-de **blocat**. Pe ramura 3 (tipurile 48/49) controlul e scos neconditionat; **[N]** n-am stabilit daca
-tipurile 48/49 intra in perimetrul etapei II.
-
-### 3.3 Ce ramane editabil
-
-Cei 14 parametri, prin `but_modifica` (S8c), **plus** liniile (cantitati, preturi, discounturi,
-explicatii, adaugari/stergeri) si discountul de document — care declanseaza regenerarea. Nimic din
-sectiunea 3.1.
-
----
-
-## 4. Ordinea reala de incarcare, si de ce conteaza
-
-### 4.1 Secventa propusa
-
-```
- 0. S7 a validat deja documentul (garzi) si a stabilit id_vanzare.
- 1. Citeste ANTETUL: SELECT ... FROM FACT_VFACTURI WHERE id_vanzare = :id
- 2. Citeste LISTA SURSA (avize) inainte de orice altceva: SELECT ... FROM VANZARI_CORESP (§6)
- 3. poDate = CreateObject("oDateFactura", 0, 0) <-- tnIdSet = 0 => Init NU ruleaza (§4.2)
- 4. poDate.lEditare = .T. <-- semnalul, inainte de orice formular
- 5. Populeaza poDate din antet: cei 14 + tip + eproforma + valuta/curs +
- discount_evidentiat + client + gestiune + sursa (cListaSursa / cListaSursaAvize)
- 6. Populeaza thisform.ndiscfactron / ndiscfactval din VANZARI.DISCOUNT
- 7. Citeste LINIILE (canalul din §1.1(B)) -> crsarticole
- 8. GARDA DE RECALCUL: thisform.lIncarcare = .T.
- 9. Umple crsfactura din crsarticole, fara dialoguri (§4.3)
-10. Adauga lista de preturi peste crsarticole (pentru S4g: adaugarea de articole noi)
-11. thisform.lIncarcare = .F.
-12. Un singur do_calculeaza_totaluri()
-13. SNAPSHOT pentru S8b (§5)
-14. Blocheaza antetul (S8c) si campurile din §3.1; arata formularul
-```
-
-### 4.2 De ce pasul 3 arata asa — `tnIdSet = 0` [V]
-
-Tot corpul lui `oDateFactura.Init` e inchis in `If !Empty(m.tnIdSet)` (`ofacturare_comun.prg:225`).
-Cu `tnIdSet = 0`, **niciuna dintre cele opt initializari de la 2.2 (nr. 1-8) nu se executa**, iar
-constructorul devine inert. **Precedentul exista si e chiar cel de reincarcare a unui document:**
-`relisteaza_ofacturare_stoc` face `poDate = Createobject("oDateFactura", 0, 0)`
-(`ofacturare_stoc.prg:497`) **[V]** exact din acest motiv.
-
-Asta rezolva **printr-o singura decizie de constructie** opt din cele paisprezece initializari
-periculoase, fara nicio modificare in `oDateFactura` — si e mult mai robust decat „suprascriem dupa",
-pentru ca nu depinde de completitudinea listei de suprascrieri.
-
-**Ce ramane de tratat separat, pentru ca nu trece prin `Init`:**
-- nr. 9-12 (`frm_alte_date.Init`) → garda `poDate.lEditare` de la 2.1;
-- **nr. 13, `poGeneratorNumere`** — e apelat din `factureaza` (`ofacturare.prg:207-209`), nu din
- `Init`. Pe calea de editare **nu trebuie sa se aloce numar**: seria si numarul vin din document
- (decizia F / plan §F). `oGeneratorNumere` are deja `dezaloca_numar` si `verifica_numar`
- (`ofacturare.prg:227`, `:250`), dar calea corecta e **sa nu se aloce deloc**. **[N]** —
- `COMUN\programe\oserii_numere.prg` n-a fost citit in aceasta sesiune; planul citeaza `:227-233`
- pentru afirmatia „la modificare nu se aloca numar nou". **De verificat la implementare** ca ocolirea
- alocarii nu lasa `poDate.rezultat_serii` intr-o stare pe care `frm_date_factura.Init` o citeste
- (`ofacturare.vc2:9736`: `If Inlist(poDate.rezultat_serii, 1, 2, 3) → clb_serie_act.do_initializeaza(...)`).
-
-### 4.3 Pasul 9 e piesa care lipseste azi — si e cea mai mare
-
-**[V]** Pe calea de copiere, `crsfactura` ramane gol; documentul se compune manual sau prin
-`do_adauga_tot`. `do_adauga_tot` (`ofacturare.vc2:13169-13198`) face `SCAN` peste `crsarticole` si
-cheama `do_adauga_articol(.T.)`, care (`:12871-12894`):
-
-- pe ramura `poArticol.gestionabil = 0 Or gnScadereStoc = 0 Or poDate.tip = 45` — creeaza
- `frm_articol_factura` **fara sa-l arate** (cu `tlImplicit = .T.`) si calculeaza totalurile. Acceptabil.
-- pe ramura `Otherwise` — cheama **`do_alege_stoc(...)`**, adica **dialogul de alegere din stocul de
- azi**. Pe calea de editare asta e gresit de doua ori: (a) ar putea cere interventia utilizatorului
- pentru fiecare linie gestionabila la simpla deschidere a documentului; (b) ar alege **loturi/serii
- din stocul curent**, desi documentul are deja `LOT`, `SERIE` si `ID_GESTIUNE` proprii, intoarse de
- cursor.
-
-In plus, `do_adauga_tot` are un `Do While` cu `aMessageBox("Nu ati selectat toata cantitatea …")`
-(`:13188`) — **un modal per linie neacoperita**. Inacceptabil la incarcare.
-
-Si `do_adauga_articol` scrie `Replace id_temp With Recno()` (`:12951` si `:13000`) **[V]** — deci chiar
-daca sursa ar avea `ID_VANZARE_DET`, **nu ar ajunge in `crsfactura` pe aceasta cale**.
-
-**Concluzie:** S8 nu poate refolosi `do_adauga_tot`. Ii trebuie o **populare directa**
-`crsarticole → crsfactura` (un `INSERT INTO crsfactura ... SELECT ...` plus recalculul valorilor pe
-linie prin `calculeaza_totaluri`), care:
-1. **nu deschide niciun dialog**;
-2. pastreaza `lot`, `serie`, `id_gestiune`, `id_pol`, `pretd` **din document**;
-3. duce `id_vanzare_det` intr-o coloana proprie noua pe `crsfactura` (**nu** in `id_temp`, care e
- suprasolicitat: `Recno()` pe o cale, `id_vanzare_det` pe alta — `prelucreaza_facturacrs` face
- `id_vanzare_det As id_temp`, `ofacturare_comun.prg:1811` **[V]**);
-4. duce `taxcode`.
-Precedentul de structura exista: blocul `tnTip = 30` din `factureaza`
-(`ofacturare.prg:340-378`) face exact o populare directa `crsarticole → crsfactura` prin
-`INSERT INTO crsfactura (...) Values (...)`, fara niciun dialog **[V]**. Se cloneaza forma lui.
-
-### 4.4 Garda de „nu recalcula acum" — unde, si de ce
-
-`crsfactura` e `RecordSource`-ul gridului, iar coloanele au `Valid`/`InteractiveChange` care
-recalculeaza. La populare programatica, `Valid` **nu** se declanseaza in VFP (se declanseaza doar la
-iesirea din control, pe interactiune) — deci riscul principal **nu** e in grid, ci in:
-
-- **`ControlSource` legate direct de `poDate`** (ex. `poDate.discount_evidentiat`,
- `ofacturare.vc2:11305`) — atribuirea programatica declanseaza `ProgrammaticChange`, nu `Valid`
- **[D]** (comportament VFP standard; nu l-am observat rulat aici);
-- **`opt_incasat.Value =`** — 2.2 nr. 12, efectul secundar documentat;
-- **`clb_discount.procent.Value =`** (`ofacturare.vc2:13475`) — daca S8 populeaza procentul de discount
- in loc de suma, `InteractiveChange` ar recalcula discountul pe baza curenta, care in timpul popularii
- e incompleta.
-
-**Recomandare concreta:** un singur flag pe formular, `Thisform.lIncarcare`, testat la intrarea in
-`do_calculeaza_totaluri` si in `actualizeaza_discount` (`ofacturare.vc2:13408-13415`), plus **regula ca
-discountul de document se incarca ca SUMA** (`ndiscfactron`/`ndiscfactval`, valorile pe care le citeste
-si scrierea, `:14272-14274`), **nu ca procent** — procentul se recalculeaza din suma la pasul 12
-(`:13475`: `procent.Value = Round(ndiscfactron * 100 / nbazafdiscount, 2)`), nu invers.
-
-### 4.5 Asezarea — decizia 5
-
-Nimic din cele de mai sus nu schimba aspectul: nu se adauga banda de avertizare, coloane cu valori
-initiale sau panou de diferente. Se schimba **titlul ferestrei** si **butonul principal** (decizia 9 /
-S8c). Diferentele vizibile fata de introducere sunt **doar** cele care rezulta din blocarea campurilor
-(3.1) si din ascunderea lui `zi_curs` (1.5) — ultima e o abatere minora de la „identic", propusa
-motivat, **de confirmat de Marius** (intrebarea 4, sectiunea 8).
-
----
-
-## 5. Interfata cu S8b — ce se retine ca „stare initiala"
-
-### 5.1 Momentul
-
-Snapshot-ul se ia la **pasul 13**: dupa incarcarea completa si dupa singurul recalcul, dar **inainte de
-afisarea formularului**. Nu mai devreme (valorile derivate n-ar fi calculate) si nu mai tarziu (orice
-`Init` de subformular ar putea polua — 2.2).
-
-### 5.2 Ce se retine, si in ce forma
-
-| Grup | Forma | Normalizare obligatorie inainte de comparatie |
-|---|---|---|
-| **Cei 14 parametri** | copie a valorilor din `poDate` (+ `id_ruta`, 1.5) intr-un obiect `poDateInitial` | `.NULL.` vs `0` vs `''` — functie unica aplicata **simetric**; `text_aditional`: **`LEFT(...,100)` + `Chr(170)`→`CR+LF`** pe ambele parti (1.7) |
-| **Discountul de document** | `ndiscfactron` si `ndiscfactval`, **ca sume** | `Round(..., gnPc)` / `Round(..., gnPVal)` |
-| `discount_evidentiat` | scalar | — |
-| **Liniile** | copie a lui `crsfactura`, cheia = **`id_vanzare_det`** (coloana noua, 4.3) | `Round` la `gnPc` / `gnPPretV` / `gnPCant`; pretul comparat in forma **rotunjita + `DIFERENTA`** (1.4.ii) |
-| **Explicatie / taxcode pe linie** | in aceeasi copie | `Alltrim`, `Nvl(...,'')` |
-
-**Trei precizari care corecteaza sau completeaza S8b:**
-
-1. **Cheia `id_vanzare_det` nu vine gratuit** — S8b o presupunea incarcata („coloana deja incarcata la
- S8"). Nu e (1.1). Devine **livrabil al lui S8**, nu premisa.
-2. **Liniile fara `id_vanzare_det`** (adaugate in sesiune) se marcheaza cu `0`/`.NULL.` si inseamna
- direct „regenerare", ca in S8b §1.3.
-3. **`zi_curs` se scoate din comparatie** (1.5) — altfel orice document ar aparea modificat.
-
-### 5.3 Cele 7 campuri comune `scrie_factura2` / `modifica_date_factura`
-
-Nimic de adaugat la S8b §3.1 — lantul cu prioritate ramane. S8 doar garanteaza premisa lui: **`poDate`
-contine, la momentul confirmarii, valorile documentului plus editarile utilizatorului si nimic altceva**
-— ceea ce e exact ce asigura sectiunile 2 si 4.
-
----
-
-## 6. Interfata cu S9 — ce trebuie sa incarce S8 ca S9 sa poata refurniza lista sursa
-
-Pasul 1 nou al lui S9 (handoff, rezultatul 7) cere **citirea listei sursa inainte de stergere**. S8 e
-locul unde se citeste, pentru ca **dupa stergere `VANZARI_CORESP` are `STERS = 1`** (`:5582` **[V]**) si
-`VANZARI.ID_COMANDA` / `ID_CTR` raman pe randul soft-sters.
-
-**Ce incarca S8, si de unde:**
-
-| Ce | Camp propus pe `poDate` | Sursa | Consumator la reemitere |
-|---|---|---|---|
-| lista de avize | `cListaSursaAvize` | `SELECT ID_VANZARE_AVIZ FROM VANZARI_CORESP WHERE ID_VANZARE_FACT = :id AND STERS = 0 AND TIP = 1` | `pack_facturare.clistaid_avize` → `scrie_corespondente_vanzari(1)` si `marcheaza_facturat` |
-| comanda | `cListaSursa` | `FACT_VFACTURI.ID_COMANDA` | `pack_facturare.clistaid` |
-| contract | `cListaSursa` (+ `id_ctr`) | `FACT_VFACTURI.ID_CTR` | idem, plus `CTR_RATE_FACTURI` |
-| tipul original | `poDate.tip`, nedegradat | `FACT_VFACTURI.TIP` | `CASE`-ul pe `ntip` din `finalizeaza_factura` |
-
-**Doua avertismente:**
-
-1. **`poDate.listaid` NU poate purta aceasta informatie** — la incarcare el trebuie sa fie
- `id_vanzare`-ul documentului insusi, ca sa se citeasca liniile (1.6). Doua campuri distincte,
- nu unul reinterpretat.
-2. **Semantica valorilor lui `TIP`** din `VANZARI_CORESP` **nu e stabilita aici [N]** (1.6) — se
- citeste din `CASE`-ul real al lui `finalizeaza_factura` la implementare.
-
-**Nu tine de S8**, dar se semnaleaza pentru ca S8 decide continutul lui `crsarticole`:
-`do_scrie_factura` face `Select crsarticole` + `Calculate Sum(cantitate) To lnCantitateRamasa` pe
-ramurile `poDate.Tip = 4` (`ofacturare.vc2:14305-14307`) si `Inlist(poDate.Tip,3,21,25,28,42,47)`
-(`:14336-14338`) **[V]**, si pe baza sumei intreaba *„Doriti sa se inregistreze si avizul de retur?"* /
-*„Doriti sa se inchida comanda?"* si seteaza `pnParametruAditional`. Pe calea de editare `crsarticole`
-contine liniile documentului **plus lista de preturi adaugata peste ele** (`ofacturare.prg:465-473`
-**[V]**), deci **suma e lipsita de sens** si intrebarea ar aparea gresit, cu efect real pe
-`pnParametruAditional`. **De rezolvat in S9** — fie prin cursor separat pentru lista de preturi, fie
-prin calcularea sumei doar peste randurile provenite din document.
-
----
-
-## 7. Criteriul „gata cand", in forma testabila
-
-**Comun tuturor tipurilor.** Pe un document existent, dupa deschidere si **inainte** de orice
-interactiune:
-
-| # | Ce se verifica | Cum |
-|---|---|---|
-| C1 | serie, numar, data, scadenta afisate = cele din `VANZARI` | comparatie ecran ↔ `SELECT serie_act, numar_act, data_act, data_scad FROM vanzari WHERE id_vanzare = :id` |
-| C2 | **niciun numar nou alocat** | inainte/dupa: ultimul numar din generatorul de serii pentru `nIdTipDoc` e neschimbat |
-| C3 | numarul de linii din grid = `SELECT count(*) FROM vanzari_detalii WHERE id_vanzare = :id AND sters = 0` | |
-| C4 | pe fiecare linie: cantitate, pret, discount, gestiune, lot, serie, cota TVA, explicatie, `taxcode` = valorile din `VANZARI_DETALII` (pret in forma rotunjita + `DIFERENTA`, 1.4.ii) | |
-| C5 | totalurile afisate = `VANZARI.TOTAL_FARA_TVA` / `TOTAL_TVA` / `TOTAL_CU_TVA` | |
-| C6 | discountul de document si `discount_evidentiat` = `VANZARI.DISCOUNT` / `DISCOUNT_EVIDENTIAT` | |
-| C7 | delegat, masina, agent, adresa de facturare, `dataora_exp`, `text_aditional`, `listare_detaliata`, `tip_saft`, `efactura`, `id_ruta` = `VANZARI` | inclusiv **cazul „documentul n-are delegat"** → campul ramane gol (2.1) |
-| C8 | **nicio scriere in baza** — criteriul de baza al lui S8b | `SELECT dataoras, id_utils FROM vanzari WHERE id_vanzare = :id` neschimbat dupa deschidere+inchidere; idem pe `VANZARI_DETALII` |
-| C9 | **niciun dialog modal** la deschidere (nici alegere de stoc, nici „nu ati selectat toata cantitatea", nici „doriti sa inchideti comanda") | observatie |
-| C10 | aspectul e cel de introducere (decizia 5): fara banda, fara coloane de valori initiale, fara panou de diferente; difera doar titlul si butonul principal | observatie |
-
-**Pe fiecare tip de sursa, in plus:**
-
-| Tip | Ce se verifica specific |
-|---|---|
-| **comanda** (3, 21, 25, 28, 42, 47) | `Ct_clb_altele` afiseaza numarul comenzii, eticheta „Nr. comanda", **blocat**; `poDate.cListaSursa` = `VANZARI.ID_COMANDA` |
-| **contract** (2, 6, 26, 52) | eticheta „Nr. contract", blocat; `id_ctr` incarcat; **`goContract` din sesiune NU suprascrie antetul** (2.2 nr. 7); daca S10 se implementeaza, **niciun avertisment de re-derivare la simpla deschidere** (`cursor_retur_document` citeste pretul stocat, rezultatul 6 al handoff-ului) |
-| **aviz** (tip 4 = factura din avize) | eticheta **„Nr. aviz / avize"** (3.2), blocat; `poDate.cListaSursaAvize` = randurile `VANZARI_CORESP` ale documentului; **nicio intrebare „doriti sa se inregistreze si avizul de retur?"** la deschidere (§6) |
-| **factura simpla** (1, 5, 10) | `Ct_clb_altele` **pastrat si vizibil** cu eticheta „Nr. factura" (3.2, ramurile 1 si 2 cu `llCopiere`), spre deosebire de emiterea normala unde e scos |
-| **retur** (8, 9, 24) | `zi_curs` e oricum scos azi pentru 8/9 (`ofacturare.vc2:9720-9725`) — comportament neschimbat; liniile se incarca cu cantitatile documentului, nu cu cele disponibile la retur |
-| **ROAAUTO** | `poDate.id_ordl` incarcat din `VANZARI.ID_ORDL`; **[N]** nu s-a verificat in aceasta sesiune ce alte campuri specifice ROAAUTO exista pe antet — `roaauto_facturi.md` nu a fost citit |
-| **proforma** (`eproforma = 1`) | `poDate.eProforma` incarcat (1.2.a) → `frm_alte_date.Init` sare din start pe ramura de proforma (`:3110`), iar `gestionabil` vine `0` din cursor (1.4) |
-
----
-
-## 8. Riscuri, goluri ramase, si intrebarile pentru Marius
-
-### 8.1 Ce n-am putut stabili, si de ce
-
-| # | Ce | De ce |
-|---|---|---|
-| N1 | Semantica exacta a valorilor `VANZARI_CORESP.TIP` (`1/2/3`, `4` liber) | Cere citirea `CASE`-ului pe `ntip` din `finalizeaza_factura`, in afara perimetrului parcurs. **Nu se preia din raportul precedent** — e exact tiparul cifrei gresite din runda 13. |
-| N2 | Daca ocolirea alocarii de numar lasa `poDate.rezultat_serii` intr-o stare pe care `frm_date_factura.Init` o citeste gresit (`ofacturare.vc2:9736`) | `COMUN\programe\oserii_numere.prg` necitit in aceasta sesiune |
-| N3 | Daca prefixul „Scadenta la N zile." adaugat la `Init` (2.2 nr. 11) e scos pe **toate** caile de iesire | Am vazut operatia inversa la `ferestre_cere_date.vc2:3037-3038`, dar n-am urmarit toate caile de `Unload`/`Destroy` |
-| N4 | Campurile de antet specifice **ROAAUTO** | `roaauto_facturi.md` necitit |
-| N5 | Daca tipurile **48/49** (custodie) intra in perimetrul etapei II | Conteaza pentru 3.2, ramura 3 |
-| N6 | Daca `frm_facturare_articole2` (varianta paralela) trebuie tratata identic | Are `do_adauga_tot` / `do_adauga_articol` proprii (`ofacturare.vc2:17476`, `:17124`), cu logica usor diferita (fara testul `llGestionabil`) — **de decis daca S8 tinteste ambele forme sau doar `frm_facturare_articole`** |
-
-### 8.2 Intrebari pentru Marius, cu recomandare
-
-1. **Canalul de citire a liniilor: (A) extindem `cursor_retur_document`, (B) procedura noua
- `cursor_editare_document`, sau (C) `FACT_VFACTURI_DETALII`?** (1.1)
- *Recomandare:* **(B)**. Argumentul nu e estetica, ci ca (A) schimba **comportamentul copierii**
- (`taxcode` ar incepe sa se propage), iar (C) pierde `ID_POL`, `PRETD` si tratamentul valutar —
- partea grea. (B) da si libertatea de a alege corect `GESTIONABIL` (1.4.i).
-
-2. **`GESTIONABIL` la editare: din nomenclatorul de azi (`IN_STOC`) sau din document (`ID_GESTIUNE`)?**
- (1.4.i)
- *Recomandare:* **din document**. Un document editat trebuie sa arate cum a fost emis; regimul de
- stoc al articolului s-a putut schimba intre timp fara nicio legatura cu documentul.
-
-3. **`text_aditional`: se normalizeaza la incarcare (`Chr(170)` → `CR+LF`) sau se afiseaza ca atare?**
- (1.7)
- *Recomandare:* **se normalizeaza la incarcare si se re-normalizeaza la comparatie**, altfel orice
- document cu text pe mai multe randuri apare modificat la deschidere. Nota: cele doua rute de scriere
- salveaza **forme diferite** ale campului (truncat/substituit vs. brut) — merita semnalat separat,
- e un defect preexistent, nu al lui #13.
-
-4. **`zi_curs` pe calea de editare: ascuns, sau afisat gol?** (1.5)
- *Recomandare:* **ascuns**, cu precedent in acelasi `Do Case` (tipurile 8/9). E o abatere mica de la
- decizia 5, si o semnalez ca atare — un camp afisat gol pe un document care are curs ar fi mai
- derutant decat absenta lui.
-
-5. **`poDate.lEditare` ca proprietate pe `oDateFactura`, sau parametru pe `frm_alte_date.Init`?** (2.1)
- *Recomandare:* **proprietate**, pentru ca sunt **cel putin patru** locuri care au nevoie de semnal
- (2.2 nr. 9-13), nu unul, si pentru ca `lCopiere` e deja acolo, cu exact acelasi rol.
-
-6. **`id_ruta` — proprietate noua pe `oDateFactura`?** (1.5)
- *Recomandare:* **da**. Fara ea S8c nu poate implementa unul din cei 14 parametri, iar azi valoarea
- circula doar prin `poRec`, care nu exista in formularul unificat.
-
-7. **Tipurile 48/49 si `frm_facturare_articole2`** (N5, N6) — intra in perimetrul etapei II?
- *Recomandare:* **nu acum**; se declara explicit ca neacoperite, ca sa nu se descopere la testare.
-
-8. **Defectul de la 2.2 nr. 11** (prefixarea `text_aditional` la `Init` pentru contracte) — se repara
- in #13, se semnaleaza separat, sau se lasa?
- *Recomandare:* **se ocoleste in #13** (prin `lEditare`) si **se semnaleaza separat** ca defect
- preexistent — repararea lui pe calea de emitere nu tine de aceasta poveste.
-
-### 8.3 Ce a fost corectat fata de materialele existente
-
-| Afirmatie anterioara | Stare |
-|---|---|
-| S8b: „lookup-ul delegatului trebuie sarit explicit, altfel pica primul criteriu" | **Nuantat** — garda `Empty(id_delegat) And Empty(id_masina)` exista deja (`ferestre_cere_date.vc2:3111`); riscul e real **doar** pe documentele fara delegat si fara masina |
-| S8b §1.2 / §7.4: „cheia de linie `id_vanzare_det`, coloana deja incarcata la S8" | **Infirmat** — `cursor_retur_document` nu o intoarce; devine livrabil al lui S8 |
-| S8b §5.2: „S8 trebuie sa suprascrie implicitul `zi_curs` cu data reala salvata" | **Infirmat structural** — nu exista coloana `ZI_CURS` pe `VANZARI` |
-| Plan S8: etichetele lui `Ct_clb_altele` (cinci) | **Incomplet** — sunt sase; lipseste „Nr. aviz / avize" (tip 4), exact cazul relevant pentru S9 |
-| Plan S8: „eliminat cand `gnScadereStoc = 0` si tipul e 1/5/10 fara copiere" | **Incomplet** — trei ramuri, tipurile `1,5,10,48,49`, si pentru `gnScadereStoc = 1`, nu doar `0` |
-| Plan S8: „`cursor_retur_document(V_COPIERE=1)` pentru linii" | **Insuficient** — umple selectorul, nu documentul; lipsesc `ID_VANZARE_DET` si `TAXCODE` |
-| Plan S8: „`completeaza_setari_document` pentru antet" | **Insuficient** — 16 proprietati din ~120, niciuna de identitate |
-
----
-
-*Cercetare incheiata pe toate cele 8 puncte cerute in briefing. Afirmatiile portante au `fisier:linie`
-sau nume de coloana din dictionar. Nu s-a modificat niciun fisier de cod; pe Oracle numai `SELECT` pe
-`all_tab_columns`.*
diff --git a/docs/cercetare/s8b_rutarea_scrierii.md b/docs/cercetare/s8b_rutarea_scrierii.md
deleted file mode 100644
index 37e983e..0000000
--- a/docs/cercetare/s8b_rutarea_scrierii.md
+++ /dev/null
@@ -1,311 +0,0 @@
-# S8b — Proiectare: rutarea scrierii dupa ce utilizatorul a schimbat ceva
-
-Livrabilul povestii **S8b** din `docs\plan_13_unificare_formular_facturare.md:2890-2898` (G-bis,
-deciziile 6/9/25/26). Cercetare READ-ONLY — zero editari de cod, zero `git_sync.ps1`/`txt2vcx.ps1`,
-zero commit, zero scriere Oracle (doar SELECT, nefolosit efectiv — tot ce trebuia era in codul VFP/
-PL-SQL deja exportat sau in rapoartele de referinta citate in briefing).
-`COMUN\clase\ofacturare_comun.vc2` si `COMUN\programe\ofacturare_editare.prg` (perimetrul #6) doar
-citite, neatinse.
-
-## Verdict (rezumat, 8 randuri)
-
-Reteta din G-bis e corecta ca directie, dar are un gol nedocumentat pana acum: **`modifica_date_factura`
-nu e singura ruta care scrie cei 14 parametri de antet** — 7 din 14 (`id_delegat`, `id_masina`,
-`id_facturare`, `listare_detaliata`, `dataora_exp`, `id_agent`, `text_aditional`) sunt scrisi **si**
-de calea normala de emitere (`scrie_factura2`, apelata direct de regenerare, decizia 35), pentru ca
-ambele cai citesc din **acelasi obiect `poDate`**, nu din doua reprezentari separate (sectiunea 3,
-dovada pe cod). Consecinta directa pentru punctul cel mai periculos al sarcinii (schimbare simultana
-antet+sume): **cand regenerarea porneste, NU se mai cheama `modifica_date_factura` in plus** — ar fi
-fie redundant (pe cele 7 campuri comune), fie periculos (ar scrie pe un `ID_VANZARE` care tocmai a
-fost soft-sters sau inca nu exista). Regenerarea *este* deja calea de scriere a antetului cand sumele
-se schimba, nu o cale separata care trebuie compusa cu ea. Explicatia de linie e acoperita direct de
-`adauga_articol_factura` (parametru `V_EXPLICATIE`, plus `V_TAXCODE`), deci regenerarea o transporta
-fara cod suplimentar — dar **doar daca cursorul de linii incarcat la S8 e re-citit din formular, nu
-din snapshot-ul initial**. Cel mai probabil loc de fals-pozitiv pentru „deschid si inchid fara sa
-modific nimic” e lookup-ul „ultimul delegat/masina al clientului” din `frm_alte_date.Init`
-(sectiunea 5) — cod construit pentru emiterea unui document nou, periculos daca ruleaza neschimbat pe
-calea de editare.
-
----
-
-## 1. Mecanismul de detectare a schimbarii
-
-### 1.1 Optiuni si ce se strica la fiecare
-
-| Optiune | Ce se strica |
-|---|---|
-| **Hash/checksum pe randuri** | Ascunde exact tipul de fals-pozitiv cel mai periculos aici: doua reprezentari numeric-egale dar text-diferite (`Str(12.5,18,2)` vs `Str(12.50,18,2)`, `.NULL.` vs `0` vs `""`) produc hash-uri diferite desi valoarea „reala" e identica. Orice normalizare facuta *inainte* de hash trebuie sa fie deja perfecta — hash-ul nu adauga nimic, doar ascunde bug-urile de normalizare in loc sa le arate. |
-| **Flag-uri `lModificat` in evenimentele de editare** | E robust doar daca *fiecare* eveniment care poate schimba o valoare seteaza flag-ul — un `ControlSource` legat direct (binding automat VFP, cazul majoritatii campurilor de antet aici, vezi `modifica_date_factura_parametri.md` §4) nu trece printr-un eveniment scriptat, deci flag-ul ramane `.F.` desi valoarea s-a schimbat. Whitelist fragil: la fiecare control nou adaugat, cineva trebuie sa-si aminteasca sa cablasje flag-ul. Cel mai riscant pentru campurile din `frm_alte_date` (S3b), unde `ControlSource=poDate.xxx` e tiparul dominant. |
-| **Snapshot la incarcare + comparatie camp cu camp la confirmare** (recomandat) | Cere disciplina la normalizare (precizie, `.NULL.`), dar e singura optiune care **nu poate rata o schimbare structurala** — compara starea finala, nu istoricul de evenimente, deci un binding automat care a schimbat o valoare fara eveniment scriptat tot apare in diff. E si optiunea deja folosita implicit in codebase pentru un caz inrudit: `chkSerieAct.Enabled = !EMPTY(NVL(poRec.numar_act,0))` (`ofacturare_comun.vc2:5736`) testeaza starea curenta, nu un istoric de evenimente. |
-
-**Recomandare: snapshot + comparatie la confirmare**, din motivul de mai sus (robustete la binding
-automat) — argumentat, nu doar preferat.
-
-### 1.2 Ce se snapshoteaza, concret
-
-- **Antet**: o copie profunda a lui `poDate` (sau a subsetului de proprietati relevante) luata
- imediat dupa S8 (incarcare), **inainte** de orice lookup auto-completat (vezi sectiunea 5 — ordinea
- conteaza: daca lookup-ul „ultimul delegat" ruleaza inainte de snapshot, snapshot-ul insusi e deja
- poluat, si orice comparatie ulterioara devine inutila).
-- **Linii**: o copie a cursorului `crsfactura` (nume alias de confirmat la implementare — S4d il
- citeaza ca atare) imediat dupa populare la S8, cu cheia de linie **`id_vanzare_det`** (coloana deja
- incarcata la S8 din `VANZARI_DETALII`, cf. plan S8: „explicatia si taxcode pe fiecare linie" — nu
- exista alt candidat de cheie stabila in materialele citite; **de confirmat exact numele coloanei in
- cursor la implementare**, nu presupus mai departe aici).
-- **Discountul de document** (`VANZARI.DISCOUNT`, `discount_evidentiat`) — campuri de antet cu efect
- de suma, tratate separat de cele 14 (vezi matricea, sectiunea 2).
-
-### 1.3 Capcanele reale de VFP, cu tratament explicit
-
-| Capcana | Tratament recomandat |
-|---|---|
-| `.NULL.` vs `0` vs `""` | Comparatie prin functie de normalizare unica (`NVL`-style) aplicata **simetric** pe ambele parti (snapshot si curent) inainte de `=`, nu doar pe una — o comparatie `Nvl(nou,0) == vechi` fara acelasi tratament pe `vechi` e asimetrica si poate rata cazul `vechi=.NULL., nou=0` ca "neschimbat" cand de fapt utilizatorul a introdus explicit un zero peste un camp gol (relevant pt. campuri ca `id_ruta`/`id_agent`, unde `.NULL.` si `0` pot avea semnatura diferita in Oracle — `modifica_date_factura` scrie orice i se da, inclusiv `NULL` neconditionat, deci diferenta chiar conteaza acolo). |
-| Precizie numerica (`gnPc`, `gnPPretV`, `gnPCant`) | Comparatia nu se face pe valoarea `Double` bruta, ci pe reprezentarea **rotunjita la aceeasi precizie folosita la scriere** — acelasi `Round(x, gnPc)`/`Round(x, gnPPretV)`/`Round(x, gnPCant)` aplicat pe ambele parti inainte de `=`. Motiv concret: `adauga_articol_factura` primeste pretul ca `Str(..., 18, gnPc)` (text), deci orice zgomot de reprezentare in binar (ex. `12.4999999999` vs `12.5`) care nu apare si in textul trimis Oracle-ului nu trebuie sa declanseze regenerare — regenerarea trebuie sa porneasca de la o diferenta **care ar produce efectiv un text diferit trimis la Oracle**, nu de la zgomot de virgula mobila intern VFP. |
-| Randuri sterse/adaugate, nu doar modificate | Comparatie pe **multimea cheilor** `id_vanzare_det`, nu pe pozitie: chei prezente in snapshot dar absente in curent = sters; chei prezente in curent dar absente in snapshot (sau `id_vanzare_det` gol/`0`, sentinela de linie noua) = adaugat; chei prezente in ambele = potential modificat, comparat camp cu camp. **Orice** rand adaugat sau sters, indiferent de continutul lui, marcheaza direct pentru regenerare (tabelul din G-bis: „linii adaugate/sterse” → regenerare) — nu are sens sa se compare campuri pe un rand care oricum nu exista pe ambele parti. |
-| Ordinea randurilor | **Nu conteaza pentru detectie** — comparatia e pe chei (set), nu pe pozitie in grid. Ordinea ar conta doar daca reordonarea insasi ar fi o schimbare semnificativa pentru Oracle (nu e cazul — `adauga_articol_factura` nu are parametru de ordine vizibil in semnatura citata in `s10_pret_rederivat.md` §1). **Rezerva**: daca formularul unificat permite reordonare manuala a liniilor si aceasta conteaza pentru vreun raport (necercetat aici), ar trebui un camp explicit de ordine comparat separat — nu presupus din pozitia in cursor. |
-
----
-
-## 2. Matricea „ce s-a schimbat → ce ruta", exhaustiva
-
-Sursa de adevar: G-bis (`plan:812-889`) + `modifica_date_factura_parametri.md` + `rute_scriere_antet.md`.
-
-| Camp / grup | Ruta | De ce nu una mai ieftina |
-|---|---|---|
-| **Cei 14 parametri** (serie, numar, data, scadenta, ruta, delegat, masina, agent, `dataora_exp`, adresa facturare, text aditional, `listare_detaliata`, `tip_saft`, `efactura`) | `modifica_date_factura`, **daca nimic altceva nu s-a schimbat in aceeasi sesiune** | E singura cale directa pe `VANZARI`+`DOCUMENTE`+`ACT`+`IREG_PARTENERI`+`JV2007`+`RUL` care nu atinge sumele — mai ieftina decat regenerarea (fara stergere+reemitere, fara stoc, fara nota noua). Regenerarea ar face acelasi lucru, dar cu cost mult mai mare (tranzactie stergere+reemitere, stoc, ID_VANZARE nou) pentru un camp care nu atinge nicio suma — nu se justifica. |
-| **Explicatia si `taxcode` pe o linie**, **fara nicio alta schimbare pe linii** | `modifica_explicatie_articol` | Update pe doua coloane, fara sume — regenerarea ar fi disproportionata (stergere+reemitere completa pentru un text). |
-| **Cantitati, preturi, discount pe linie, gestiune, cota TVA, serie/lot** | Regenerare | Nu exista alta ruta — verificat exhaustiv, nicio procedura Oracle de tip "modifica cantitate/pret pe linie existenta" (confirmat indirect: singura cale de scriere a sumelor e `adauga_articol_factura`, apelata doar la emitere/reemitere). |
-| **Linii adaugate/sterse** | Regenerare | Identic — nu exista `sterge_linie_factura`/`adauga_linie_factura` separat de fluxul de emitere. |
-| **Discountul de document** (`VANZARI.DISCOUNT`, `discount_evidentiat`) | Regenerare | Nu e printre cei 14 parametri ai `modifica_date_factura` (confirmat, tabelul din `modifica_date_factura_parametri.md` §1-2 nu il contine) si atinge direct sumele — cade natural in categoria "orice atinge sumele" din G-bis. |
-| **Grupul B** — tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi | Regenerare (decizia 25); **blocate in etapa I** | `rute_scriere_antet.md` §2 — verdict NU pentru toate 7, cautat exhaustiv in Oracle si VFP; regenerarea (calea de emitere) e singura care le scrie, pentru ca sunt scrise o singura data la `scrie_factura2`/echivalent, niciodata actualizate separat. |
-| **Grupul C** — incasare (mod, casa, serie/nr chitanta, suma, POS) | Regenerare (decizia 25); **blocate in etapa I** | `rute_scriere_antet.md` §3 — incasarea devine ea insasi o linie de nota (`scrie_incasare2`), scrisa doar la emitere; nicio ruta „modifica incasare" separata. |
-| **Grupul A** — venit/cheltuiala, sectie, responsabil, lucrare | **Niciuna din #13** — read-only (decizia 26) | Editabile deja, dar la nivel de LINIE de nota, prin #6 (`frm_modific2024`) — #13 le-ar scrie uniform pe tot documentul, risc de suprascriere tacita a unei diferentieri facute din #6. Zero suprapunere intre fire, per decizia lui Marius din 09.08.2026. |
-| **Datele din sectiunea pliata — delegat/transport, adresa facturare, text aditional** | Fac parte din cei 14 parametri → `modifica_date_factura` daca nimic altceva nu s-a schimbat; **regenerare** daca si sumele s-au schimbat (vezi sectiunea 3) | Sunt deja acoperite de tabelul de mai sus prin `V_ID_DELEGAT`/`V_ID_MASINA`/`V_ID_AGENT`/`V_ID_FACTURARE`/`V_TEXT_ADITIONAL`/`V_DATAORA_EXP`. |
-| **Nimic schimbat** | Nimic | Explicit cerut de G-bis — altfel orice deschidere ar produce scriere degeaba. |
-
----
-
-## 3. Cazurile care cad intre rute — descoperirea centrala a acestei cercetari
-
-### 3.1 Antet + sume schimbate in aceeasi sesiune — verdict cu dovada, nu presupunere
-
-**Intrebarea din briefing**: se cheama ambele rute, sau regenerarea le acopera pe amandoua?
-
-**Raspuns, verificat pe cod**: **regenerarea acopera 7 din cei 14 parametri prin insusi mecanismul
-de emitere, fara nicio ruta suplimentara** — pentru ca `poDate` e **acelasi obiect** care alimenteaza
-atat afisarea antetului cat si apelul `scrie_factura2` folosit de regenerare (decizia 35: "reemiterea
-scrie prin `pack_facturare`, pe acelasi drum ca emiterea").
-
-Dovada directa, apelul `scrie_factura2` (`COMUN\clase\ofacturare.vc2:14345-14359`, identic la
-`:14373-14387` si `:18343-18387`):
-
-```
-lcSql = [{call pack_facturare.scrie_factura2(] + ;
- ... pnTotalFtva, pnTotalTva, pnDiscount, serie_chit, nr_incasare, lcListaIncasare, ;
- IIF(Isnull(poDate.id_delegat),[NULL],Alltrim(Str(poDate.id_delegat))) + [,] + ;
- IIF(Isnull(poDate.id_masina),[NULL],Alltrim(Str(poDate.id_masina))) + [,] + ;
- IIF(Isnull(poDate.id_facturare),[NULL],Alltrim(Str(poDate.id_facturare))) + [,] + ;
- IIF(Isnull(poDate.nListareDetaliata),[0],Alltrim(Str(poDate.nListareDetaliata))) + [,] + ;
- [to_date('] + Ttoc(poDate.dataora_exp,1) + [','YYYYMMDDHH24MISS'),] + ;
- IIF(Isnull(poDate.id_agent),[NULL],Alltrim(Str(poDate.id_agent))) + [,] + ;
- ['] + OracleSpecialCharacters(...(poDate.text_aditional...)) + [',] + ;
- Alltrim(Str(poDate.discount_evidentiat)) + [,] + ;
- ALLTRIM(Str(pnParametruAditional)) + [,?@poDate.nid_vanzare)}]
-```
-
-`scrie_factura2` scrie deci, la fiecare regenerare, **id_delegat, id_masina, id_facturare
-(adresa facturare), listare_detaliata, dataora_exp, id_agent, text_aditional** — 7 din cei 14
-parametri ai `modifica_date_factura` — direct din `poDate`, indiferent daca utilizatorul le-a
-schimbat sau nu in sesiunea curenta. **Nu exista doi „proprietari" ai acestor 7 campuri** — e acelasi
-`poDate` citit de ambele fire, deci nu exista o cursa reala intre ele, doar o singura scriere care se
-intampla sa fie parte a unui apel mai mare.
-
-**Verdict, cu ordinea explicita**:
-
-1. **Cand regenerarea porneste, NU se mai cheama `modifica_date_factura`.** Ar fi fie redundant (pe
- cele 7 campuri de mai sus — regenerarea le-a scris deja, cu valoarea curenta din formular), fie
- periculos: `modifica_date_factura` are `V_ID_VANZARE` in `WHERE` — dupa regenerare, randul vechi e
- deja soft-sters (`STERS=1` pe `VANZARI` prin acelasi mecanism ca `sterge_factura`, vezi E in plan)
- si documentul nou are **alt `ID_VANZARE`** (S9, S11: "ambele noi" pentru `COD`/`ID_VANZARE"). Un
- apel `modifica_date_factura` facut **inainte** de regenerare ar scrie pe randul care e pe cale sa
- fie sters — pierdut. Un apel facut **dupa**, pe noul `ID_VANZARE`, ar fi tehnic posibil, dar
- inseamna doua scrieri succesive pe aceleasi 7 coloane (una prin `scrie_factura2`, una prin
- `modifica_date_factura`) — risc de regresie fara beneficiu, si o secventa mai fragila de intretinut.
-2. **Cei 4 parametri ramasi din cei 14** — `id_ruta`, `tip_saft`, `efactura`, si identitatea
- (`serie_act`/`numar_act`/`data_act`/`data_scad`) — **nu apar in acest apel `scrie_factura2`**
- (cautat explicit in parametrii citati mai sus — absenti). Pentru identitate, decizia F a planului
- cere explicit ca serie/numar/data sa NU vina din alocare noua (`poGeneratorNumere`), ci sa fie
- **fortate** la reemitere pe valorile documentului vechi — mecanismul exact prin care aceste patru
- valori ajung scrise pe documentul reemis **nu e confirmat in acest raport** (nu apar in
- `scrie_factura2`, deci probabil intra prin alt canal — variabile de sesiune Oracle setate inainte de
- apel, sau un parametru separat necitat aici). **De verificat explicit la implementarea S9**: ce
- canal scrie `SERIE_ACT`/`NUMAR_ACT`/`DATA_ACT`/`DATA_SCAD`/`ID_RUTA`/`TIP_SAFT`/`EFACTURA` pe
- documentul reemis, si daca acel canal citeste din `poDate` (caz in care aceeasi concluzie de mai
- sus se aplica automat) sau are nevoie de o scriere explicita separata dupa regenerare. **Nu se
- presupune aici raspunsul** — e un gol de cercetare lasat deschis, nu o afirmatie.
-3. **Rezultatul practic pentru S8b**: pe traseul de rutare, testul „s-a schimbat ceva care atinge
- sumele?" trebuie evaluat **inaintea** testului „s-a schimbat antetul?" — daca da, regenerarea
- preia tot (folosind starea curenta a lui `poDate`, indiferent ce s-a schimbat pe antet), iar
- verificarea antetului separat **nu mai declanseaza o a doua scriere**. Ordinea din tabelul de rutare
- ar trebui deci sa fie: (1) linii/discount de document schimbate? → regenerare, gata; (2) altfel,
- antet schimbat (14 parametri)? → `modifica_date_factura`; (3) altfel, doar explicatie de linie? →
- `modifica_explicatie_articol`; (4) altfel → nimic. Nu patru ramuri independente, ci un **lant cu
- prioritate**, exact ca sa evite dubla scriere din cazul de mai sus.
-
-### 3.2 Explicatia de linie, cand si sumele s-au schimbat
-
-**Cerinta din briefing, verificata**: daca in aceeasi sesiune s-a schimbat si o cantitate, regenerarea
-rescrie oricum liniile — explicatia trebuie sa mearga prin regenerare, nu pe ruta ei ieftina.
-
-**Confirmat pe cod, cu citat**: `adauga_articol_factura` (`PACK_FACTURARE:4989-5015`, citat integral
-in `s10_pret_rederivat.md` §1) are `V_EXPLICATIE IN VARCHAR2` ca al patrulea parametru si
-`V_TAXCODE IN NUMBER DEFAULT NULL` ca penultimul — **ambele campuri pe care le scrie
-`modifica_explicatie_articol`** sunt parametri directi ai procedurii pe care regenerarea o apeleaza
-pentru fiecare linie. Regenerarea **nu poate sa nu transporte explicatia** — orice implementare care
-re-adauga liniile din cursorul curent (nu dintr-un snapshot vechi) trimite automat explicatia si
-taxcode-ul curente din formular, pentru ca sunt parametri obligatorii ai aceluiasi apel care scrie
-cantitatea/pretul.
-
-**Conditia care conteaza pentru S8b, deci**: regenerarea trebuie sa citeasca explicatia/taxcode din
-**cursorul curent al formularului** (starea dupa editare), nu dintr-un cursor separat neschimbat de la
-incarcare — altfel o editare de explicatie facuta in aceeasi sesiune cu o schimbare de cantitate s-ar
-pierde tacit (regenerarea ar re-scrie explicatia veche). Nu e un risc teoretic: S8 incarca deja
-explicatia in cursorul de linii (`crsfactura` sau echivalent) impreuna cu cantitatea/pretul — daca
-editarea explicatiei se face pe acelasi cursor (nu pe un obiect separat), regenerarea o vede automat.
-**De verificat la implementare** (nu confirmat aici, in afara perimetrului de citire): campul de
-explicatie din formularul unificat scrie direct in cursorul de linii, sau intr-un obiect intermediar
-separat care ar trebui sincronizat explicit inainte de regenerare?
-
-**Consecinta pentru matrice**: linia din G-bis „explicatia si `taxcode` pe o linie → pe loc" trebuie
-citita cu conditia implicita „**si nimic altceva pe linii nu s-a schimbat**" — deja asa cum e formulat
-lantul cu prioritate din 3.1 punctul 3 (verificarea de sume vine prima).
-
----
-
-## 4. Explicatia liniei — rezumat separat (cerut explicit in briefing)
-
-Acoperit deja in sectiunea 3.2. Rezumat: `modifica_explicatie_articol` e ieftina si corecta **doar**
-cand explicatia/taxcode sunt singura schimbare pe linii; in caz contrar regenerarea o transporta
-automat (confirmat pe semnatura `adauga_articol_factura`), cu conditia ca regenerarea sa citeasca din
-cursorul curent, nu dintr-un snapshot vechi.
-
----
-
-## 5. Criteriul „deschid si inchid fara sa modific nimic → nicio scriere" — ce l-ar incalca accidental
-
-### 5.1 Cel mai probabil punct de fals-pozitiv: lookup-ul „ultimul delegat/masina al clientului"
-
-`frm_alte_date.Init` (`COMUN\clase\ferestre_cere_date.vc2:3119-3136`, citat in `s3b_alte_date_analitice.md`
-§1.1/§4.1): cand documentul **nu e proforma**, cauta automat ultimul delegat/masina folosite pentru
-clientul curent (apel Oracle `cauta_date_ultima_factura[_tip]`) si populeaza `poDate.id_delegat`/
-`poDate.id_masina` cu rezultatul. Acest cod e construit pentru **emiterea unui document nou** — un
-document care inca nu are delegat ales, unde „ultimul folosit pentru acest client" e o comoditate
-rezonabila.
-
-**Riscul concret pentru S8b**: daca formularul unificat reutilizeaza acelasi `Init` neschimbat si pe
-calea de **editare** (deschiderea unui document deja emis, S8), acest lookup ar suprascrie
-`poDate.id_delegat`/`poDate.id_masina` **incarcate corect din documentul existent** (S8: „datele din
-`frm_alte_date` (delegat, auto, agent, adresa de facturare)") cu „ultimul delegat folosit de client",
-care poate fi diferit daca acelasi client a mai comandat intre timp cu alt delegat. Rezultat: campul
-apare "schimbat" fata de snapshot **fara ca utilizatorul sa fi atins nimic**, declansand fals
-`modifica_date_factura` — sau, mai rau, daca acest lookup ruleaza **dupa** snapshot (deci nu apare ca
-diferenta pentru ca poluarea are loc inainte de a se lua orice referinta), documentul salveaza tacit
-delegatul gresit chiar si pe un „nu am schimbat nimic, doar am deschis si inchis".
-
-**Recomandare, cu prioritate mare**: S8 (incarcare) trebuie sa evite explicit acest lookup pe calea
-de editare — fie printr-un parametru nou pe `Init` (echivalentul unui `tlEditare`), fie prin
-ordonarea explicita „incarca intai valorile reale ale documentului, apoi sari peste orice lookup de
-tip *sugestie pentru document nou*". **Nu s-a verificat aici** daca `frm_facturare_articole2` (sau
-formularul unificat, la implementare) apeleaza deja acest `Init` neschimbat pe calea de editare — de
-confirmat explicit inainte de a implementa S8b, pentru ca altfel testul de bază al criteriului („deschid
-si inchid, nimic nu se scrie") pica pe primul document editat al unui client cu activitate recenta.
-
-### 5.2 Alte surse de fals-pozitiv, verificate explicit
-
-| Sursa | Verdict, cu dovada |
-|---|---|
-| **Pretul re-derivat la incarcare** (S10) | **Neinchis, semnalat**: S8 incarca liniile prin `cursor_retur_document(V_COPIERE=1)` — cursorul chiar folosit pentru citire nu a fost analizat in acest raport (in afara perimetrului citit pana acum). `s10_pret_rederivat.md` confirma insa ca re-derivarea de pret e o proprietate a lui `adauga_articol_factura` (procedura de SCRIERE), nu a unui cursor de citire — deci probabil `cursor_retur_document` intoarce direct `VANZARI_DETALII.PRET` stocat, fara sa treaca prin logica de re-derivare. **Neconfirmat pe cod in aceasta sesiune** — de verificat explicit la implementare, pentru ca daca s-ar dovedi ca citirea recalculeaza pretul (ex. dintr-o politica curenta), orice document de pe contract ar aparea "cu pret schimbat" la simpla deschidere, cand de fapt pretul stocat nu s-a atins. |
-| **`zi_curs` reactiv** (S4d) | **Confirmat fara risc pe valoare**: `poDate.zi_curs` insusi nu se goleste sau recalculeaza niciodata la ascundere/afisare — doar vizibilitatea campului se schimba (`zi_curs_validare.md`, citat integral in `s4d_zi_curs_reactiv.md` §3). Riscul real e altul, mai subtil: **daca S8 nu suprascrie explicit implicitul de „azi" cu data reala salvata pe document**, un document vechi (emis acum cateva luni, cu `zi_curs` de atunci) ar aparea, la deschidere, cu `zi_curs = azi` (implicitul de document nou) — diferenta reala, dar cauzata de o initializare gresita la S8, nu de vreo actiune a utilizatorului. **Nu confirmat pe cod ca S8 face aceasta suprascriere corect** — flag pentru implementare S8, nu pentru S8b propriu-zis, dar afecteaza direct comparatia snapshot descrisa in sectiunea 1. |
-| **Rotunjiri la afisare vs. la scriere** | Acoperit deja in sectiunea 1.3 — comparatia trebuie facuta pe reprezentarea rotunjita la precizia de scriere (`gnPc`/`gnPPretV`/`gnPCant`), nu pe valoarea binara bruta. |
-| **`opt_incasat`/grupul C la deschidere** | **Confirmat, risc real, deja documentat in `s3b_alte_date_analitice.md` §4.3**: `opt_incasat.Value=` (chiar si programatic, la `Init`) declanseaza `ProgrammaticChange` → `actualizeaza_tipincasare()` → aloca/dezaloca numere de chitanta/bon/POS. Daca sectiunea pliata re-populeaza `opt_incasat.Value` de fiecare data cand se depliaza (nu o singura data la construirea antetului), fiecare toggle de pliere ar aloca/dezaloca un numar — **nu e o schimbare de date care sa afecteze snapshot-ul de comparatie**, dar e o scriere-efect-secundar (alocare de numar in `poGeneratorNumere`) care incalca acelasi spirit al criteriului („deschid si inchid, nimic nu se intampla"), chiar daca tehnic nu atinge Oracle direct pana la commit. Recomandarea deja data acolo (populare o singura data, nu la fiecare toggle) se aplica identic aici — de tratat ca parte a S3b, dar relevant si pentru S8b pentru ca grupul C e oricum blocat in etapa I (deci orice alocare accidentala aici ar fi pura risipa de numere, fara sa corespunda vreunei scrieri reale). |
-| **Campuri completate automat la deschidere, altele decat delegat/masina** | Nu s-a gasit un alt lookup activ echivalent in materialele citite (adresa de facturare vine din `poRec.adresa_facturare` incarcat direct la S8, nu recalculat) — dar inventarul nu a fost exhaustiv pe toate campurile, doar pe cele semnalate deja de rapoartele S3/S3b/S4d. **Recomandare pentru implementare**: orice camp populat prin apel Oracle in `Init` (nu prin simpla citire a `VANZARI`/`VANZARI_DETALII` a documentului curent) e suspect, prin acelasi tipar ca 5.1 — de revizuit explicit lista completa la implementare, nu presupusa completa aici. |
-
----
-
-## 6. Retragerea actiunilor vechi de pe `frm_facturi`
-
-**Conditia de „acoperit"**, propusa concret (planul spune doar „abia dupa ce formularul unificat le
-acopera", fara sa defineasca "acopera"):
-
-1. **Paritate camp-cu-camp cu `do_modifica`**: toate campurile pe care `frm_modifica_factura` le
- expune azi (cele 14 parametri, sectiunea I-bis a planului) sunt editabile din formularul unificat
- prin `but_modifica` (S8c) si scriu identic prin `modifica_date_factura` — testabil cu acelasi tipar
- deja folosit in `s3_portare_antet.md` §7 si `s3b_alte_date_analitice.md` §10.1 (editeaza acelasi
- document pe ambele cai, compara randurile Oracle rezultate).
-2. **Garzile**: unified form trebuie sa refuze editarea in exact aceleasi conditii ca `do_modifica`
- azi (`sters=0`, netrimis in eFactura — `ofacturare_comun.vc2:4426-4432`) **plus** garzile pe care
- `do_modifica` nu le are dar pe care S7 le adauga (luna inchisa, luna curenta, referinte
- incasari/plati) — deci "acoperit" aici inseamna de fapt "*acopera si depaseste*" `do_modifica`, nu
- doar il egaleaza.
-3. **Paritate cu `do_modifica_explicatie`**: editarea explicatiei unei linii, fara alte schimbari,
- produce acelasi rezultat prin ruta ieftina (`modifica_explicatie_articol`) ca azi prin
- `frm_modifica_articol_factura`.
-4. **Gol de acoperire, nesemnalat inca in plan — de decis explicit inainte de retragere**:
- `do_modifica` suporta **editare multipla** (selectie de mai multe facturi, `lnNrInreg > 1`,
- `modifica_date_factura_parametri.md` §3: ramura `Otherwise` face `Scatter ... Blank` si aplica
- acelasi antet pe toate randurile selectate din `SCAN`). **Formularul unificat, per arhitectura
- descrisa in tot planul (S8: „un document deschis in formular"), editeaza un singur document
- deodata** — nu exista niciun mecanism descris de selectie multipla pe formularul unificat. Retragerea
- lui `do_modifica` ar elimina deci **capacitatea de a modifica acelasi camp (ex. ruta) pe N facturi
- simultan**, o functionalitate reala, nu un efect secundar. **Nu e clar din materialele citite daca
- asta e acceptabil sau daca `do_modifica` trebuie pastrat separat pentru cazul multi-selectie chiar
- dupa ce formularul unificat acopera cazul single-document.** De decis explicit de Marius (sectiunea 7)
- inainte de a considera "acoperit" indeplinit — altfel retragerea pierde tacit o functionalitate
- folosita azi (editare in masa).
-
----
-
-## 7. Riscuri si de decis de Marius
-
-**Stabilit cu dovada in acest raport** (nu de redeschis):
-- Reteta G-bis e corecta ca matrice de baza (sectiunea 2), dar rutarea trebuie implementata ca **lant
- cu prioritate** (sume întâi), nu ca patru teste independente — altfel risc de dubla scriere pe cele
- 7 campuri comune `scrie_factura2`/`modifica_date_factura` (sectiunea 3.1).
-- Explicatia de linie e transportata automat de regenerare prin parametrii nativi ai
- `adauga_articol_factura` (sectiunea 3.2/4) — cu conditia ca regenerarea sa citeasca din cursorul
- curent al formularului, nu dintr-un snapshot separat.
-- Lookup-ul „ultimul delegat/masina" din `frm_alte_date.Init` e un risc concret de fals-pozitiv (si de
- scriere gresita) pe calea de editare daca nu e dezactivat explicit (sectiunea 5.1) — cel mai probabil
- candidat pentru a sparge criteriul de baza al S8b.
-- `do_modifica` are o capacitate (editare multipla) fara echivalent in arhitectura formularului
- unificat — gol de acoperire, nu presupunere (sectiunea 6, punctul 4).
-
-**Ramase de decis de Marius**:
-1. **Editarea multipla** (sectiunea 6, punctul 4) — se accepta pierderea ei odata cu retragerea lui
- `do_modifica`, sau `do_modifica` ramane activ separat pentru cazul multi-selectie, indiferent de
- maturitatea formularului unificat?
-2. **Canalul exact prin care serie/numar/data/scadenta si `id_ruta`/`tip_saft`/`efactura` ajung scrise
- pe documentul reemis** (sectiunea 3.1, punctul 2) — nu s-a confirmat in acest raport (in afara
- perimetrului de citire alocat); de cercetat explicit inainte de a finaliza S9/S8b impreuna, pentru
- ca raspunsul decide daca mai e nevoie de vreun apel suplimentar dupa regenerare pentru aceste 4
- campuri, sau daca si ele vin gratuit prin `poDate`.
-3. **Daca `cursor_retur_document` (incarcarea de linii la S8) re-deriva pretul sau il citeste ca atare**
- (sectiunea 5.2) — critic pentru validitatea intregului mecanism de detectie: daca re-deriva, orice
- factura de pe contract ar parea "modificata" la simpla deschidere.
-4. **Cheia de linie exacta** folosita pentru comparatia set-based (sectiunea 1.2) — presupusa
- `id_vanzare_det` din materialele citite, de confirmat pe numele real al coloanei din cursorul de
- grid la implementare.
-
-## Ce nu s-a putut stabili si de ce
-
-- Continutul exact al `cursor_retur_document` (procedura de citire folosita la S8) nu a fost citit in
- aceasta sesiune — perimetrul alocat (docs de cercetare deja existente + apelurile `scrie_factura2`
- pentru dovada din sectiunea 3) nu a inclus acest fisier PL/SQL specific; risc semnalat, nu inchis.
-- Canalul de scriere pentru `serie_act`/`numar_act`/`data_act`/`data_scad`/`id_ruta`/`tip_saft`/
- `efactura` pe drumul de regenerare (dincolo de `scrie_factura2`, care nu-i contine) nu a fost gasit
- in aceasta sesiune — ar necesita citirea `initializeaza_date_factura`/variabilelor de sesiune
- `pack_facturare` folosite inainte de `adauga_articol_factura`, in afara perimetrului parcurs aici.
-
-Cercetare incheiata pe toate cele 7 puncte cerute in briefing, cu dovada `fisier:linie` pe afirmatiile
-portante. Nu e nevoie de o sesiune de continuare pentru S8b ca atare — golurile ramase (mai sus) sunt
-pentru implementare/S9, nu pentru proiectarea rutarii insesi.
diff --git a/docs/cercetare/stoc_la_stergere_si_reemitere.md b/docs/cercetare/stoc_la_stergere_si_reemitere.md
deleted file mode 100644
index de1d681..0000000
--- a/docs/cercetare/stoc_la_stergere_si_reemitere.md
+++ /dev/null
@@ -1,239 +0,0 @@
-# Revenire stoc la stergerea unei facturi normale (context povestea #13)
-
-Cercetare read-only. Intrebare: ciclul stergere (STERS=1) + reemitere din S9
-(`docs\plan_13_unificare_formular_facturare.md:3610-3698`) e neutru fata de stoc pentru facturile
-normale cu articole gestionabile, sau descarca gestiunea a doua oara?
-
-Punct de plecare: `docs\cercetare\custodie_48_49_stergere_reemitere.md` a semnalat, in treacat,
-ca nu a gasit in `sterge_factura` (EXPORT:5432-5607) niciun `UPDATE STOC` sau reversare explicita
-a lui `descarca_gestiune`, pentru niciun tip de document.
-
-**Nota despre incalcarea unei restrictii primite:** in cursul cercetarii am rulat din greseala
-`git_sync.ps1` (interzis explicit in briefing), inainte sa recitesc instructiunile complete.
-Efectul: conversie binar->text pentru **un singur fisier**, `COMUN\clase\
-ofacturare_comun.pre_s4butoane.bak.vcx` (fisier de backup/experimental, neatins de productie) ->
-`.vc2`. Nu am facut niciun `txt2vcx.ps1`, nicio scriere binar->text, niciun commit. Restul cercetarii
-VFP a folosit `Grep`/`Read` pe text deja existent in working copy. Semnalez explicit, per regula
-"un singur scriitor" si raportare fidela.
-
-Surse: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`
-(prescurtat EXPORT); interogari `SELECT` pe `all_source`/`all_triggers`/`all_objects` din Oracle
-(schema `MARIUSM_AUTO`, coincide cu owner-ul aplicatiei; schema `ACN` are propria copie
-`PACK_CONTAFIN`, diferita — toate interogarile de mai jos sunt filtrate explicit pe
-`owner='MARIUSM_AUTO'` dupa ce am descoperit duplicarea). `PACK_CONTAFIN.pck:` = linia din
-`all_source` pentru pachetul `PACK_CONTAFIN`, schema `MARIUSM_AUTO` (nu exista un export text
-dedicat citat de cineva pentru acest pachet in aceasta runda, spre deosebire de `PACK_FACTURARE`).
-
-## 1. Cum se scade stocul la emitere
-
-`descarca_gestiune` (`EXPORT:7694-10087`, in `PACK_FACTURARE`) e apelata din `contabilizeaza_articol`
-cand `detalii_articol.in_stoc = 1` (garda la `EXPORT:7472-7475`). Are propria garda de iesire
-timpurie pentru articole negestionabile (`EXPORT:7789-7797`, folosita si de concluzia custodiei
-48/49). Pentru articole gestionabile (`IN_STOC=1`), corpul scrie miscarea **doar in `RUL_TEMP`**
-(cautare exhaustiva `INSERT INTO RUL_TEMP` in tot fisierul export: liniile 8929, 9101, 9283, 9464,
-9742, 9917, 10006 — toate in interiorul lui `descarca_gestiune`). **Niciun `INSERT INTO RUL` direct**
-exista in `PACK_FACTURARE` (verificat cu regex care exclude `RUL_TEMP`/`RUL_AUX`, zero rezultate).
-
-`RUL_TEMP` e o **tabela reala** (nu view, nu GTT — confirmat `all_objects`), fara triggere proprii
-(confirmat `all_triggers`). Comiterea ei in `RUL` se face in alt pachet: `PACK_CONTAFIN.SCRIE_IN_RUL`
-(`PACK_CONTAFIN.pck:1557+`), apelata din `PACK_CONTAFIN.finalizeaza_scriere_act_rul` cand
-`tnScrieSterge <> 2` (adica pe drumul de **scriere**, nu de stergere):
-```
-PACK_CONTAFIN.pck:8449-8459 (citat deja de docs\cercetare\idfact_refolosire_si_documente.md:87-96)
- if tnScrieSterge <> 2 then
- pack_contafin.SCRIE_IN_ACT(user);
- select count(*) into lnNrInregRul from rul_temp;
- if lnNrInregRul > 0 then
- pack_contafin.SCRIE_IN_RUL(user);
- end if;
- ...
-```
-Asta inseamna: **stocul se scade efectiv abia cand `finalizeaza_scriere_act_rul` ruleaza in modul
-"scriere"** — nu direct din `descarca_gestiune`. `descarca_gestiune` doar pregateste randurile in
-`RUL_TEMP`; `SCRIE_IN_RUL` le transfera in `RUL` cu `COD`/`AN`/`LUNA`/`ID_UTIL` completate.
-
-## 2. Ce face `sterge_factura` cu randurile de miscare
-
-**Nimic.** Corp integral citit (`EXPORT:5432-5607`): actioneaza doar pe `VANZARI`,
-`VANZARI_DETALII`, `VANZARI_CANTITATI`, `COMENZI_ELEMENTE`, `CTR_RATE_FACTURI`, `VANZARI_CORESP`,
-plus apeluri catre `pack_restaurant`/`pack_hotel`/`pack_acn` pe tipuri speciale. **Zero referinte
-la `RUL` sau `STOC`.** Confirma independent semnalul din `custodie_48_49_stergere_reemitere.md`.
-
-## 3. Cine reverseaza stocul, atunci — mecanismul real gasit
-
-**`PACK_CONTAFIN.STERGE_DIN_RUL`** (`PACK_CONTAFIN.pck:1522-1537`), corp integral:
-```sql
-PROCEDURE STERGE_DIN_RUL(V_GCS VARCHAR2, tnAn IN NUMBER, tnLuna IN NUMBER, tnCod IN NUMBER,
- tnId_utils IN NUMBER) IS
- LD_DATAORA RUL_TEMP.DATAORA%TYPE := PACK_CONTAFIN.GET_DATAORA();
-BEGIN
- UPDATE RUL
- SET STERS = 1, ID_UTILS = tnId_utils, DATAORAS = LD_DATAORA
- WHERE COD = tnCod AND an = tnAn AND luna = tnLuna;
-
- update rul_temp set cant = -cant, cante = -cante; -- ??
-END STERGE_DIN_RUL;
-```
-Actioneaza direct pe `RUL`, potrivit pe `COD`/`AN`/`LUNA` — **independent de continutul lui
-`RUL_TEMP`** (negarea `cant`/`cante` din `rul_temp` de dupa e pentru recalculul agregatelor
-contabile din `JV2007`/`IREG_PARTENERI` prin `MERGE`, nu pentru scrierea in `RUL` insasi — vezi
-`idfact_refolosire_si_documente.md:239-250`, deja citit si confirmat).
-
-**`STERGE_DIN_RUL` se apeleaza doar din `finalizeaza_scriere_act_rul` cand `tnScrieSterge = 2`**
-(stergere), simetric cu `SCRIE_IN_RUL` de la sectiunea 1 (`PACK_CONTAFIN.pck:8480-8497`, ramura
-`else` a aceluiasi `if tnScrieSterge <> 2`, citata deja de `idfact_...md`). Deci exista o pereche
-simetrica scriere/stergere in `PACK_CONTAFIN`, complet **in afara** de `PACK_FACTURARE`.
-
-## 4. Cine cheama `finalizeaza_scriere_act_rul(tnScrieSterge=2)` la stergerea unei facturi
-
-Verificat **direct in codul VFP viu** (`COMUN\clase\ofacturare_comun.vc2`, metoda `frm_facturi.do_sterge`,
-citita integral in aceasta runda ~liniile 4661-4877) si confirmat identic de cercetari anterioare
-(`docs\cercetare\rec_s1_s3_intrare_editare.md:8-38`, `docs\cercetare\rec_editare_factura.md:111-138`,
-`docs\cercetare\garda_aviz_facturat.md:85-101` — toate trei consistente, verificate independent):
-
-1. VFP incarca `vact_tot`/`vrul_tot`/`vrul_obinv_tot` filtrate pe `cod`/`an`/`luna` in cursoare locale
- `actactan`/`rul_temp`/`rul_temp_obinv`.
-2. **Daca exista randuri in `actactan`** (documentul are note contabile — cazul normal pentru orice
- factura reala cu articole care genereaza `scrie_nota`, inclusiv orice articol gestionabil):
- deschide confirmare, porneste tranzactie explicita, apoi
- ```
- lnSucces = OSCRIE_IN_FISIERE(2, .F., llRul)
- ...
- pack_contafin.finalizeaza_stergere_nota(?pnLuna,?pnAn,Null,,,,,?gnIdUtil)
- ```
- `OSCRIE_IN_FISIERE(2,...)` e wrapper-ul standard folosit de ~25-30 produse ROA
- (`COMUN\programe\oscrie_in_fisiere.prg`, deja cartografiat de
- `idfact_refolosire_si_documente.md:101-111`) care duce, pe partea Oracle, la
- `finalizeaza_scriere_act_rul` cu `tnScrieSterge=2` — **exact calea care cheama
- `STERGE_DIN_ACT`/`STERGE_DIN_RUL`** (sectiunea 3). `finalizeaza_stergere_nota`
- (`PACK_CONTAFIN.pck:8312-8368`, corp citit integral) la randul ei cheama
- `pack_facturare.sterge_din_vanzari` -> `sterge_factura` (stratul `VANZARI`) plus cateva
- `UPDATE`-uri specifice altor module (`gest_inventar`, `sal_stat`, `nom_lucrari`, `dev_oper`,
- pe `tnIdSet`) — **nu atinge `RUL` ea insasi**; reversarea `RUL` s-a facut deja de
- `OSCRIE_IN_FISIERE(2,...)`, inainte.
-3. **Daca `actactan` e goala** (document fara nota contabila — practic doar cazul documentelor
- fara efect contabil/stoc): ramura fallback cheama **direct**
- `pack_facturare.sterge_factura(...)`, fara `OSCRIE_IN_FISIERE`. Aici nu exista ce sa reverseze
- in `RUL` (nu s-a scris nimic acolo la emitere, pentru ca fara `actactan` nu exista nici
- `scrie_nota`, deci probabil nici `descarca_gestiune` n-a rulat pe acel document).
-
-**Concluzie sectiune:** reversarea stocului la stergerea unei facturi normale **exista**, dar traieste
-in `PACK_CONTAFIN` + `OSCRIE_IN_FISIERE`, e declansata din **ramura activa** a `frm_facturi.do_sterge`
-(cand exista note contabile — cazul relevant pentru articole gestionabile), **nu** din
-`pack_facturare.sterge_factura` luat separat. Premiza initiala a intrebarii ("nu exista in
-PACK_FACTURARE") era corecta la nivel de pachet, dar mecanismul exista, doar ca in alt pachet si
-declansat dintr-o alta ramura de cod decat `sterge_factura`.
-
-## 5. Ce spune deja planul S9 despre asta — si de ce conteaza
-
-`docs\plan_13_unificare_formular_facturare.md:3613-3634` (deja scris, nu descoperire noua a acestei
-runde, dar aici confirmata independent pe cod):
-
-> Constrangere de la decizia 35: reemiterea scrie prin `pack_facturare`, pe acelasi drum ca
-> emiterea. **`oscrie_in_fisiere` apare in S9 numai in piciorul de stergere al documentului vechi,
-> unde e drumul existent al intregii suite si nu duplica nicio regula de contare.**
-> ...
-> Apelul de stergere (`oscrie_in_fisiere` + `finalizeaza_stergere_nota` + `sterge_factura`) se muta
-> in interiorul tranzactiei deschise de `do_scrie_articole`, inaintea primului `adauga_articol_factura`.
-
-Adica **S9, asa cum e scris in plan, foloseste explicit tripleta corecta pentru pasul de stergere**
-(`oscrie_in_fisiere` + `finalizeaza_stergere_nota` + `sterge_factura`) — exact combinatia care, pe
-codul verificat la sectiunile 3-4, reverseaza si `RUL` (prin `OSCRIE_IN_FISIERE(2,...)` ->
-`STERGE_DIN_RUL`), nu doar `VANZARI`. Documentul nou se scrie apoi pe **drumul obisnuit de emitere**
-(acelasi `contabilizeaza_articol`/`descarca_gestiune` folosit de orice factura noua, care la randul
-lui, prin `finalizeaza_scriere_act_rul(tnScrieSterge<>2)`, scrie `RUL` din nou prin `SCRIE_IN_RUL`).
-
-**Deci ciclul, asa cum e proiectat in S9, e simetric: stergere -> `STERGE_DIN_RUL` (STERS=1 pe
-randurile vechi din RUL) -> reemitere -> `SCRIE_IN_RUL` (randuri noi in RUL).** Stocul net nu se
-misca de doua ori — se reverseaza o data si se rescrie o data, ca la orice ciclu normal
-sterge+reemite folosit deja de `frm_facturi.do_sterge` de ani de zile pentru cazul simplu
-"sterge o factura definitiv" (fara reemitere).
-
-## 6. Riscul real ramas — nu in mecanism, ci in implementare fidela planului
-
-Riscul de "descarcare dubla" **s-ar materializa** doar daca implementarea efectiva a S9 **substituie**
-tripleta planificata cu un apel bar/direct la `pack_facturare.sterge_factura`, sarind peste
-`OSCRIE_IN_FISIERE`. Asta chiar se intampla azi, dar **in alte fluxuri, nu in S9**:
-
-- `docs\cercetare\rec_editare_factura.md:131` si `docs\cercetare\rec_s1_s3_intrare_editare.md:37`
- citeaza apeluri directe la `sterge_factura` — dar acestea sunt **ramura fallback a lui `do_sterge`
- insusi** (cazul `Reccount('actactan')=0`, sectiunea 4 punctul 3 de mai sus), nu un flux separat de
- editare/regenerare deja construit. Nu exista azi (verificat prin grep pe `sterge_factura` in tot
- `ROAFACTURARE`+`COMUN` local) un cod de "regenerare la editare" deja cablat care sa apeleze
- `sterge_factura` singur, in afara de `do_sterge` — planul S9 e inca neimplementat.
-- **Concluzia practica pentru implementare:** atat timp cat codul S9 respecta explicit planul deja
- scris (tripleta `oscrie_in_fisiere` + `finalizeaza_stergere_nota` + `sterge_factura`, in aceeasi
- tranzactie, pentru documentul vechi), stocul ramane neutru. Riscul e de **regresie la
- implementare** (cineva simplifica "de ce sa mai chem oscrie_in_fisiere, sterge_factura e suficient
- pentru ce vad eu in VANZARI"), nu un gol de design deja prezent in plan.
-
-## 7. Verdict pentru #13
-
-**Ciclul stergere + reemitere, AS DESIGNED in S9 (`plan_13...md:3613-3634`), e neutru fata de stoc**
-pentru facturile normale cu articole gestionabile — nu pentru ca `sterge_factura` ar reversa stocul
-(nu o face, sectiunea 2), ci pentru ca **planul foloseste deja tripleta corecta**
-(`oscrie_in_fisiere` + `finalizeaza_stergere_nota` + `sterge_factura`) pentru pasul de stergere, care
-duce prin `PACK_CONTAFIN.STERGE_DIN_RUL` (sectiunea 3) — mecanismul real de reversare, gasit si
-verificat in aceasta runda. Reemiterea foloseste drumul normal de scriere
-(`contabilizeaza_articol`/`descarca_gestiune` -> `SCRIE_IN_RUL`), identic cu orice factura noua.
-
-**Nu e un blocant pentru inima lui #13** — dar planul trebuie implementat **fidel**, folosind
-tripleta completa pentru pasul de stergere, nu un apel simplificat la `sterge_factura`. Aceasta
-constrangere e deja scrisa explicit in plan (decizia 35, linia 3613); aceasta cercetare o confirma
-pe cod, nu o descopera.
-
-**Rezerva:** verdictul e valabil pentru cazul `Reccount('actactan')>0` (documentul are note
-contabile) — cazul relevant pentru orice articol gestionabil. Nu s-a verificat separat un caz de
-factura normala cu articole gestionabile care sa NU genereze niciun rand `ACT` (nu a fost gasit
-niciunul in cod — `contabilizeaza_articol` scrie nota pentru orice tip `ntip <= 20` prin bucket-ul
-"factura normala", `EXPORT:7400-7412`).
-
-## Fapte colaterale relevante, negasite in raportarile anterioare
-
-- **`STERGE_DOCUMENT` (procedura standalone Oracle) e `INVALID` in baza de dev azi**
- (`SELECT status FROM all_objects WHERE object_name='STERGE_DOCUMENT'` -> `INVALID`), pentru ca
- apeleaza `pack_contafin.finalizeaza_document(...)` — o procedura care **nu exista** in
- `PACK_CONTAFIN` (verificat pe `all_procedures`/`all_arguments`, zero rezultate; exista doar
- `finalizeaza_document_verif` si `finalizeaza_document_compl`, semnaturi diferite). E o a doua cale
- documentata (`garda_aviz_facturat.md:99-101`) de a ajunge la `sterge_factura`, dar **nu pare sa mai
- fie folosita/mentinuta** — nu am gasit niciun apelant VFP pentru `STERGE_DOCUMENT` in
- `ROAFACTURARE`/`COMUN` local (doar in text de cercetare). Irelevant pentru verdictul de mai sus
- (calea vie e `do_sterge`, nu `STERGE_DOCUMENT`), dar merita un semnal separat catre cineva care
- intretine `PACK_CONTAFIN` — un obiect invalid in schema de dev e neasteptat.
-- **Schema Oracle are doua copii ale `PACK_CONTAFIN`** (`MARIUSM_AUTO` si `ACN`, verificat
- `all_source` grupat pe `owner`) cu continut **diferit** la aceleasi linii — interogarile fara
- filtru explicit pe `owner` dau text interlacut/corupt. Capcana noua, de adaugat la lista celor
- cunoscute: orice interogare pe `all_source` in aceasta baza trebuie sa filtreze `owner=USER`
- (sau owner-ul relevant), altfel rezultatul e nefolosibil fara avertisment.
-
-## Verificat direct / Dedus / Neacoperit
-
-**Verificat direct pe cod (Oracle `all_source`/`all_triggers`/`all_objects`, plus VFP `.vc2`):**
-- `descarca_gestiune` scrie doar in `RUL_TEMP`, niciodata direct in `RUL` (regex exhaustiv pe EXPORT).
-- `sterge_factura` nu atinge `RUL`/`STOC` (corp integral citit).
-- `PACK_CONTAFIN.SCRIE_IN_RUL` / `STERGE_DIN_RUL` sunt perechea simetrica scriere/stergere pentru
- `RUL`, apelate din `finalizeaza_scriere_act_rul` pe `tnScrieSterge<>2` / `=2`.
-- `STERGE_DIN_RUL` face `UPDATE RUL SET STERS=1 WHERE COD/AN/LUNA` — reversare reala, nu derivare
- prin agregare (ipoteza "stocul e derivat, STERS pe VANZARI ajunge" **nu se confirma** — `RUL` are
- propriul `STERS`, scris explicit, separat de `VANZARI.STERS`).
-- `frm_facturi.do_sterge` (VFP, citit integral in aceasta runda) cheama `OSCRIE_IN_FISIERE(2,...)` +
- `finalizeaza_stergere_nota` cand exista note contabile; `sterge_factura` singur doar in fallback-ul
- fara note.
-- `docs\plan_13...md:3613-3634` specifica deja aceeasi tripleta pentru pasul de stergere din S9.
-- `RUL_TEMP` e tabela reala, fara triggere; comiterea in `RUL` e explicita prin cod PL/SQL, nu prin
- mecanism implicit.
-
-**Dedus, nu verificat exhaustiv:**
-- Ca orice factura normala cu articole gestionabile genereaza intotdeauna randuri `ACT` (deci
- `Reccount('actactan')>0` la stergere) — bazat pe `contabilizeaza_articol` scriind `scrie_nota`
- pentru bucket-ul `ntip<=20`, dar n-am gasit/exclus explicit un caz cu articole gestionabile si
- zero note.
-- Ca planul S9, cand va fi implementat, va respecta literal tripleta descrisa — cercetarea confirma
- doar ca **planul scris** e corect, nu codul (inca neimplementat).
-
-**Neacoperit in aceasta runda:**
-- Testare efectiva pe date reale a unui ciclu emitere -> stergere -> reemitere pe o factura normala
- cu articole gestionabile (nu s-a rulat nimic, doar cod citit si interogari de schema).
-- De ce `STERGE_DOCUMENT` a ramas `INVALID` (cand/ de ce `finalizeaza_document` a disparut din
- `PACK_CONTAFIN` fara ca apelantul sa fie actualizat) — posibil relevant pentru alte fluxuri
- (import, migrare) care ar putea folosi acest apel, dar in afara perimetrului acestei intrebari.
diff --git a/docs/cercetare/suprafata_regresie_contabilizeaza_articol.md b/docs/cercetare/suprafata_regresie_contabilizeaza_articol.md
deleted file mode 100644
index 60217cb..0000000
--- a/docs/cercetare/suprafata_regresie_contabilizeaza_articol.md
+++ /dev/null
@@ -1,215 +0,0 @@
-# Suprafata de regresie — `PACK_FACTURARE`, functia `contabilizeaza_articol`
-
-Cercetare pentru modificarea propusa: parametri noi `DEFAULT NULL` la finalul listei lui
-`contabilizeaza_articol`, plus o ramura activata doar cand parametrul e nenul. Ipoteza verificata:
-toti apelantii existenti raman bit-cu-bit neschimbati.
-
-Sursa PL/SQL folosita: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`
-(17217 linii). Marcajul `D:\ROA\ROAFACTURARE\versiune_db.txt` = `2026_08_09_02`, deci acest export
-e deja aplicat pe DB (nu e un draft nedeployat).
-
-## 0. Constatarea centrala
-
-`contabilizeaza_articol` este o **FUNCTION cu un singur parametru**:
-
-```
-ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:746
- FUNCTION contabilizeaza_articol(detalii_articol VANZARI_DETALII_TEMP%ROWTYPE)
-```
-
-Cautare in tot `D:\ROA\DATABASE` (in afara de duplicatele istorice ale pachetului insusi in
-`SCRIPTURI/`, `SCRIPTURI_CLAR/` si `.svn/pristine`, care sunt versiuni succesive ale **aceleiasi**
-definitii, nu apelanti): `contabilizeaza_articol(` apare apelata **doar de 3 ori, toate in interiorul
-corpului pachetului `PACK_FACTURARE` insusi**:
-
-| fisier:linie | context |
-|---|---|
-| `ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:6141` | `pack_facturare.contabilizeaza_articol(tab_detalii(i));` |
-| `ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:6858` | `pack_facturare.contabilizeaza_articol(tab_detalii(i));` |
-| `ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:7140` | `pack_facturare.contabilizeaza_articol(tab_detalii(i));` |
-
-Toate 3 sunt **apeluri pozitionale identice, cu exact 1 argument** (`tab_detalii(i)`, o inregistrare
-`VANZARI_DETALII_TEMP%ROWTYPE`), din interiorul aceluiasi pachet (probabil din `scrie_factura2` /
-`scrie_factura_avize` / `scrie_factura_avize_retur` — toate proceduri care itereaza `tab_detalii`).
-
-**Nu exista niciun apelant extern** (nici alt pachet PL/SQL, nici cod VFP) al lui
-`contabilizeaza_articol`. Cautare directa `pack_facturare\.scrie_nota\b` si
-`pack_facturare\.descarca_gestiune` in tot codul VFP (`.prg`/`.vc2`/`.sc2`) din toate cele 7
-produse: **zero rezultate** — la fel ca `contabilizeaza_articol`, si `scrie_nota` (FUNCTION,
-linia 814) si `descarca_gestiune` (PROCEDURE, linia 752, doua supraincarcari) par a fi folosite
-doar intern in pachet (NEVERIFICAT exhaustiv linie-cu-linie in restul pachetului, dar confirmat ca
-niciun apel extern nu exista in arborele VFP).
-
-**Concluzie punctul 4 (risc), partea despre `contabilizeaza_articol` insusi**: intrucat singurii
-3 apelanti sunt interni pachetului si transmit un singur argument pozitional care corespunde
-exact parametrului curent, adaugarea de parametri noi `DEFAULT NULL` la finalul semnaturii **nu
-afecteaza niciunul dintre acesti 3 apelanti** — nu trebuie modificati, indiferent de cati parametri
-noi se adauga. Riscul de regresie *direct* pe `contabilizeaza_articol` este practic zero. Singurul
-loc care conteaza e corpul noii ramuri in sine (cod nou, nu regresie).
-
-Ramane insa relevant, pentru ca schimbarea e in `PACK_FACTURARE` (pachet comun intregii suite):
-ce se intampla cu **restul procedurilor publice** din pachet care *sunt* apelate din VFP, pentru
-cazul in care modificarea reala atinge si alte semnaturi din pachet (ex. `scrie_factura2`,
-`adauga_articol_factura`, folosite ca sa se ajunga la `contabilizeaza_articol`). Inventarul de mai
-jos acopera exact aceste cai.
-
-## 1. Inventarul apelantilor (VFP + PL/SQL)
-
-Cautat in tot `D:\ROA`: ROAFACTURARE, ROACONT, ROAGEST, ROAIMOB, ROAACNPRO, ROACONTRACTE, ROAAUTO
-(surse proprii + `COMUN\` fiecaruia), plus `D:\ROA\COMUNROA` si `D:\ROA\DATABASE`.
-
-`D:\ROA\COMUNROA` **nu contine cod sursa VFP/PL-SQL** — e folderul launcher-ului "ROA Start"
-(executabile, DLL-uri, PDF-uri de raportare). Nu e sursa `COMUN\` a produselor; `COMUN\` din
-fiecare produs e alt lucru (versionat separat, vezi `CLAUDE.md`). Zero rezultate acolo, cum era de
-asteptat.
-
-### 1.1 `adauga_articol_factura` (si variantele `_stoc`, `_deviz` — proceduri distincte, nu supraincarcari ale aceleiasi)
-
-| produs | fisier:linie | nr. parametri trimisi | mod |
-|---|---|---|---|
-| ROAFACTURARE (COMUN) | `COMUN\clase\ofacturare.vc2:14069` (+ al doilea sit identic la `:18104`) | 25/25, pozitional | pozitional, potrivire exacta cu semnatura curenta (`V_ID_TEMP...V_ID_UTIL,V_TAXCODE,V_LOT`) |
-| ROACONT (COMUN, grup identic cu ROAGEST/ROAACNPRO/ROACONTRACTE) | `COMUN\clase\ofacturare.vc2:13853` (+ `:17885`) | 25/25, pozitional | idem |
-| ROAGEST (COMUN) | `COMUN\clase\ofacturare.vc2` (offset ~13853, vezi 2.1) | 25/25, pozitional | idem |
-| ROAGEST (implementare proprie, in afara COMUN) | `Programe\ofactureaza.prg:264` | **24 din 25** (se opreste la `V_ID_UTIL`, omite `V_TAXCODE` si `V_LOT` — ambii au deja `DEFAULT NULL`) | pozitional, se bazeaza deja pe omiterea parametrilor finali cu default |
-| ROAIMOB (COMUN) | `COMUN\clase\ofacturare.vc2` (offset ~13847) | 25/25, pozitional | idem grup |
-| ROAACNPRO (COMUN) | `COMUN\clase\ofacturare.vc2` (offset ~13853, grup identic) | 25/25, pozitional | idem |
-| ROACONTRACTE (COMUN) | `COMUN\clase\ofacturare.vc2` (offset ~13853, grup identic) | 25/25, pozitional | idem |
-| ROAAUTO (COMUN) | `COMUN\clase\ofacturare.vc2:13853` (+ `:17884`) | 25/25, pozitional | idem |
-| ROAACNPRO (implementare proprie) | `Programe\proceduri_acnpro.prg:3382` | apeleaza **`adauga_articol_factura_deviz`**, nu `adauga_articol_factura` — 17+ parametri pozitionali, verificat pana la `V_PRET_CU_TVA` (linia 3399), coada netaiata explicit dar tiparul e identic cu ROAAUTO de mai jos | pozitional |
-| ROAAUTO (implementare proprie) | `Programe\oproceduri_devize.prg:1240` | apeleaza `adauga_articol_factura_deviz`, **19 din 20** parametri (se opreste la `V_TAXCODE`, omite `V_LOT` final, care are `DEFAULT NULL`) | pozitional |
-| ROAFACTURARE (COMUN) | `COMUN\programe\ofacturare_stoc.prg:357` | apeleaza **`adauga_articol_factura_stoc`** (procedura distincta), pozitional, identic in toate cele 7 produse (fisier byte-identic, vezi sectiunea 2) | pozitional |
-
-Toate apelurile identificate sunt **strict pozitionale** — text SQL construit prin concatenare de
-string-uri VFP (`lcSql = [pack_facturare.functie(] + Alltrim(Str(...)) + [,] + ...`), nu apel VFP
-cu parametri numiti si nu `=>` (named notation) in PL/SQL. Niciun apelant nu foloseste named
-notation. **Singurul tip de apel care s-ar putea strica la adaugarea de parametri noi la coada ar
-fi un apel pozitional care specifica deja *mai multi* parametri decat lista curenta** (nu e cazul
-gasit) sau un apel care se opreste inainte de un parametru fara `DEFAULT` (nu e cazul: ambele
-proceduri `adauga_articol_factura` si `adauga_articol_factura_deviz` au deja tiparul "coada de
-parametri opsionali cu `DEFAULT NULL`" folosit activ de ROAGEST si ROAAUTO astazi — precedent direct
-ca acest tipar de extensie e deja tolerat de codul existent).
-
-### 1.2 `scrie_factura2` / `scrie_factura`
-
-Semnatura curenta (linia 640): 17 parametri, **fara niciun `DEFAULT`** — `V_TOTFTVA`...
-`V_PARAMETRU_ADITIONAL` (15 IN), `V_ID_VANZARE` (OUT), `V_CURSOR_VERIFICARE` (OUT, ultimul).
-
-| produs | fisier:linie | nr. parametri trimisi | mod |
-|---|---|---|---|
-| ROAFACTURARE (COMUN) | `COMUN\clase\ofacturare.vc2:14345` (+ al doilea sit `:18343`) | **16 din 17** — se opreste la `V_ID_VANZARE` (`?@poDate.nid_vanzare`), omite `V_CURSOR_VERIFICARE` | pozitional |
-| ROACONT/ROAGEST/ROAACNPRO/ROACONTRACTE (COMUN, grup identic) | `COMUN\clase\ofacturare.vc2:14130` (+ `:18124`) | 16 din 17, idem | pozitional |
-| ROAIMOB (COMUN) | `COMUN\clase\ofacturare.vc2:14124` (+ `:18118`) | 16 din 17, idem | pozitional |
-| ROAAUTO (COMUN) | `COMUN\clase\ofacturare.vc2:14129` (+ `:18151`) | 16 din 17, idem | pozitional |
-| ROAGEST (implementare proprie) | `Programe\ofactureaza.prg:307` | 16 din 17, idem (`?poDate.nid_vanzare` e ultimul bind) | pozitional |
-
-**Anomalie semnalata, in afara scopului cerut dar relevanta pentru risc general pe pachet**:
-toate sitele active de apel pentru `scrie_factura2` — in toate cele 7 produse, in ambele
-implementari (COMUN si ROAGEST proprie) — transmit **16 din cele 17 parametri declarati**,
-omitand complet ultimul parametru `V_CURSOR_VERIFICARE OUT pack_facturare.cursor_facturare`, care
-**nu are `DEFAULT`** (parametrii `OUT` nu pot avea `DEFAULT` in PL/SQL). Verificat identic in
-ambele exporturi disponibile (`ff_2026_08_06_10` si `ff_2026_08_09_01`), deci nu e o modificare de
-ultima ora. **NEVERIFICAT** cum functioneaza efectiv acest apel in productie (nu am acces la DB
-live) — posibile explicatii: (a) `goExecutor.oExecute(lcSql, lcCursorVerificare)` are o logica
-proprie de completare/legare a cursorului de iesire care nu se vede din text, (b) parametrul are
-de fapt un comportament tolerat de driver-ul Oracle folosit, sau (c) e un bug preexistent,
-netestat de multa vreme pe acest cod-cale. Nu are legatura cu schimbarea propusa la
-`contabilizeaza_articol` (nu se ating parametrii lui `scrie_factura2`), dar merita un test manual
-separat inainte de a presupune ca "toate caile prin pachet functioneaza azi fara eroare".
-
-### 1.3 `scrie_nota` / `scrie_nota_import` — fals pozitiv de cautare
-
-`scrie_nota_import` gasit in ROACONT (`Clase\oactualizari.vc2:920`, `Programe\ocont2003.prg:785`,
-`Programe\oproceduri_actualizari.prg:189`, `Programe\oproceduri_inchidere.prg:167,335,524`) si in
-ROAGEST (`Programe\inchidere_k.prg:192,257,373,381`) **NU este** functia `pack_facturare.scrie_nota`
-din pachet — e o **procedura VFP locala**, definita in
-`ROAFACTURARE\COMUN\programe\ooperatii_comune.prg:1081` (`PROCEDURE scrie_nota_import(...)`),
-folosita pentru import de note contabile, fara nicio legatura cu `PACK_FACTURARE`. Cautarea directa
-`pack_facturare\.scrie_nota\b` in tot arborele VFP a dat **zero rezultate** (sectiunea 0).
-
-### 1.4 `descarca_gestiune`
-
-Zero apeluri externe gasite in cod VFP (cautare directa `pack_facturare\.descarca_gestiune`,
-0 rezultate in toate cele 7 produse). Pachetul are doua supraincarcari (liniile 752 si 773),
-probabil folosite doar intern (apelate din `contabilizeaza_articol` conform comentariului de la
-linia 1466: `-- facturare_articole2, contabilizeaza_articol > descarca_gestiune`) —
-**NEVERIFICAT** linie-cu-linie in restul corpului pachetului (17217 linii; nu am parcurs tot
-corpul, doar semnaturile si comentariile relevante), dar nimic din cautarea externa VFP le atinge.
-
-## 2. Duplicarea fisierelor `COMUN\`
-
-Comparatie pe continut (MD5), nu pe nume, pentru cele 3 fisiere unde s-au gasit apeluri, in cele
-7 copii `COMUN\` (ROAFACTURARE, ROACONT, ROAGEST, ROAIMOB, ROAACNPRO, ROACONTRACTE, ROAAUTO):
-
-| fisier | rezultat |
-|---|---|
-| `clase\ofacturare.vc2` | **4 variante distincte**: ROAFACTURARE unic; {ROACONT, ROAGEST, ROAACNPRO, ROACONTRACTE} identice intre ele; ROAIMOB unic; ROAAUTO unic |
-| `programe\ofacturare_stoc.prg` | **identic byte-cu-byte in toate cele 7** (un singur MD5) |
-| `programe\ooperatii_comune.prg` | identic in 6 din 7; **ROAIMOB are o varianta diferita** |
-
-Pentru `ofacturare.vc2`, desi hash-urile difera intre cele 4 grupuri (fisierul are ~19000 de linii
-si diferente in alte zone), **structura si continutul exact al apelurilor catre
-`adauga_articol_factura` / `scrie_factura2` sunt identice cuvant-cu-cuvant** intre toate cele 4
-variante — doar offset-ul de linie difera (ex. apelul `adauga_articol_factura` e la linia 14069 in
-ROAFACTURARE, 13853 in grupul ROACONT/ROAGEST/ROAACNPRO/ROACONTRACTE, 13847 in ROAIMOB, 13853 in
-ROAAUTO — text identic, verificat prin grep pe fiecare variant separat). Deci pentru scopul acestei
-schimbari: **e acelasi sit de apel duplicat de 7 ori** (nu 7 implementari independente care ar
-putea diverge in reactia la parametri noi), plus doua implementari suplimentare, independente si
-reale, in ROAGEST (`Programe\ofactureaza.prg`) si ROAACNPRO/ROAAUTO
-(`Programe\proceduri_acnpro.prg` / `Programe\oproceduri_devize.prg`, pentru varianta `_deviz`).
-
-`ofacturare_stoc.prg` (contine apelul catre `adauga_articol_factura_stoc`) e literalmente **acelasi
-fisier**, deci 1 singur loc de verificat, nu 7.
-
-## 3. Cine emite efectiv facturi prin acest pachet
-
-Pe baza apelurilor gasite (nu doar a prezentei fisierului `COMUN\` — care exista in toate 7, dar
-nu inseamna ca produsul chiar il foloseste activ pentru facturare):
-
-| produs | ajunge la `pack_facturare` pentru facturare? | dovada |
-|---|---|---|
-| ROAFACTURARE | **Da** | `adauga_articol_factura` + `scrie_factura2` in `COMUN\clase\ofacturare.vc2` |
-| ROACONT | **Da** | acelasi cod COMUN (grup identic) |
-| ROAGEST | **Da**, cu 2 cai | codul COMUN identic + implementare proprie in `Programe\ofactureaza.prg` (posibil cod mai vechi/alternativ, coexista) |
-| ROAIMOB | **Da** | varianta proprie de `ofacturare.vc2`, dar acelasi tipar de apel |
-| ROAACNPRO | **Da**, cu 2 cai | codul COMUN (grup identic) + `adauga_articol_factura_deviz` in `Programe\proceduri_acnpro.prg` |
-| ROACONTRACTE | **Da** | codul COMUN (grup identic) — nu are cale proprie suplimentara gasita |
-| ROAAUTO | **Da**, cu 2 cai | varianta proprie de `ofacturare.vc2` + `adauga_articol_factura_deviz` in `Programe\oproceduri_devize.prg` |
-
-Niciun produs din cele 7 nu pare sa aiba `COMUN\clase\ofacturare.vc2` ca fisier mort — toate cele
-7 au si `Programe\` propriu (in afara de COMUN) care instantiaza clasa relevanta (NEVERIFICAT
-exhaustiv ca fiecare produs chiar *instantiaza si ruleaza* clasa din `ofacturare.vc2` la runtime —
-verificarea s-a facut pe prezenta apelului in sursa, nu pe flux de executie live). **Toate cele 7
-produse sunt in aria de regresie** pentru orice modificare de pachet care afecteaza
-`adauga_articol_factura*` sau `scrie_factura2` — nu doar ROAFACTURARE.
-
-## 4. Verdict de risc
-
-**Pentru `contabilizeaza_articol` insusi** (obiectul cerut al schimbarii): risc **practic zero**.
-Cei 3 apelanti sunt toti interni pachetului, toti pozitionali cu un singur argument identic cu
-semnatura actuala (`detalii_articol VANZARI_DETALII_TEMP%ROWTYPE`). Adaugarea de parametri noi
-`DEFAULT NULL` la coada nu schimba niciunul dintre aceste 3 apeluri — nu necesita nicio modificare
-in cele 3 sit-uri, indiferent de produs. Nu exista niciun apel extern (nici alt pachet PL/SQL, nici
-VFP din niciun produs) care sa poata fi afectat, pentru ca nu exista niciun apel extern, punct.
-
-**Pentru pachetul `PACK_FACTURARE` in ansamblu**, daca schimbarea reala atinge si alte proceduri
-publice (nu doar `contabilizeaza_articol`):
-- Tiparul "adauga parametri `DEFAULT NULL` la coada, apelantii pozitionali raman neschimbati"
- **are deja precedent activ** in codul curent: `adauga_articol_factura` (V_TAXCODE, V_LOT) si
- `adauga_articol_factura_deviz` (4 parametri finali cu DEFAULT) sunt deja apelate de unii
- producatori omitand parametrii finali optionali (ROAGEST, ROAAUTO). Deci genul de schimbare
- propus e sigur *daca* regula "toti parametrii noi sunt strict la coada si toti au DEFAULT" se
- respecta — ceea ce e exact ipoteza declarata pentru `contabilizeaza_articol`.
-- **Singurul risc real identificat in tot pachetul** nu vine din schimbarea propusa, ci e o
- anomalie preexistenta, independenta: apelurile la `scrie_factura2` (in toate cele 7 produse) omit
- deja parametrul final `V_CURSOR_VERIFICARE` (OUT, fara DEFAULT posibil). Daca cineva "repara" acea
- nepotrivire ca parte a aceleiasi lucrari de mentenanta pe pachet, *acolo* ar trebui atinsi toti
- apelantii din sectiunea 1.2 — dar asta e o schimbare diferita de cea descrisa (parametri noi la
- `contabilizeaza_articol`), nesolicitata explicit aici. O semnalez ca sa nu fie confundata cu
- "toti apelantii raman neschimbati" pentru intregul pachet, daca scopul lucrarii se extinde.
-- Nu s-a gasit niciun apel cu named notation (`=>`) nicaieri in cele 7 produse pentru functiile
- cerute — deci nu exista risc de reordonare-parametri-pe-nume la adaugarea de parametri noi.
-
-**Lista de produse pe care trebuie rulata regresia** (din sectiunea 3): toate cele 7 —
-ROAFACTURARE, ROACONT, ROAGEST, ROAIMOB, ROAACNPRO, ROACONTRACTE, ROAAUTO — pentru ca toate emit
-efectiv facturi prin acest pachet, chiar daca modificarea la `contabilizeaza_articol` insusi nu
-impune, teoretic, nicio schimbare de cod la niciunul dintre ele.
diff --git a/docs/cercetare/verif_baza_vie_cont_venit.md b/docs/cercetare/verif_baza_vie_cont_venit.md
deleted file mode 100644
index 0b547fe..0000000
--- a/docs/cercetare/verif_baza_vie_cont_venit.md
+++ /dev/null
@@ -1,250 +0,0 @@
-# Verificari pe baza de date vie — reteta contului de venit (#13, J-quater)
-
-Rulat: **10.08.2026**, schema `MARIUSM_AUTO` pe `ROA_CENTRAL` (`10.0.20.121:1521`, `SERVICE_NAME=ROA`),
-client `D:\ROA\instantclient_19_18\sqlplus.exe`. **Doar `SELECT`** — nicio scriere, nicio modificare de
-structura. Raspunde la punctul 2 din „Ce ramane deschis" al `docs\handoff_13_formular_unificat.md`.
-
-## Verdict, in trei randuri
-
-**Pasul 1 al retetei (derivarea `SCC`) e sigur: zero ambiguitate, zero cazuri de cont de venit gol pe
-articole reale.** **Pasul 2 (gasirea unei politici cu acel `SCC`) reuseste pentru 3 din 7 conturi
-candidate si eșueaza pentru 4** — dar nu asa cum prevedea planul: **`704` are 19 politici valabile azi,
-nu zero**, iar cele care lipsesc sunt `702`, `703`, `711`, `7018`. **Riscul serios nu e ambiguitatea, ci
-`PTVA`-ul notei** — singura nota cu `SCC=707` are `PTVA=5`, deci alegerea politicii dupa `SCC` importa si
-o cota de TVA care poate fi greșita.
-
-## Doua corectii la planul si handoff-ul rundei 8
-
-| Ce spune planul (J-quater, „Costurile") | Ce arata baza vie |
-|---|---|
-| „pentru **704** nu s-a gasit nicio nota configurata, deci trebuie creata o data din ecranul de configurare note contabile" | **FALS.** `704` e cel mai bine acoperit cont: **4 note de vanzari** (`NOTA 1`, `COMISION INTERMEDIERE`, `SERVICII VALUTA`, `SERVICII TRANSPORT`) si **25 de politici** (19 valabile azi). `NOTA 1` — nota implicita a majoritatii politicilor — are exact `SCC=704`. **Pasul de creare a notei pentru 704 se scoate din plan.** |
-| „`CONT_VENIT` are date reale (**20 de conturi**, migrare 2023)" | **Imprecis.** Tabelul are **41 de randuri active**; exact **20** au `CONT_VENIT` populat. Restul 21 sunt conturile de ajustari (`391`…`398`, toate cu `CONT_CHELT=681`) — vezi mai jos de ce nu conteaza. |
-
-Ce **se confirma** din plan: `CONT_VENIT` **n-are consumatori** (nu am verificat aici — a fost stabilit pe
-cod in runda 8); lantul invers e realizabil; ambiguitatea „mai multe politici cu acelasi `SCC`" e reala.
-
-## 1. DDL-ul lui `CORESP_CONT_VENCHELT` (cerut explicit in handoff)
-
-| # | Coloana | Tip | Null |
-|---|---|---|---|
-| 1 | `ID_CCV` | `NUMBER(10,0)` | N |
-| 2 | `CONT` | `VARCHAR2(4)` | Y |
-| 3 | `CONT_CHELT` | `VARCHAR2(4)` | Y |
-| 4 | `CONT_VENIT` | `VARCHAR2(4)` | Y |
-| 5 | `STERS` | `NUMBER(1,0)` | N |
-| 6 | `DATAORAS` | `DATE` | Y |
-| 7 | `CONT_APROVIZIONARE` | `VARCHAR2(4)` | Y |
-| 8 | `CONT_DIFERENTE` | `VARCHAR2(4)` | Y |
-
-Constrangeri: **doar** `PK_CORESP_CONT_VENCHELT` pe `ID_CCV`, plus `NOT NULL` pe `ID_CCV` si `STERS`.
-**Nu exista unique pe `CONT`** — deci nimic in schema nu impiedica doua randuri pe acelasi cont de
-gestiune. In date insa **nu exista niciun `CONT` duplicat**, deci pasul 1 al retetei e determinist azi.
-Fragilitatea e de tip „merge pana nu merge": daca cineva adauga un al doilea rand pe `301`, derivarea
-devine ambigua fara ca nimic sa semnaleze.
-
-## 2. Continutul relevant al tabelului — cele 20 de randuri cu cont de venit
-
-| `CONT` (gestiune) | `CONT_CHELT` | **`CONT_VENIT`** |
-|---|---|---|
-| `231` | `212` | `707` |
-| `301`, `302`, `3021`–`3028`, `303` | `601`, `602`, `6021`–`6028`, `603` | **`707`** (13 randuri) |
-| `331`, `332` | `711` | `711` |
-| `341` | `711` | `702` |
-| `345`, `348` | `711` | `7015` |
-| `346` | `711` | `703` |
-| `361` | `711` | `7018` |
-| `371` | `607` | `707` |
-| `381` | `608` | `707` |
-
-Cele 21 de randuri fara `CONT_VENIT` sunt `391`, `392`, `3921`, `3922`, `393`, `394`, `3941`, `3945`,
-`3946`, `395`, `3951`–`3958`, `396`, `397`, `398` — toate cu `CONT_CHELT=681`, adica **ajustari pentru
-depreciere**, nu conturi de gestiune pe care sta marfa.
-
-**Si contează**: `articole_pe_cont_cu_venit_gol = 0`. Niciun articol activ din `NOM_ARTICOLE` nu are
-`CONT`-ul pe un rand cu `CONT_VENIT` gol. **Deci ramura „cont de venit derivat gol" nu are cazuri reale**
-— trebuie tratata defensiv, dar nu e un scenariu de acoperit in UX.
-
-## 3. Interogarea inversa — rezultatul pe fiecare `SCC` candidat
-
-```sql
-with cand as (select column_value scc from table(sys.odcivarchar2list('707','711','702','703','7015','7018','704')))
-select c.scc, count(distinct p.id_pol) pol,
- count(distinct case when nvl(p.datai,date '1900-01-01')<=trunc(sysdate)
- and nvl(p.datas,date '2999-12-31')>=trunc(sysdate)
- then p.id_pol end) pol_valabile_azi,
- count(distinct nc.id_set) seturi, count(nc.id_note) nc_randuri
- from cand c
- left join note_contabile nc on nc.scc = c.scc
- left join crm_note_vanzari nv on nv.id_set = nc.id_set and nvl(nv.sters,0)=0
- left join crm_politici_preturi p on p.id_nota = nv.id_nota and p.sters=0
- group by c.scc;
-```
-
-| `SCC` | Politici | **Valabile azi** | Seturi cu acest `SCC` | Randuri `NOTE_CONTABILE` | Verdict pentru pasul 2 |
-|---|---|---|---|---|---|
-| **`704`** | 25 | **19** | 7 | 28 | **reuseste**, cu ambiguitate mare |
-| **`707`** | 4 | **4** | 5 | 8 | **reuseste**, ambiguitate mica |
-| **`7015`** | 1 | **1** | 1 | 1 | **reuseste, caz ideal** |
-| `711` | 0 | 0 | 4 | 4 | **eșuează** — note exista, dar **nicio politica** nu le foloseste |
-| `702` | 0 | 0 | 3 | 3 | **eșuează** — idem |
-| `703` | 0 | 0 | 3 | 3 | **eșuează** — idem |
-| `7018` | 0 | 0 | **0** | **0** | **eșuează total** — nu exista nici macar nota |
-
-Citit pe conturile de gestiune: reteta merge pentru marfa (`301`–`303`, `371`, `381`, `231` → `707`) si
-pentru produsele din `345`/`348` (→ `7015`), plus pentru orice cade pe fallback-ul `704`. **Nu merge**
-pentru `331`/`332` (→ `711`), `341` (→ `702`), `346` (→ `703`), `361` (→ `7018`) — adica **producția
-neterminată, semifabricatele, produsele reziduale si ambalajele**.
-
-Distinctia care conteaza la `711`/`702`/`703`: **nota exista, doar politica lipseste.** Costul de
-configurare e „ataseaza nota existenta unei politici", nu „creeaza nota de la zero". Doar `7018` cere
-si nota noua.
-
-## 4. Riscul pe care planul nu l-a vazut: `PTVA` si `IN_VALUTA` de pe nota
-
-Cele 7 note de vanzari active, cu nota contabila atasata:
-
-| `ID_NOTA` | Denumire | `ID_SET` | `SCD` | **`SCC`** | **`PTVA`** | `CU_TVA` | **`IN_VALUTA`** |
-|---|---|---|---|---|---|---|---|
-| 1 | `NOTA 1` | 251023 | `4111` | **704** | **21** | 1 | 0 |
-| 2 | `DISCOUNT` | 251024 | `667` | 4111 | 21 | 1 | 0 |
-| 3 | `COMISION INTERMEDIERE` | 251025 | `4111` | **704** | **0** | 1 | **1** |
-| 4 | `SERVICII VALUTA` | 251026 | `4111` | **704** | **0** | 1 | **1** |
-| 5 | `VANZARE MARFA` | 251027 | `4111` | **707** | **5** | 1 | 0 |
-| 6 | `PRODUCTIE` | 251028 | `4111` | **7015** | 21 | 1 | 0 |
-| 7 | `SERVICII TRANSPORT` | 251029 | `4111` | **704** | 21 | 1 | 0 |
-
-> **RETRAS — verificat pe cod si infirmat.** Ingrijorarea de mai jos, formulata la prima citire a acestor
-> date („`PTVA=5` pe singura nota cu `SCC=707` produce TVA greșit"), **nu se susține**.
-> `docs\cercetare\s10_pret_rederivat.md`, „Completare: nota contabila a politicii" p. 2: `cursor_articol`
-> (`PACK_FACTURARE:7218-7271`) **nu selecteaza `D.PTVA`**; cota folosita e
-> `detalii_articol.proc_tvav * 100 - 100` (`:7464`), din articol / document. Coloana e moarta pentru
-> `contabilizeaza_articol`. Iar `IN_VALUTA=1` pe un document in lei nu da eroare si nu strica suma —
-> doar populeaza redundant `ACT_TEMP.SUMA_VAL` la curs 1. **Deci criteriul de selectie NU trebuie extins
-> cu `PTVA` / `IN_VALUTA`.** Se pastreaza textul de mai jos doar ca urma a raționamentului; nu se citeaza
-> ca risc.
-
-Ce **rămâne** ca risc real din aceste date, si e mai grav: `cursor_articol` face `LEFT JOIN
-NOTE_CONTABILE ON C.ID_SET = D.ID_SET` fara `ROWNUM` si fara agregare, iar bucla care il consuma executa
-`scrie_nota` **si** `descarca_gestiune` o data **pentru fiecare rand al setului**, cu pretul si cantitatea
-intregi de fiecare data. Deci un set cu N randuri = **venit inregistrat de N ori si gestiune descarcata de
-N ori**. Cele 7 note de vanzari active au exact un rand fiecare — dar **30 din cele 40 de seturi din baza
-au mai multe, cu maxim 30**. Vezi punctul 6.1 mai jos.
-
-Ce planul enunta drept **avantaj** al retetei — „politica reala aduce si `CU_TVA`, `IN_VALUTA`,
-`EXPLICATIE`, `ASCD`, `ASCC`" — se confirma ca argument, cu nuanta ca `ASCD`/`ASCC` au oricum fallback
-automat din grupul de utilizatori, deci nu ele justifica alegerea.
-
-Textul original al ingrijorarii, pastrat pentru trasabilitate:
-
-- **`707` are o singura nota, si aceea cu `PTVA=5`.** Pentru marfa (majoritatea articolelor de gestiune)
- singurul rezultat posibil al pasului 2 e nota cu TVA 5%.
-- **Doua din cele patru note cu `SCC=704` au `IN_VALUTA=1`** (`SERVICII VALUTA`, `COMISION INTERMEDIERE`),
- deci o potrivire pe `SCC` poate ateriza pe ele pe un document in lei.
-
-Colateral util pentru **S4c**: exista deja o nota de discount configurata — `id_nota=2`, `SCD=667` /
-`SCC=4111`. Nu e o eroare de configurare (explica randul `SCC=4111` din agregat), e nota folosita pentru
-discount. De verificat la S4c daca discountul pe linie trece prin ea.
-
-## 5. Efectul colateral al pasului 3 — politica **este** o lista de preturi
-
-Pasul 3 al retetei insereaza articolul in politica alesa, prin `pack_preturi.adauga_politica_pret_art`.
-Politicile candidate, cu numarul de articole pe care le contin azi:
-
-| `SCC` | `ID_POL` | Nume | Articole |
-|---|---|---|---|
-| `7015` | 41 | `STOC PRODUSE` | **6310** |
-| `707` | 39 | `LISTA PRETURI LEI` | **909** |
-| `707` | 40 | `LISTA PRETURI CU TVA EURO` | 2 |
-| `707` | 47 / 62 | `DEPOZIT ELI` / `DEPOZIT ELI_31/07/2025 11:07:25` | 3 / 3 |
-| `704` | 2 | `LISTA 2` | 19 |
-| `704` | 34 | `LISTA 2 - EURO` | 12 |
-| `704` | 36 | `SERVICE AUTO` | 9 |
-| `704` | 35 | `LISTA STANDARD EURO` | 8 |
-| `704` | 9 | `CHIOSC` | 5 |
-| `704` | 6, 12, 13, 14, 15, 16 | `LISTA DE PROBA`, `S5 ZILNIC`, `S6 WEEKEND SEZON`, `S7 CRACIUN`, `S3 PASTE`, `S3 1MAI` | 4 fiecare |
-| `704` | 65, 66 | `TRANSPORT`, `SERVICII INFORMATICE` | 1 fiecare |
-| `704` | 26, 27, 28, 29, 30, 31 | `S6 ZILE IARNA`, `S8 REVELION`, `S1 IARNA2`, `S1 IARNA2 WEEKEND`, `S2 PRIMAVARA`, `S7 CRACIUN` | **0** |
-
-**Astea sunt liste de preturi reale, cu nume de client si de sezon.** Daca reteta alege `LISTA PRETURI
-LEI` sau `STOC PRODUSE` pentru un articol adaugat ad-hoc pe factura, articolul **apare de acum in lista
-de preturi a acelui context**, cu pretul cu care a fost facturat o data. Asta e efectul pe care planul il
-descrie drept „politica tehnica populata automat" — dar **numai daca politica e chiar tehnica**.
-Alegerea unei politici comerciale existente **poluează o lista de preturi de producție**.
-
-Consecinta de proiectare, de dus in J-quater: pasul 2 nu trebuie sa caute *orice* politica cu `SCC`-ul
-potrivit, ci **o politica tehnica dedicata, una per `SCC`**, creata anume — modelul
-`gnId_pol_pret_stoc` extins de la o politica la sapte. Cele sase politici cu **0 articole** arata ca o
-politica goala e o stare acceptata de produs.
-
-Detaliu care ajuta: **majoritatea politicilor cu `SCC=704` trimit la aceeasi `id_nota=1`**. Deci
-ambiguitatea celor 19 politici e ambiguitate de **lista de preturi**, nu de rezultat contabil — toate dau
-acelasi `704` / `PTVA=21` / lei. Cu atat mai mult, criteriul de alegere trebuie sa fie „care lista de
-preturi vreau sa murdaresc", si raspunsul corect e „niciuna dintre cele existente".
-
-## 6. Fragilitati masurate, de trecut in Riscuri
-
-1. **`ID_SET` cu mai multe randuri dubleaza venitul si descarcarea de gestiune.** Pe cele 7 seturi
- folosite de politici, fiecare are exact **1** rand `NOTE_CONTABILE`. Dar in tabel sunt **40 de seturi,
- din care 30 au mai multe randuri**, cu maxim **30 de randuri pe set**. Confirmat pe cod
- (`s10_pret_rederivat.md`, Completare p. 1): `cursor_articol` face `LEFT JOIN ... ON C.ID_SET =
- D.ID_SET` **fara `ROWNUM`, fara agregare, fara filtru**, iar bucla `:7393-7542` executa `scrie_nota`
- **si** `descarca_gestiune` o data per rand, **cu aceeasi cantitate si acelasi pret intreg**, fara
- distributie (`ORDINE` nu apare in tot pachetul). Deci pasul 2 al retetei trebuie sa garanteze **un
- singur rand pe setul ales**, nu doar un rand cu `SCC`-ul potrivit. Conditia care face reteta sigura
- azi e o coincidenta a datelor, nu o garanție a codului sau a schemei.
-2. **Doua politici active fara `ID_NOTA`**: `32 HOTEL TAXE` si `33 HOTEL CAZARE` (ambele valabile
- 01.01.2010–31.12.2099, `id_valuta=3`). Un articol pe una din ele are `id_pol` valid dar **fara nota** —
- comportament neverificat, intrebare trimisa agentului pe `PACK_FACTURARE`. E o gaura care **exista
- deja azi**, independenta de #13.
-3. **Fara unique pe `CORESP_CONT_VENCHELT.CONT`** — vezi punctul 1.
-
-## 7. Distributia articolelor — cat de mult conteaza fiecare ramura a deciziei 27
-
-`NOM_ARTICOLE`, 6430 articole active:
-
-| Prima cifra din `CONT` | Articole | Conturi distincte | Ramura deciziei 27 |
-|---|---|---|---|
-| `3xx` | **6125** | 9 | gestionabil → `CORESP_CONT_VENCHELT` |
-| `8xx` (toate `8035`) | 26 | 1 | nu e 6xx/7xx, nu e in `CORESP` → **`704`** |
-| `6xx` | 22 | 5 | `NOM_ARTICOLE.CONT` ca atare |
-| `7xx` | 20 | 6 | `NOM_ARTICOLE.CONT` ca atare |
-| `1xx` | 4 | 2 | → `704` |
-| `4xx` | 3 | 2 | → `704` |
-| `0xx` | 1 | 1 | → `704` |
-| `2xx` | 1 | 1 | → `704` |
-| **fara `CONT`** | **228** | — | → `704` |
-
-Conturi de pe articole care **nu** sunt 6xx/7xx si **nu** apar in `CORESP_CONT_VENCHELT.CONT`, deci cad pe
-`704`: `8035` (26 articole), `123` (3), `446` (2), `111`, `409`, `0`, `212`, `37` (1 fiecare).
-
-**Ramura dominanta e de departe cea gestionabila** — 6125 din 6430. Iar ea trimite in majoritate spre
-`707`, adica spre cazul cu `PTVA=5`. Cele 228 de articole fara cont si cele 26 pe `8035` fac fallback-ul
-`704` un caz real, nu teoretic — si acolo reteta functioneaza.
-
-Nota: `212` apare pe un articol, dar in `CORESP_CONT_VENCHELT` figureaza ca `CONT_CHELT` (pe randul
-`231`), nu ca `CONT`. Deci cade corect pe `704` prin regula deciziei 27.
-
-## Ce nu s-a putut stabili aici, si de ce
-
-- **Ce face `contabilizeaza_articol` cu `PTVA` / `CU_TVA` / `IN_VALUTA` ale notei** — e intrebare de cod,
- nu de date. Trimisa agentului deja incarcat in `PACK_FACTURARE`; raspunsul intra in
- `docs\cercetare\s10_pret_rederivat.md`, sectiunea „Completare: nota contabila a politicii". **Pana
- atunci pasul 2 al retetei nu se considera validat.**
-- **Daca `CONT_VENIT` chiar n-are consumatori** — stabilit pe cod in runda 8, nu reverificat pe date.
-- **Comportamentul politicii fara nota** — idem, intrebare de cod, trimisa.
-- Verificarile sunt pe **schema de dezvoltare** `MARIUSM_AUTO`. Datele sunt reprezentative (liste de
- preturi cu nume reale, 6430 articole), dar **o baza de client poate avea alta configurare de note** —
- in special poate avea deja politici pe `711` / `702` / `703`. Concluziile pe **structura** (lantul,
- absenta unique-ului, `ID_SET` multi-rand) sunt insa independente de date.
-
-## Reproducere
-
-Cele trei scripturi rulate, in ordine: descoperire DDL/coloane · interogarea inversa pe `SCC` ·
-efecte colaterale si distributii. Interogarea-cheie e citata integral la punctul 3. Rulare:
-
-```powershell
-& 'D:\ROA\instantclient_19_18\sqlplus.exe' -L -S 'MARIUSM_AUTO/ROMFASTSOFT@ROA_CENTRAL' '@fisier.sql'
-```
-
-SQL-ul se scrie in fisier **ASCII**, nu prin pipe din PowerShell (BOM-ul UTF-16 sparge parserul), si cu
-`linesize 32767` — vezi `COMUN\docs\oracle_export.md`.
diff --git a/docs/cercetare/verif_goluri_ntip_aviz.md b/docs/cercetare/verif_goluri_ntip_aviz.md
deleted file mode 100644
index d38ed9a..0000000
--- a/docs/cercetare/verif_goluri_ntip_aviz.md
+++ /dev/null
@@ -1,325 +0,0 @@
-# Verificare adversariala — golul ntip=4 si "ramurile de aviz" (contabilizeaza_articol)
-
-Verifica raportul `docs/cercetare/gol_ntip4_factura_din_avize.md`. Rol: incercare de infirmare,
-nu confirmare. Toate citatele de mai jos sunt re-verificate direct in aceasta runda pe
-`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (17217 linii) si
-pe `COMUN\clase\ofacturare.vc2` (ambele copii, `frm_facturare_articole` ~13967-14500 si
-`frm_facturare_articole2` ~18003-18500). Status: **TERMINAT**.
-
-## Corectie structurala prealabila — cei "3 apelanti" ai `contabilizeaza_articol` sunt gresit numiti
-
-Toate rapoartele anterioare (`canal_cont_venit_fara_politica.md:67`, `nota_contabila_fara_politica.md:103`,
-si implicit raportul verificat) numesc cei 3 apelanti interni `scrie_factura2`,
-**`scrie_factura_avize_retur`**, `scrie_aviz_retur`. **Gresit pentru al doilea.** Verificare directa
-pe granitele reale (`PROCEDURE ...` / `END ...`):
-
-```
-ff_...:6264 PROCEDURE scrie_factura_avize_retur(... ff_...:6657 END scrie_factura_avize_retur;
-ff_...:6692 PROCEDURE scrie_factura_avize(... ff_...:7058 END scrie_factura_avize;
-ff_...:7085 PROCEDURE scrie_aviz_retur(... ff_...:7171 END scrie_aviz_retur;
-```
-
-Apelul de la `ff_...:6858` (`pack_facturare.contabilizeaza_articol(tab_detalii(i));`, in interiorul
-`IF articole_aviz(j).custodie = 1 THEN`) cade **intre 6692 si 7058** — deci apartine lui
-**`scrie_factura_avize`** (fara `_retur`), nu lui `scrie_factura_avize_retur` (care se termina la
-6657, cu 200+ linii inainte). `scrie_factura_avize_retur` **nu cheama deloc**
-`contabilizeaza_articol` — corpul ei (6264-6657) insereaza direct in `VANZARI_DETALII_TEMP` din
-`VANZARI_DETALII` (randurile avizului sursa deja existente), fara sa treaca prin
-`adauga_articol_factura` sau `contabilizeaza_articol`.
-
-**De ce conteaza**: `scrie_factura_avize` e exact handler-ul Oracle pentru `ntip=4` ("facturare din
-aviz") — apelat din VFP la `ofacturare.vc2:14318` (`Case poDate.Tip = 4`). Deci al doilea apel real
-catre `contabilizeaza_articol` **e in interiorul propriului handler `ntip=4`** (pentru randurile
-`custodie=1`), nu intr-un flux separat "avize+retur". Cei 3 apelanti reali sunt:
-
-| Apel | Procedura reala | Cand se ajunge la ea din VFP |
-|---|---|---|
-| `ff_...:6141` | `scrie_factura2` | `Case Inlist(poDate.Tip,3,21,25,28,42,47)` sau `Otherwise` (`ofacturare.vc2:14332,14361`, identic la `:18330,18361`) — calea principala pentru aproape toate tipurile, inclusiv avizele |
-| `ff_...:6858` | `scrie_factura_avize` | `Case poDate.Tip = 4` (`:14301,14318`) — doar pentru randurile `custodie=1` ale unei facturi din aviz |
-| `ff_...:7140` | `scrie_aviz_retur` | **Niciun apel gasit in `COMUN\` din VFP** (`Grep` pe tot `COMUN` si pe tot proiectul — zero rezultate in cod, doar in rapoarte). Posibil cod mort/apelat din alt produs; nu afecteaza verdictele de mai jos, pentru ca `scrie_factura2` singura e suficienta sa dovedeasca A1a. |
-
-Corectia nu schimba verdictul general al A1a (avizele *ajung* la `contabilizeaza_articol`), dar
-schimba **prin ce drum** — relevant pentru oricine ar urma sa scrie cod pe baza acestor rapoarte.
-
-## A1. Ramurile de AVIZ raman atinse si ramura noua le-ar scrie SCD gresit
-
-**Verdict: CONFIRMAT, dar mai ingust decat sustine raportul.**
-
-### A1a. Ajunge `contabilizeaza_articol` sa fie apelata pe un AVIZ?
-
-**DA, confirmat**, prin `scrie_factura2`. Ruta VFP (`ofacturare.vc2:14282-14389`, identic la
-`:18enable...`, verificata in ambele copii ale formularului):
-
-```
-Case poDate.eProforma = 1 -> scrie_proforma
-Case poDate.Tip = 4 -> scrie_factura_avize && facturare din aviz
-Case Inlist(poDate.Tip,3,21,25,28,42,47) -> scrie_factura2 && din comenzi / avize din comenzi
-Otherwise -> scrie_factura2 && tot restul (incl. 29, 22, 24, 27...)
-```
-
-In interiorul `scrie_factura2` (`ff_...:6072-6142`), CASE-ul propriu **intercepteaza unele `ntip`
-inainte** de a ajunge la `contabilizeaza_articol`:
-
-```
-WHEN ntip IN (23,25,30,41) THEN transfera_articol(...) -- NU contabilizeaza_articol
-WHEN ntip IN (42,47) THEN descarca_gestiune(...) direct -- NU contabilizeaza_articol
-WHEN ntip IN (2,6,52) AND id_rata<>0 THEN contabilizeaza_rata(...)
-ELSE contabilizeaza_articol(...) -- aici ajung 28, 29, 21, 22, 24, 27, 3, ...
-```
-
-Deci `ntip=28` si `ntip=29` **chiar ajung** la `contabilizeaza_articol` (prin `scrie_factura2`, ramura
-`ELSE`) — asta confirma miezul A1a. Dar `ntip IN (23,25,30,41,42,47)`, desi trec prin `scrie_factura2`
-(sunt in lista VFP `Inlist(3,21,25,28,42,47)`), **nu ajung niciodata** la `contabilizeaza_articol` —
-sunt deviate mai devreme, in CASE-ul propriu al lui `scrie_factura2`, spre `transfera_articol`/
-`descarca_gestiune`. Vezi corectia la sectiunea 3 (tabelul per-`ntip`).
-
-### A1b. Poate un articol fara politica sa fie adaugat pe un aviz?
-
-**DA, confirmat structural**, pe doua cai distincte in `adauga_articol_factura` (`ff_...:5052-5203`):
-
-- `WHEN ntip IN (3,21,28,42,47)` (`:5053-5078`): cauta in `COMENZI_ELEMENTE` dupa
- `ID_COMANDA + ID_ARTICOL + PRET` — **fara nicio referinta la `V_ID_POL`** in `WHERE`. Un articol
- fara politica poate gasi potrivire aici daca exista elementul de comanda corespunzator (comanda +
- articol + pret identice), indiferent de politica. **Fara handler `EXCEPTION`** — la fel ca ramura
- `ntip=4`, dar aici absenta handler-ului nu conteaza pentru `id_pol`, pentru ca filtrul nu-l
- foloseste.
-- `ELSE` (`:5187-5203`, bucket-ul implicit pentru orice `ntip` neacoperit de ramurile speciale —
- include `29` si restul avizelor "simple"): **nicio interogare legata de politica** — ia direct
- `V_PRET_TEMP`/`V_ID_VALUTA_TEMP`/`V_PRETURI_CU_TVA_TEMP`/`V_IN_STOC_TEMP` (valorile deja calculate
- de VFP), plus o singura `SELECT` pe `JTVA_COLOANE` dupa `V_ID_JTVA_COLOANA` (nimic legat de
- `id_pol`). **Zero obstacol** pentru un articol fara politica pe aceasta ramura.
-
-Nu am gasit (si nu am cautat exhaustiv, la fel ca raportul original) formularul VFP concret care ar
-adauga azi un articol ad-hoc fara politica pe un aviz — premisa ramane, ca si in raportul original,
-mostenita din proiectul #13 (`canal_cont_venit_fara_politica.md`), nu re-derivata aici. Ce am putut
-confirma exhaustiv e partea Oracle: **daca** VFP trimite `V_ID_POL=NULL` pe aceste `ntip`, Oracle nu
-pune nicio piedica.
-
-### A1c. `SCD` in blocul `:7398-7423` — hardcodat sau derivat?
-
-Citit integral (`ff_...:7398-7423`), confirmat identic cu citatul raportului, **linie cu linie**:
-
-```
-ff_...:7400-7406 WHEN ntip<=20 OR ntip IN (nTipFacturaHotel,nTipFacturaRestaurant,
- nTipNotaPlata,nTipVanzareRetail,48,49,51,52) THEN
- V_SCD := crs_rand_articol.scd; -- din politica (NOTE_CONTABILE.SCD)
-ff_...:7413-7417 WHEN ntip IN (28,29) THEN
- V_SCD := '461'; -- HARDCODAT, aviz catre clienti debitori
-ff_...:7418-7422 ELSE
- V_SCD := '418'; -- HARDCODAT, aviz generic
-```
-
-`V_SCC` (linia 7425) vine mereu din `crs_rand_articol.scc` (coloana notei de vanzari), **indiferent
-de ramura** — CASE-ul de mai sus decide doar `V_SCD`. Confirmat: hardcodarea exista exact cum spune
-raportul, fara offset de linie.
-
-**Nuanta importanta, omisa de raport**: proiectarea `canal_cont_venit_fara_politica.md:146` (sursa
-ramurii noi) **flagheaza deja, printr-o paranteza**, ca "ramurile aviz raman `'418'`/`'461'`, deja
-hardcodate azi la `ff_...:7415,7420`, independent de politica" — deci designul **e constient** de
-existenta acestor hardcodari si de faptul ca ar trebui pastrate, dar **nu da structura de cod
-concreta** (niciun `IF`/`CASE` pe `ntip` in tabelul "Continutul ramurii noi", sectiunea 3) care sa
-implementeze efectiv acea pastrare. Raportul verificat prezinta acest lucru ca pe o **descoperire
-noua** ("Gol sora... gasit in aceasta cercetare") — de fapt designul deja stia de riscul general, dar
-nu-l rezolvase in cod. Concluzia practica ramane aceeasi (ramura noua, asa cum e descrisa azi in
-proiectare, chiar ar hardcoda `SCD='4111'` fara conditionare pe `ntip` daca ar fi implementata
-literal dupa tabelul din sectiunea 3), dar caracterizarea "gol nou, neconsemnat" e inexacta.
-
-### Corectie la tabelul per-`ntip` din raport (sectiunea 3)
-
-Raportul marcheaza `IN (28,29)` **si** "toate celelalte (`21,22,23,24,25,27,30,41,42,47,...`)" ca
-"Atinsa: DA". Pe baza rutarii reale prin `scrie_factura2` (A1a de mai sus):
-
-| `ntip` | Ajunge la `contabilizeaza_articol`? | Motiv |
-|---|---|---|
-| `28`, `29` | **DA** | `scrie_factura2` -> `ELSE` -> CASE intern `ntip IN(28,29)` -> `SCD='461'` |
-| `21`, `22`, `24`, `27`, `3` si alte "otherwise" nespeciale | **DA** (probabil) | cad in `ELSE` al lui `scrie_factura2` -> `ELSE` intern -> `SCD='418'` |
-| `23`, `25`, `30`, `41` | **NU** | interceptate in `scrie_factura2` de `WHEN ntip IN(23,25,30,41) THEN transfera_articol(...)` — nu ajung niciodata la `contabilizeaza_articol` prin acest apelant |
-| `42`, `47` | **NU** | interceptate de `WHEN ntip IN(42,47) THEN descarca_gestiune(...) direct` — la fel, nu ajung |
-
-Golul real e deci mai ingust decat "orice aviz": se limiteaza la avizele care cad in ramura `ELSE` a
-lui `scrie_factura2` (28, 29, si restul avizelor "simple" neexcluse), nu la `23,25,30,41,42,47`, care
-sunt structural neatinse de `contabilizeaza_articol` prin singurul apelant confirmat. (Nu exclud ca
-`scrie_aviz_retur`, al carei apelant VFP nu l-am gasit, sa trateze si aceste `ntip` — dar cum nu exista
-dovada ca e apelata deloc, nu pot confirma nici infirma pentru ea.)
-
-## A2. Golul `ntip=46` (`nTipNotaPlata`) — `scrie_nota` sarita azi
-
-**Verdict: CONFIRMAT.**
-
-- Constanta: `ff_...:84 nTipNotaPlata VANZARI.TIP%TYPE := 46;` — **exact 46**, verificat direct, nu
- presupus.
-- Garda: `ff_...:7441 IF pack_facturare.nTip <> pack_facturare.nTipNotaPlata THEN` — inainte de
- apelul `scrie_nota` (`:7443-7467`) — citat exact, linie identica cu raportul.
-- Poate un `ntip=46` sa primeasca un articol fara politica? **DA**, prin acelasi bucket `ELSE`
- (`ff_...:5187-5203`) al `adauga_articol_factura` verificat la A1b — `nTipNotaPlata` nu e in niciuna
- din ramurile speciale (`3,21,28,42,47`, `4`, `45`, `V_OPT_FACTURARE=3`), deci cade in `ELSE`, care
- nu cere `id_pol` deloc.
-- Ajunge la `contabilizeaza_articol`? **DA** — `ntip=46` nu e proforma, nu e `Tip=4`, nu e in
- `Inlist(3,21,25,28,42,47)` -> `Otherwise` -> `scrie_factura2` -> nu e in `(23,25,30,41)`/`(42,47)`/
- `(2,6,52)` -> `ELSE` -> `contabilizeaza_articol`.
-- Ramura noua (per `canal_cont_venit_fara_politica.md` sectiunea 3, pasul 1 "Apeluri, o singura data
- fiecare") descrie apelul `scrie_nota` **fara** sa mentioneze garda `ntip<>nTipNotaPlata` — deci, asa
- cum e scrisa azi proiectarea, ar apela necondiționat `scrie_nota` pentru un document `NotaPlata` cu
- linie `cont_venit`. Gol real, bine argumentat de raport.
-
-## A3. `ntip=4` exclus prin `NO_DATA_FOUND` neprins la `adauga_articol_factura`
-
-**Verdict: CONFIRMAT**, cu toate liniile citate verificate exact, fara offset:
-
-- `ff_...:5080-5103` — ramura `WHEN ntip=4`, `WHERE A.ID_POL = V_ID_POL` (linia 5096 exact), fara
- `EXCEPTION`. Confirmat caracter cu caracter identic cu citatul raportului.
-- Semantica SQL `NULL = NULL` -> `UNKNOWN`, niciodata `TRUE`: standard, corect.
-- **Ordinea de apel confirmata direct pe VFP**: `do_scrie_articole` (`ofacturare.vc2:13967`) cheama
- `initializeaza_date_factura` (seteaza `ntip`), apoi in bucla `Scan` peste `crsfactura` cheama
- `adauga_articol_factura` (`:14069-14091`) pentru fiecare rand — **toate acestea ruleaza inainte** de
- `Do Case` (`:14282`) care alege `scrie_factura_avize`/`scrie_factura2`/etc. Deci un articol cu
- `V_ID_POL=NULL` pe `ntip=4` cade la `adauga_articol_factura` **inainte** ca `scrie_factura_avize` sa
- fie chemata — linia nu ajunge niciodata la `contabilizeaza_articol`. Confirma independent
- concluzia raportului.
-- **Semantica VFP `Nvl(Alltrim(Str(poArt.id_pol)),[NULL])`** (`ofacturare.vc2:14072`, identic
- `:18107`): in Visual FoxPro, `Str()` si `Alltrim()` **propaga `.NULL.`** cand primesc `.NULL.` ca
- argument (comportament standard, documentat al limbajului — orice functie "null-aware" aplicata pe
- `.NULL.` intoarce `.NULL.`, nu eroare si nu `"0"`). `Nvl(.NULL., [NULL])` inlocuieste explicit cu
- literalul caracter `NULL` (4 caractere), care ajunge **necotat** in textul SQL generat (concatenare
- directa, fara ghilimele in jur) — deci Oracle il interpreteaza ca si cuvantul-cheie `NULL`, nu ca
- string. Rezultat: `V_ID_POL` ajunge `NULL` in Oracle exact cand `poArt.id_pol` e `.NULL.` in VFP.
- Verificare bazata pe semantica standard VFP (nu am putut rula VFP live — masina partajata, conform
- interdictiei) — consistenta si cu tiparul deja folosit identic pentru alti parametri opționali pe
- acelasi apel (`id_gestiune`, `id_valuta_d`, `id_part_rez` etc., toate cu acelasi `Nvl(Alltrim(Str(...`).
-- **Neverificat** (nici in raportul original, nici aici): cum ajunge efectiv `poArt.id_pol` sa fie
- `.NULL.` pentru un articol fara politica — ramane premisa mostenita din proiectul #13, nu
- re-derivata in aceasta runda.
-
-## A4. Numerele de linie — offset +17 sau identice?
-
-**Verdict: NICIUNA din cele doua afirmatii e o regula generala — depinde de setul de citate comparat.**
-
-- **Pentru citatele proprii ale raportului verificat** (re-testate direct aici): `adauga_articol_factura`
- header `:4989-5015`, ramura `ntip=4` `:5080-5103`, `contabilizeaza_articol` header `:7173`, CASE
- `:7398-7423`, hardcode `:7413-7422`, garda `:7441`, `nTipNotaPlata:=46` la `:84` — **toate identice**,
- zero offset. Raportul are dreptate pentru propriile sale citate.
-- **Dar exista un offset real, doar ca nu e +17 ci +9**, intre citatele mai vechi din
- `nota_contabila_fara_politica.md:100-104` (`ff_...:6150`, `:6867`, `:7149` pentru cele 3 apeluri
- `contabilizeaza_articol`) si pozitiile reale confirmate in aceasta runda pentru **aceleasi** apeluri
- (`6141`, `6858`, `7140`) — diferenta consecventa de **9 linii**, nu 17, si in directia opusa
- (citatul vechi e mai mare, nu mai mic).
-- Concluzia corecta: fisierul `PACK_FACTURARE.sql` a fost re-exportat de mai multe ori pe parcursul
- proiectului (cod adaugat/sters intre versiuni), asa ca **fiecare set de citate vechi are propriul
- offset fata de exportul curent — nu exista o constanta universala (nici 0, nici +17, nici +9)**.
- `handoff_13_formular_unificat.md:190` ("+17") si acest raport ("identic, fara offset") sunt ambele
- adevarate **doar pentru seturile de citate pe care le-au verificat fiecare** — nu se pot generaliza
- una peste alta. Disciplina corecta, pe care ambele rapoarte au respectat-o, e re-verificarea directa
- pe fisierul curent inainte de orice citare — nu presupunerea unui offset fix.
-
-## Text de plan corectat (sectiunea 4 din raportul verificat, rescris)
-
-```
-**Ramura `ntip=4` (facturare din avize, handler real `scrie_factura_avize:6692-7058`, nu
-`scrie_factura_avize_retur` cum apare gresit in rapoartele anterioare) — exclusa structural, nu
-necesita cod suplimentar.** `adauga_articol_factura`, ramura `WHEN ntip=4` (`:5080-5103`), cauta
-randul sursa din `VANZARI_DETALII` prin `A.ID_POL = V_ID_POL`, fara handler de exceptie — cu
-`V_ID_POL=NULL` (exact cazul liniei fara politica), comparatia nu se poate potrivi niciodata, deci
-apelul cade cu `ORA-01403` la adaugarea articolului, in bucla `do_scrie_articole` (`ofacturare.vc2:
-13967-14106`), care ruleaza intotdeauna inaintea `Do Case`-ului (`:14282`) ce ar chema
-`scrie_factura_avize`. Un articol fara politica nu poate fi, structural, adaugat pe un document
-`ntip=4`; ramura noua `cont_venit` nu are nimic de tratat aici.
-
-**Gol confirmat, de acoperit inainte de implementare — mai ingust decat s-a crezut initial**:
-ramurile de aviz care **efectiv** ajung la `contabilizeaza_articol` prin singurul apelant confirmat
-functional (`scrie_factura2`, apelat pentru `Inlist(3,21,25,28,42,47)` si pentru toate celelalte
-tipuri prin `Otherwise`) sunt cele care cad in `ELSE`-ul CASE-ului propriu al `scrie_factura2`:
-`ntip IN (28,29)` -> `SCD='461'`, restul (`21,22,24,27` si alte "otherwise" avize) -> `SCD='418'`
-(`:7413-7422`). **`ntip IN (23,25,30,41,42,47)` NU ajung la `contabilizeaza_articol`** prin acest
-apelant — sunt deviate mai devreme, in `scrie_factura2` insasi, spre `transfera_articol`/
-`descarca_gestiune`, deci golul nu li se aplica (contabilizeaza_articol si ramura ei noua nu se
-executa niciodata pentru ele). `adauga_articol_factura` nu cere `id_pol` pentru niciunul din aceste
-`ntip` (foloseste calea "din comenzi", fara filtru pe `id_pol`, sau calea implicita `ELSE`, fara nicio
-interogare legata de politica) — deci un articol fara politica poate ajunge pe oricare din avizele
-`28,29,21,22,24,27` cu `cont_venit` populat. Designul deja semnalase acest risc printr-o paranteza
-(`canal_cont_venit_fara_politica.md:146`, "ramurile aviz raman 418/461"), dar nu-l implementase: ramura
-noua trebuie sa aleaga `SCD` in functie de `ntip` (pastrand `'461'` pentru `IN(28,29)`, `'418'` pentru
-restul avizelor atinse), nu sa hardcodeze `'4111'` necondiționat.
-
-**Gol confirmat separat**: ramura noua trebuie sa pastreze garda `IF ntip <> nTipNotaPlata` (`ntip=46`,
-`ff_...:7441`) inainte de a apela `scrie_nota` — azi sarita intentionat pentru documentele de tip
-"nota de plata", iar un articol fara politica poate fi adaugat si pe acest tip de document
-(`adauga_articol_factura`, bucket `ELSE`, fara cerinta de `id_pol`).
-
-**Defensiv (opțional)**: se poate adauga o garda explicita `IF cont_venit IS NOT NULL AND ntip = 4
-THEN RAISE_APPLICATION_ERROR(...)`, dar e demonstrat redundanta — cazul e deja imposibil pe caile VFP
-cunoscute, blocat cu doua straturi independente inainte de a ajunge la `contabilizeaza_articol`.
-```
-
-## Ce nu s-a putut stabili in aceasta runda (mostenit din raportul original, nu re-rezolvat)
-
-- Cum ajunge `poArt.id_pol` sa fie `.NULL.` in VFP pentru un articol fara politica pe un aviz —
- premisa proiectului #13, nu re-derivata.
-- Cine cheama `scrie_aviz_retur` (daca cineva) — cautare exhaustiva in `COMUN\` si in tot proiectul,
- zero rezultate; posibil cod mort sau apelat din alt produs al suitei ROA.
-- Comportamentul exact `goExecutor`/`oPrelucrareEroare()` la o exceptie Oracle neprinsa — nu urmarit
- in aceasta runda (mostenit ca gol si in raportul original).
-
-## Handoff
-
-Verificare incheiata, toate cele 4 afirmatii + corectia structurala preliminara sunt in sectiunile de
-mai sus. Zero cod atins, zero write-back, doar `SELECT`/`Read`/`Grep` pe SQL si VFP text. Context
-consumat substantial (citire extinsa pe `ff_...sql` si `ofacturare.vc2`), dar verificarea s-a incheiat
-inainte de pragul de predare.
-
----
-
-## Propagarea `CONT_VENIT` prin cei trei apelanti — verificare
-
-Intrebare noua de la team-lead: argumentul central al proiectarii (`canal_cont_venit_fara_politica.md`,
-sectiunea 1, `:63-69`) — "orice coloana noua pe `VANZARI_DETALII_TEMP` ajunge automat in
-`detalii_articol`, fara sa atingi cei 3 apelanti, pentru ca fac `SELECT * BULK COLLECT` intr-un
-`TABLE OF ...%ROWTYPE`" — se bazeaza pe lista de nume deja corectata mai sus. Verificat acum pe
-numele **reale** ale celor 3 apelanti (`scrie_factura2`, `scrie_factura_avize`, `scrie_aviz_retur`),
-fiecare citit direct, linie cu linie, in aceasta runda.
-
-### 1-2. `scrie_factura2` (`:6020-6223`)
-
-```
-ff_...:6039-6040 TYPE tab_detalii_type IS TABLE OF vanzari_detalii_temp%ROWTYPE;
- tab_detalii tab_detalii_type;
-ff_...:6063 SELECT * BULK COLLECT INTO tab_detalii FROM VANZARI_DETALII_TEMP;
-ff_...:6141 pack_facturare.contabilizeaza_articol(tab_detalii(i));
-```
-**`SELECT *` intr-un `TABLE OF VANZARI_DETALII_TEMP%ROWTYPE`, confirmat.** `CONT_VENIT` curge automat.
-
-### 1-2. `scrie_factura_avize` (`:6692-7058`, handler-ul real `ntip=4`)
-
-```
-ff_...:6708-6709 TYPE tab_detalii_type IS TABLE OF vanzari_detalii_temp%ROWTYPE;
- tab_detalii tab_detalii_type;
-ff_...:6749 SELECT * BULK COLLECT INTO tab_detalii FROM VANZARI_DETALII_TEMP;
-ff_...:6858 pack_facturare.contabilizeaza_articol(tab_detalii(i)); -- doar pt. custodie=1
-```
-**Acelasi tipar: `SELECT *` in `TABLE OF VANZARI_DETALII_TEMP%ROWTYPE`, confirmat.** Intre populare
-(`:6749`) si apelul catre `contabilizeaza_articol` (`:6858`), randul `tab_detalii(i)` e modificat doar
-pe doua campuri (`.cantitate`, `.id_rata`, `:6855-6856`) — `CONT_VENIT` ramane neatins, curge automat.
-Chiar daca numele apelantului real difera de ce credea proiectarea, **concluzia ei ("nu se ating deloc")
-ramane corecta pentru acest apelant**, doar numele era gresit.
-
-### 3. `scrie_aviz_retur` (`:7085-7171`)
-
-```
-ff_...:7097-7098 TYPE tab_detalii_type IS TABLE OF vanzari_detalii_temp%ROWTYPE;
- tab_detalii tab_detalii_type;
-ff_...:7106 SELECT * BULK COLLECT INTO tab_detalii FROM VANZARI_DETALII_TEMP;
-ff_...:7140 pack_facturare.contabilizeaza_articol(tab_detalii(i)); -- doar pt. custodie=0 (ELSE la :7115)
-```
-**Acelasi tipar, confirmat.** Nu conteaza ca nu i-am gasit apelant VFP (ramane nedovedit ca se
-executa vreodata) — *daca* s-ar executa, `CONT_VENIT` ar curge automat si aici, deci nu schimba
-suprafata diff-ului indiferent de raspuns.
-
-### Verdict pe argumentul proiectarii
-
-**Se salveaza.** Toti cei 3 apelanti reali (nu cei numiti gresit in rapoartele anterioare) folosesc
-identic `SELECT * BULK COLLECT INTO
FROM VANZARI_DETALII_TEMP`
-— zero lista explicita de coloane, zero `%ROWTYPE` pe alta tabela, zero constructie camp-cu-camp.
-Concluzia proiectarii ("adaugi coloana pe `VANZARI_DETALII_TEMP`, `contabilizeaza_articol` o vede
-automat prin toti apelantii, fara sa atingi `scrie_factura2`/`scrie_factura_avize`/`scrie_aviz_retur`")
-**e corecta ca mecanism**, chiar daca doua din cele trei nume citate pentru ea erau gresite. Corectia
-de nume nu schimba nimic la suprafata de regresie a schemei — schimba doar la ce trebuie sa te uiti
-daca vreodata unul dintre cei trei apelanti isi schimba modul de populare a lui `tab_detalii`.
diff --git a/docs/cercetare/verif_proforma_alegere_stoc.md b/docs/cercetare/verif_proforma_alegere_stoc.md
deleted file mode 100644
index c4baeb0..0000000
--- a/docs/cercetare/verif_proforma_alegere_stoc.md
+++ /dev/null
@@ -1,366 +0,0 @@
-# Verificare — alegerea stocului pe proforma (runda de verificare)
-
-Investigatie read-only, 10.08.2026. Raspunde la 4 intrebari punctuale cerute de team-lead, pentru
-decizia de proiectare S5b (comutare FACTURA <-> PROFORMA cu linii deja adaugate).
-
-Continua fara sa reia: `s5b_proforma_descarcare_gestiune.md` (mecanismul `gestionabil=0` /
-`id_gestiune=-1000`) si `s5b_proiectare_proforma_copiere.md` (proiectarea de runda 12, care a
-descoperit deja ca `scrie_proforma` nu cheama `contabilizeaza_articol` deloc).
-
-Nicio modificare de cod, niciun `git_sync.ps1`/`txt2vcx.ps1`, niciun commit, nicio scriere Oracle
-(numai `SELECT`/`Read`/`Grep` pe fisiere de pe disc). Sursa Oracle folosita:
-`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (citat mai jos
-`PACK:linie`).
-
-**Status: COMPLET.**
-
----
-
-## Rezumat executiv
-
-1. **Da, pe calea principala si pe toate celelalte surse (cu exceptia copierii), stocul NU se
- alege la adaugarea unei linii pe proforma azi** — pentru ca `gestionabil` a fost deja fortat pe
- `0` in VFP, in masa, **inainte** ca gridul de linii sa se deschida. Cand ruleaza `Do Case`-ul de
- la `ofacturare.vc2:13803`, `poArticol.gestionabil` e deja `0`, nu valoarea reala din nomenclator.
-2. **Marcarea negestionabila are un singur mecanism activ azi, exclusiv in VFP**:
- `UPDATE (m.lcCursor) SET gestionabil = 0` (`ofacturare.prg:333-336`), rulat in interiorul
- functiei `factureaza()`, imediat dupa incarcarea cursorului candidat (`crsarticole`) si
- **inainte** de construirea `crsfactura` (`creeaza_facturacrs`, linia 338) — adica la
- **deschiderea documentului / incarcarea liniilor candidate**, nu la Termina/salvare. **Exista si
- un al doilea mecanism, in Oracle**, in `cursor_retur_document` (`PACK:3993-4000`,
- `CASE WHEN V_PROFORMA=1 THEN 0 ...`), dar acesta e **mort in fluxul curent**: `cursor_retur_document`
- se cheama dintr-un singur loc (`ofacturare.prg:268`, ramura de copiere), cu
- `V_PROFORMA = poDate.eProforma` **al documentului nou**, care e **intotdeauna 0** dupa copiere
- (`nIdTipDoc` nu se propaga de la sursa, `ofacturare_comun.prg:370`) — deci ramura `V_PROFORMA=1`
- nu se activeaza niciodata azi. **Nu e o contradictie intre cele doua rapoarte anterioare — sunt
- doua mecanisme reale in cod, dar doar unul (cel VFP) e activ pe traseul de creare a unei
- proforme; cel Oracle exista doar pentru copiere si acolo nu se declanseaza cu valoarea curenta a
- parametrului.**
-3. **`pret_achizitie` depinde de sursa**: pe calea principala (`cursor_preturi`, lista de preturi)
- NU se completeaza deloc din cursor (coloana nici nu exista in `SELECT`-ul lui `cursor_preturi`)
- — ramane `0`, prin acelasi tipar de valoare implicita ca la `id_gestiune` (`do_initializeaza_articol`).
- Pe sursele care incarca dintr-un document existent (`cursor_avize`, `cursor_retur_document` —
- avize si copiere), `PRET_ACHIZITIE` **e** selectat direct din `VANZARI_DETALII`, deci ajunge real.
-4. **Daca proforma ar pastra `id_gestiune` real pana la salvare, nimic din contabilizare/stoc nu
- s-ar strica** — pentru ca blocajul real nu e sentinela `-1000`, ci faptul ca `scrie_proforma`
- (calea Oracle aleasa la Termina cand `eProforma=1`) **nu cheama niciodata**
- `contabilizeaza_articol`/`descarca_gestiune` (confirmat deja in raportul-sursa de runda 12).
- `adauga_articol_factura` (care ar primi `V_ID_GESTIUNE` real) **se cheama oricum**, neconditionat
- de `eProforma`, pentru orice linie — deci un `id_gestiune` real ar ajunge fara probleme in
- `VANZARI_DETALII_TEMP`/`VANZARI_DETALII`, fara sa declanseze nimic in plus. **`do_alege_stoc` nu
- rezerva stoc real** — face doar un `SELECT` (cursoare `cursor_gestiuni_articol*`) si scade local,
- in memorie, cantitatile deja puse pe documentul curent (`crsfactura`), ca operatorul sa nu aleaga
- de doua ori acelasi lot; nu scrie nimic in Oracle. Deci lasarea lui `do_alege_stoc` sa ruleze pe
- proforma nu ar bloca stoc pentru nimeni. Singurul risc real gasit e cel deja semnalat in
- `s5b_proiectare_proforma_copiere.md` §5 (drumul invers, proforma -> factura in aceeasi sesiune),
- care ramane valabil indiferent de aceasta decizie.
-
----
-
-## Intrebarea 1 — se alege stocul la adaugarea unui articol pe proforma azi?
-
-**Raspuns: NU, pe niciuna dintre caile de creare directa a unei proforme** (nu prin copiere).
-
-### Calea principala — `cursor_preturi`
-
-`cursor_preturi` (`PACK:2138-2646`) e apelat pentru `tnTip` in `{45, 1, 22, 5, 29, 7, 10, 23}`
-(`ofacturare.prg:275-282` — lista de preturi, inclusiv `restaurant`), adica cea mai comuna sursa
-pentru o proforma noua. SELECT-ul lui `cursor_preturi` intoarce `GESTIONABIL` ca
-`C.IN_STOC AS GESTIONABIL` (`PACK:2192`, `:2297` — valoarea reala din `NOM_ARTICOLE`, fara nicio
-constienta de proforma; `cursor_preturi` **nu are parametru** `V_PROFORMA`, confirmat prin grep pe
-tot fisierul: `V_PROFORMA` apare doar la declaratia si corpul lui `cursor_retur_document`,
-`PACK:408, 3939, 3944, 3952, 3957, 3994`).
-
-Insa, imediat dupa ce acest cursor e adus in `crsarticole` in VFP, **inainte** ca operatorul sa
-apuce sa vada gridul de linii:
-
-```
-COMUN\programe\ofacturare.prg:330-336
-* Daca este o proforma, consider toate articolele negestionabile, pentru a nu mai alege din stoc
-* 12.03.2021
-IF poDate.eProforma = 1
- UPDATE (m.lcCursor) SET gestionabil = 0
- GO TOP IN (m.lcCursor)
-ENDIF
-```
-
-`m.lcCursor` = `crsarticole` (setat la `:310`). Acest bloc ruleaza **dupa** `Do Case`-ul de
-incarcare (`:266-308`) si **inainte** de `creeaza_facturacrs([crsfactura])` (`:338`) — adica la
-compunerea listei de articole candidate, nu la salvare. Cand operatorul adauga o linie mai tarziu,
-`Do Case`-ul care alege dialogul (`ofacturare.vc2:13803-13809`) citeste `poArticol.gestionabil`,
-care e deja `0` pentru **toate** liniile candidate (setat in masa mai sus), deci intra pe ramura
-`frm_articol_factura`, **niciodata** pe `Thisform.do_alege_stoc`.
-
-### Celelalte cursoare (fara copiere)
-
-Verificat direct in `PACK_FACTURARE`, niciunul din urmatoarele cursoare, folosite pentru celelalte
-surse ale unei proforme noi, nu are parametru `V_PROFORMA` si nici nu calculeaza `GESTIONABIL` in
-functie de proforma — toate intorc valoarea reala din nomenclator/contract:
-
-| Cursor | Apelat pentru (`tnTip`) | `GESTIONABIL` in SELECT | Linie |
-|---|---|---|---|
-| `cursor_preturi` | 45,1,22,5,29,7,10,23 | `C.IN_STOC` | `PACK:2192,2297` |
-| `cursor_contract` | 2,26,6,52 | `A.GESTIONABIL` (coloana reala) | `PACK:2411,2487,2572` |
-| `cursor_comanda` | 3,21,25,28,42,47 | `E.IN_STOC` | `PACK:2789` |
-| `cursor_lucrare` | 27 | `C.IN_STOC` | `PACK:3029` |
-| `cursor_articole_k` | 48,49 | `C.IN_STOC` | `PACK:3117` |
-| `cursor_avize` | 4 | `C.IN_STOC` | `PACK:3634` |
-| `cursor_aviz_nir` | 30 | `0` (hardcodat) | `PACK:3745` |
-| `cursor_gestiune` | 41 | `A.GESTIONABIL` | `PACK:4104` |
-| `cursor_retur` | 8,9,24 | (nu are coloana `GESTIONABIL` separata — vezi nota) | `PACK:3934-3948` |
-
-Pentru **toate** aceste surse, aceeasi bucla `ofacturare.prg:330-336` e singurul loc care forteaza
-`gestionabil=0` cand `poDate.eProforma=1` — mecanismul e identic indiferent de sursa, pentru ca
-`UPDATE (m.lcCursor) SET gestionabil = 0` ruleaza pe `crsarticole` dupa orice ramura a `Do Case`-ului
-de la `:266-308`, nu doar pe ramura lista-de-preturi.
-
-### Ramura de copiere — singura cu parametru `V_PROFORMA` in Oracle
-
-`Case m.llCopiere` (`ofacturare.prg:267-268`) e **singura** ramura care apeleaza
-`cursor_retur_document`, singurul cursor cu parametru `V_PROFORMA`. Insa la copiere, documentul nou
-pleaca intotdeauna cu `eProforma=0` (`nIdTipDoc` explicit necopiat, `ofacturare_comun.prg:370` —
-deja stabilit in `s5b_proiectare_proforma_copiere.md` §2.3), deci `V_PROFORMA` trimis e `0`, iar
-ramura `GESTIONABIL = B.IN_STOC` (valoarea reala) se activeaza, nu `WHEN V_PROFORMA=1 THEN 0`. Asta
-e comportamentul **corect si dorit** la copiere (liniile redevin gestionabile) — dar confirma ca
-`V_PROFORMA=1` nu apare niciodata cu valoarea `1` in vreun apel real azi (vezi Intrebarea 2).
-
-**Concluzie Intrebarea 1**: pe orice cale de creare directa a unei proforme (nu copiere), la
-momentul `Do Case`-ului de adaugare a liniei (`ofacturare.vc2:13803`), `poArticol.gestionabil` e
-deja `0` — fortat de VFP la incarcare, nu valoarea reala din nomenclator. `do_alege_stoc` nu ruleaza
-niciodata pentru o linie noua adaugata sub `eProforma=1`, indiferent de sursa.
-
----
-
-## Intrebarea 2 — unde exact se face marcarea negestionabila si CAND?
-
-**Doua locuri in cod, dar un singur loc activ azi:**
-
-### 2.1 VFP — activ, la incarcarea documentului (nu la salvare)
-
-`COMUN\programe\ofacturare.prg:333-336`, in interiorul procedurii `factureaza()`. Secventa completa
-in `factureaza()`:
-
-1. `:266-308` — `Do Case` pe `tnTip`/`llCopiere`, alege cursorul Oracle si il aduce in `crsarticole`.
-2. `:311` — `goExecutor.oExecute(lcSqlCursor, lcCursor)` — executa efectiv apelul Oracle.
-3. `:324-336` — daca sunt randuri, **si daca `poDate.eProforma = 1`**: `UPDATE crsarticole SET gestionabil = 0`.
-4. `:338` — abia acum `creeaza_facturacrs([crsfactura])` construieste cursorul gol de linii ale
- documentului; liniile candidate (`crsarticole`, deja marcate) raman disponibile pentru ca
- operatorul sa aleaga din ele.
-
-Acest pas ruleaza **la deschiderea ecranului de adaugare articole**, mult inainte de `Termina`
-(`do_scrie_factura`, apelat doar la click pe butonul de finalizare — vezi 2.3 mai jos). Nu exista
-niciun `UPDATE`/`REPLACE gestionabil With 0` la salvare in `do_scrie_factura` sau `do_scrie_articole`
-— am cautat explicit `gestionabil` in ambele metode (`ofacturare.vc2:14197-14380`,`:13967-14150`) si
-singura referinta la `gestionabil` in acea zona e citirea lui la `Do Case`-ul din `:13803` (decizia
-de dialog), nu o scriere.
-
-### 2.2 Oracle — exista in cod, dar mort in fluxul curent
-
-`cursor_retur_document` (`PACK:3949-4064`), branch la `PACK:3993-4000`:
-```sql
-(case
- when V_PROFORMA = 1 then 0
- when V_COPIERE = 1 then B.IN_STOC
- else A.GESTIONABIL
- end) AS GESTIONABIL,
-```
-cu comentariu explicit in cod: `-- V_PROFORMA: Daca este proforma (1), fac articolele negestionabile
-sa pot alege orice cantitate` (`PACK:3957`). Acest cod **exista si e corect scris**, dar
-`cursor_retur_document` are un singur punct de apel in tot codul VFP (confirmat prin cautare in
-`ofacturare.prg`, singura potrivire e la `:268`; potrivirile suplimentare gasite in
-`COMUN\.svn\pristine\*` sunt copii istorice ale **aceleiasi** linii, nu apeluri suplimentare), si
-acolo `V_PROFORMA` trimis e `poDate.eProforma` **al documentului nou** din copiere, care e
-intotdeauna `0` (Intrebarea 1). **Deci acest branch Oracle nu se activeaza niciodata cu valoarea 1
-in fluxul curent** — e cod mort din perspectiva efectului observabil, desi sintactic corect si
-prezent.
-
-### 2.3 Clarificare pe "inainte de compunerea documentului" vs. "la salvare"
-
-Formularea raportului de runda 9 ("VFP marcheaza toate liniile proformei negestionabile inainte de
-compunerea documentului") e **corecta** — "compunerea documentului" inseamna acolo constructia
-listei de articole candidate/`crsfactura` (pasul 4 de mai sus), care se intampla la
-**deschiderea** ecranului de facturare, nu la apasarea `Termina`. Nu exista o contradictie reala cu
-mentiunea `V_PROFORMA` din `cursor_retur_document` din brief — acel `CASE` Oracle e un mecanism
-separat, pentru un cursor diferit (candidati la copiere), care azi nu se declanseaza niciodata cu
-`V_PROFORMA=1`. Ambele afirmatii din surse sunt adevarate simultan, pentru ca descriu lucruri
-diferite.
-
-**Concluzie Intrebarea 2**: singurul mecanism activ e `UPDATE` de masa in VFP
-(`ofacturare.prg:333-336`), care ruleaza in `factureaza()`, la incarcarea/compunerea listei de
-articole candidate — **cu mult inainte** de `Termina`/`do_scrie_factura`. Mecanismul Oracle din
-`cursor_retur_document` exista in cod dar nu se activeaza cu valoarea curenta a parametrilor.
-
----
-
-## Intrebarea 3 — se completeaza `pret_achizitie` pe liniile de proforma?
-
-**Depinde strict de sursa cursorului, la fel ca la `gestionabil` — dar cu rezultat opus pentru
-calea principala.**
-
-### Ce cursoare selecteaza `PRET_ACHIZITIE`
-
-Cautare directa in `PACK_FACTURARE` (`grep PRET_ACHIZITIE`): coloana **nu apare deloc** in
-`cursor_preturi` (`PACK:2138-2646`), `cursor_contract` (`:2646-2952`), `cursor_comanda`
-(`:2952-3173`), `cursor_lucrare` (`:3173-3595`), `cursor_articole_k` (`:3595-3703`),
-`cursor_gestiune` (`:4158-4349`). Apare doar in:
-- `cursor_avize` (in jurul liniilor `PACK:3754-3864` — sursa `VANZARI_DETALII`/`RUL`, articol
- provenit dintr-un aviz existent);
-- `cursor_retur_document` (`PACK:4026`, `A.PRET_ACHIZITIE` direct din `VANZARI_DETALII`, folosit la
- copiere).
-
-### Ce se intampla in VFP cand lipseste
-
-`crsfactura` (structura din `creeaza_facturacrs`, `ofacturare_comun.prg:1777`) are un camp
-`pret_achizitie` in schema — dar o linie noua nu se construieste prin copiere in masa din
-`crsarticole`, ci prin `Scatter`/`Gather` pe obiectul `poArticol`, populat cand utilizatorul alege un
-articol din grid. `do_initializeaza_articol` (`ofacturare.vc2:13715-13719`), apelat pentru orice
-linie care trece prin `frm_articol_factura` (ramura negestionabila, deci si orice linie de
-proforma):
-```
-If Type('toArticol.pret_achizitie')="U"
- AddProperty(toArticol,'pret_achizitie',0)
-Endif
-If Isnull(toArticol.pret_achizitie)
- toArticol.pret_achizitie = 0
-Endif
-```
-Deci: **pe calea principala (lista de preturi), `pret_achizitie` ramane `0`** pe liniile de proforma
-— campul nici nu exista in `crsarticole` sursa (cursorul Oracle nu-l selecteaza), asa ca proprietatea
-lipseste pe `poArticol` si `do_initializeaza_articol` o creeaza cu valoare implicita `0`, exact
-acelasi tipar defensiv folosit pentru `id_gestiune=-1000` (aceeasi metoda, linii apropiate,
-`:13618-13623` vs `:13715-13719`).
-
-**Pe sursele care carata un document existent** (`cursor_avize`, si `cursor_retur_document` la
-copiere), `pret_achizitie` **e** populat real din `VANZARI_DETALII.PRET_ACHIZITIE` a documentului
-sursa, deci proprietatea exista pe `poArticol` si `do_initializeaza_articol` nu o suprascrie.
-
-### Unde ajunge
-
-Indiferent de valoare (`0` sau reala), `poArt.pret_achizitie` merge neschimbat catre Oracle ca
-parametru pozitional in apelul catre `adauga_articol_factura`:
-```
-ofacturare.vc2:14073
-... + Alltrim(Str(poArt.pret_achizitie,18,gnPPret)) + [,] + ...
-```
-primit ca `V_PRET_ACHIZITIE_TEMP` (`PACK:4995`), copiat direct `V_PRET_ACHIZITIE := V_PRET_ACHIZITIE_TEMP`
-(`PACK:5031`, fara sentinela, spre deosebire de `id_gestiune`) si scris ca atare in
-`VANZARI_DETALII_TEMP.PRET_ACHIZITIE` (`PACK:5229/5259`), apoi in `VANZARI_DETALII` la
-`scrie_in_vanzari`.
-
-**Concluzie Intrebarea 3**: pe calea principala (lista de preturi), `pret_achizitie` ramane `0` pe
-liniile de proforma — nu vine din `do_alege_stoc` (care nu ruleaza) si nici din cursorul Oracle (care
-nu-l selecteaza pe aceasta ramura). Pe sursele avize/copiere, valoarea reala din documentul sursa se
-pastreaza.
-
----
-
-## Intrebarea 4 — ce s-ar strica daca proforma ar pastra gestiunea reala pana la salvare?
-
-### 4a. `adauga_articol_factura` se cheama si pentru liniile de proforma?
-
-**Da, neconditionat.** `do_scrie_factura` (`ofacturare.vc2:14197+`) cheama
-`Thisform.do_scrie_articole()` la linia **14264**, **inainte** de `Do Case poDate.eProforma = 1`
-(care alege intre `scrie_proforma` si `scrie_factura2`, la `:14282`):
-```
-ofacturare.vc2:14264
-llReturn = Thisform.do_scrie_articole() && se deschide tranzactie manuala
-...
-ofacturare.vc2:14282
-Do Case
- Case poDate.eProforma = 1
- * scrie_proforma are aceiasi parametri ca scrie_factura2
- * salveaza doar in vanzari, nu si in contabilitate
- lcSql = [{call pack_facturare.scrie_proforma(...)}]
-```
-`do_scrie_articole` parcurge liniile din `crsfactura` si cheama `adauga_articol_factura` pentru
-fiecare (`ofacturare.vc2:14069-14073`, deja citat in raportul-sursa) — **acelasi cod, indiferent de
-`eProforma`**. Daca `poArt.id_gestiune` ar fi real (nu `-1000`), `adauga_articol_factura` l-ar
-traduce direct in `V_ID_GESTIUNE2 := V_ID_GESTIUNE` (`PACK:5032-5034`, gate-ul `<> -1000`) si l-ar
-scrie ca atare in `VANZARI_DETALII_TEMP.ID_GESTIUNE` (`PACK:5237,5267`), apoi in
-`VANZARI_DETALII.ID_GESTIUNE` la `scrie_in_vanzari` (`INSERT INTO VANZARI_DETALII SELECT FROM
-VANZARI_DETALII_TEMP`, fara nicio conditie suplimentara pe `id_gestiune`).
-
-### 4b. Are efect ca linia sa ramana cu `ID_GESTIUNE` completat, cata vreme `scrie_proforma` nu cheama `contabilizeaza_articol`?
-
-**Niciunul, pe partea de contabilizare/descarcare.** Confirmat deja (runda 12,
-`s5b_proiectare_proforma_copiere.md`, sectiunea "Descoperire centrala"): `scrie_proforma`
-(`PACK:5637-5671`) cheama **doar** `scrie_in_vanzari` — insereaza antetul si liniile ca atare, apoi
-seteaza `VANZARI.EPROFORMA=1`. **Nu cheama** `contabilizeaza_articol` in niciun caz. Sentinela
-`-1000` conteaza doar **in interiorul** lui `contabilizeaza_articol` (`PACK:7472-7476`), care nu
-ruleaza deloc pentru `scrie_proforma`. Deci `ID_GESTIUNE` real pe o linie de proforma nu ar declansa
-`descarca_gestiune`, nu ar genera `NOTE_CONTABILE`, nu ar atinge `RUL`/`STOC` — pentru ca intreaga
-functie care ar face asta nu se executa pe traseul `scrie_proforma`.
-
-### 4c. Rapoarte/view-uri care citesc `ID_GESTIUNE` pe documente `eProforma=1` si ar arata altceva?
-
-Cautare `eproforma` (case-insensitive) in tot `PACK_FACTURARE`: doar 3 potriviri, toate in
-`scrie_proforma`/comentarii (`PACK:1408, 5666, 5668`) — nicio alta procedura/vedere din pachet nu
-filtreaza sau calculeaza dupa `EPROFORMA`.
-
-Pe partea VFP, `crsDetaliiListare` (folosit la **relistarea** unui document deja emis, inclusiv
-proforma — `oproceduri_facturare.prg:1111-1126`, sursa `fact_vfacturi2`) **include** coloana
-`id_gestiune` in schema si in `SELECT`, indiferent de `eproforma` (nu exista filtru pe
-`eproforma` in acest `SELECT`). Deci daca `ID_GESTIUNE` ar fi real pe o proforma, acest cursor l-ar
-citi ca atare la relistare — azi citeste `NULL`. **Nu am putut confirma daca vreun raport `.frx`
-tiparit efectiv afiseaza `id_gestiune`/`nume_gestiune` pe documentul proforma insusi**
-(rapoartele `PROFORMA`/`PROFORMA_VAL` nu au versiune text `.fr2` generata in `Rapoarte\`, deci nu
-s-au putut grep-ui direct) — de regula gestiunea e un camp intern, nu unul tiparit pe un document
-comercial, dar afirmatia ramane neconfirmata pe cod, nu doar presupusa corecta. Vezi "Ce nu s-a
-putut stabili".
-
-### 4d. `do_alege_stoc` rezerva stoc sau doar alege?
-
-**Doar alege — nu scrie nimic in Oracle.** Corpul complet al `do_alege_stoc`
-(`ofacturare.vc2:13200-13400+`) face exclusiv: (1) un `SELECT` prin
-`cursor_gestiuni_articol`/`cursor_gestiuni_articol_retur`/`cursor_gestiuni_articol_stoc0` (toate
-proceduri read-only, populeaza un cursor local `crsgestarticoltemp`), (2) o scadere **locala, in
-memorie**, a cantitatilor deja adaugate pe **acelasi document, in aceeasi sesiune**
-(`ofacturare.vc2:13273-13311`: `SELECT ... FROM crsfactura ... INTO CURSOR crsFacturaArticoleTemp`,
-apoi `a.cantitate - Nvl(b.cantitate,0)` la afisare), ca sa nu i se ofere operatorului sa aleaga de
-doua ori acelasi lot pe acelasi document. **Nu exista niciun `INSERT`/`UPDATE` catre Oracle in
-aceasta metoda** — `goExecutor.oExecute` apare o singura data, pentru `SELECT`-ul de la pasul (1).
-Blocarea/decrementarea reala a stocului se intampla abia la `descarca_gestiune`
-(`PACK:7648-7797`), apelata doar din `contabilizeaza_articol`, care (per 4b) nu ruleaza niciodata
-pentru `scrie_proforma`. **Deci chiar daca `do_alege_stoc` ar rula pe liniile unei proforme, nu ar
-"tine" stoc blocat pentru nimeni** — nu exista mecanism de rezervare reala in aplicatie pe acest
-traseu, doar o verificare locala de neduplicare in sesiunea curenta.
-
-**Concluzie Intrebarea 4**: nimic din contabilizare, descarcare de gestiune sau stoc real nu s-ar
-strica daca proforma ar pastra `id_gestiune` real pana la salvare — blocajul functional e la nivelul
-routing-ului `scrie_proforma` (care nu cheama `contabilizeaza_articol`), nu la nivelul sentinelei
-`-1000`. Singurul loc unde s-ar vedea o diferenta reala e la **relistarea** documentului
-(`crsDetaliiListare`/`fact_vfacturi2`), unde `id_gestiune` ar aparea completat in loc de `NULL` —
-efect cosmetic/informational, nu unul care sa afecteze stocul sau contabilitatea, cu rezerva ca nu
-s-a confirmat daca vreun `.frx` chiar il tipareste. Riscul real ramas e cel deja identificat in
-`s5b_proiectare_proforma_copiere.md` §5 (drumul invers, proforma comutata inapoi in factura in
-aceeasi sesiune, inainte de Termina) — acela nu se schimba, indiferent de aceasta decizie, pentru ca
-depinde de routing-ul de la Termina, nu de momentul in care se alege gestiunea.
-
----
-
-## Ce nu s-a putut stabili
-
-1. **Daca vreun raport `.frx` tiparit (PROFORMA/PROFORMA_VAL) afiseaza efectiv `id_gestiune` sau
- `nume_gestiune` pe documentul insusi** — rapoartele nu au versiune text `.fr2` generata in
- `Rapoarte\`, asa ca nu s-a putut grep pe continutul lor; ar necesita fie generarea textului cu
- `git_sync.ps1`/`foxbin2prg` (in afara mandatului read-only), fie deschidere in IDE VFP.
-2. **Nu s-a rulat nimic pe date vii** — toata analiza e trasare de cod static (VFP text + PL/SQL
- text), conform mandatului read-only.
-3. **Cautarea "eproforma" in Oracle** a acoperit doar `PACK_FACTURARE` — nu s-au verificat alte
- pachete/view-uri/rapoarte Oracle care ar putea referi `VANZARI.EPROFORMA` impreuna cu
- `ID_GESTIUNE` (de exemplu rapoarte de gestiune/stoc din alte module ROA). Zero rezultate in
- `PACK_FACTURARE` nu e dovada de completitudine pentru intreaga schema.
-4. **`cursor_retur`** (`PACK:3934-3948`, folosit pentru `tnTip` 8,9,24 — retururi) nu a fost citit
- integral pentru coloana `GESTIONABIL` (tabelul de la Intrebarea 1 il listeaza fara valoare
- confirmata) — nu are parametru `V_PROFORMA` (confirmat prin grep), deci concluzia generala
- (marcarea vine doar din VFP) ramane valabila, dar valoarea exacta intoarsa de coloana nu a fost
- verificata linie-cu-linie.
-
----
-
-## Handoff
-
-Cercetare incheiata intr-o singura sesiune, fara sa fie nevoie de predare de context. Toate cele 4
-intrebari din brief au raspuns cu dovada `fisier:linie`, plus rezumatul executiv de mai sus. Niciun
-fisier de cod atins, niciun `git_sync.ps1`/`txt2vcx.ps1` rulat, niciun commit, nicio scriere pe
-Oracle.
diff --git a/docs/cercetare/zi_curs_validare.md b/docs/cercetare/zi_curs_validare.md
deleted file mode 100644
index 16ccca6..0000000
--- a/docs/cercetare/zi_curs_validare.md
+++ /dev/null
@@ -1,262 +0,0 @@
-# Cercetare: validarea zi_curs la ofacturare.vc2:8076 si impactul asupra S4d
-
-## Verdict (5-10 randuri)
-
-Ascunderea selectorului de zi curs NU va lasa un document fara curs si NU va cadea la salvare,
-CU CONDITIA sa se respecte precedentul deja existent in cod: `poDate.zi_curs` primeste un implicit
-necondiionat (data documentului) chiar in `oDateFactura.Init`/`Reset`
-(`COMUN\programe\ofacturare_comun.prg:247` si `:496`), INAINTE ca formularul sa decida ce ascunde.
-Nicaieri codul nu goleste `poDate.zi_curs` cand controlul e ascuns/eliminat. Riscul real de eroare
-Oracle (-20005, "Nu este setat cursul...") vine NU din camp gol, ci din faptul ca verificarea
-`pack_facturare.verifica_cursuri_valute` (in `cursor_preturi`) ruleaza NECONDITIONAT de `in_valuta`
-al documentului curent si exclude doar moneda nationala - deci un `zi_curs` implicit (azi) care nu
-are curs setat in tabela CURS pentru o valuta folosita in listele de preturi ale utilizatorului
-poate pica oricum, INDIFERENT daca selectorul e vizibil sau nu. Linia :8076 NU apartine formularului
-de factura, ci unui formular separat, restrans, pentru AVIZ PE LUCRARE / AVIZ PE NIR
-(`frm_date_aviz_lucrare`, tipuri 27 si 30) - fara control de valuta pe el - si valideaza `zi_curs`
-strict pentru ca tipul 27 are nevoie de curs pentru articolele din comanda (posibil in valuta),
-INDEPENDENT de `poDate.in_valuta`. Precedentul cerut la punctul 6 exista deja, dar in alt formular:
-`frm_date_factura`, tipurile 8/9 (retur), unde `clb_zi_curs` e eliminat NECONDITIONAT si documentul
-se salveaza corect - motivul principal e ca SQL-ul pentru retur (`cursor_retur`) nici nu foloseste
-`poDate.zi_curs`.
-
-## 1. Ce valideaza linia :8076
-
-Index de simboluri: `frm_date_aviz_lucrare.inainte_de_do_termin` = `ofacturare.vc2:8054-8119`
-(fisier real: `COMUN\clase\ofacturare.vc2`).
-
-Blocul complet (validare secventiala pe formular, fiecare `Case` opreste salvarea la primul fail):
-
-```
-COMUN\clase\ofacturare.vc2:8063-8079
-Do Case
-Case Empty(poDate.dataireg)
- amessagebox("Nu ati completat data inregistrarii!",48,"Atentie")
- ...
-Case Empty(poDate.dataact)
- amessagebox("Nu ati completat data documentului!",48,"Atentie")
- ...
-Case Empty(Nvl(poDate.id_fdoc,0))
- amessagebox("Nu ati ales felul documentului!",48,"Atentie")
- ...
-Case Empty(Nvl(poDate.zi_curs,{}))
- amessagebox("Nu ati completat ziua cursului valutar!",48,"Atentie")
- This.clb_zi_curs.SetFocus()
- plReturn = .F.
-Case Empty(poDate.nract)
- ...
-```
-
-Valideaza STRICT prezenta unei date in `poDate.zi_curs` (`Empty(Nvl(...,{}))`), nu existenta unui
-curs in baza pentru acea data - acel test se face abia in Oracle, la momentul in care se cere
-cursorul de articole (vezi punctul 4).
-
-## 2. Cand ruleaza si pe ce tipuri de document
-
-`inainte_de_do_termin` e apelat la evenimentul butonului "Termina" al formularului (`BUT_TERMIN1`,
-vezi lista de obiecte a clasei, `ofacturare.vc2:7674-7679`) - deci la incercarea de a incheia
-completarea datelor de antet, inainte de a trece la ecranul de articole.
-
-`frm_date_aviz_lucrare` NU e formularul de factura. E instantiat DOAR pentru doua tipuri de
-document, ambele AVIZ (nu FACTURA):
-
-```
-COMUN\programe\ofacturare.prg:187-226 (identic in factureaza2, :697-699)
-Do Case
- Case tnTip = 27
- poDate.nIdTipDoc = 6 && AVIZ
- Case tnTip = 30
- poDate.nIdTipDoc = 6 && AVIZ
- Case tnTip < 21 Or Inlist(tnTip, 45, 48, 49, 51, 52)
- poDate.nIdTipDoc = 5 && FACTURA
- ...
-Do Case
- Case tnTip = 27
- lcObiect = [frm_date_aviz_lucrare]
- Case tnTip = 30
- lcObiect = [frm_date_aviz_lucrare]
- Case tnTip < 21 Or Inlist(tnTip, 45, 48, 49, 51, 52)
- lcObiect = [frm_date_factura]
- Otherwise
- lcObiect = [frm_date_aviz]
-Endcase
-```
-
-Titlul formularului confirma: `Lb_titlu_alb_b121.Caption = "AVIZ PE BAZ DE LUCRARE"`
-(`ofacturare.vc2:7670`), schimbat in `Init` la "AVIZ PE BAZ DE NIR" cand `nid_tip = 30`
-(`ofacturare.vc2:8154-8161`).
-
-Nu exista o garda mai sus in lant care sa dezactiveze validarea :8076 pe vreun tip - ruleaza
-identic pentru tip 27 si tip 30, necondiionat de `poDate.in_valuta`. IMPORTANT: aceasta clasa
-NU are deloc control de valuta pe formular - lista de obiecte a clasei (`ofacturare.vc2:7623-7637`)
-nu contine niciun `ct_clb_valuta`. Deci validarea de aici nu e legata de "documentul e in valuta",
-ci de nevoia formularului AVIZ-LUCRARE de a avea o zi de curs pentru articolele comenzii care pot
-fi preturite in valuta (vezi punctul 4, `cursor_lucrare`).
-
-Concluzie: linia :8076 NU intra deloc in fluxul de facturare (FACTURA) vizat de decizia 15 - e un
-formular separat, pentru un subset ingust de avize (27 = aviz pe lucrare, 30 = aviz pe NIR).
-
-## 3. Ce se intampla daca zi_curs e gol la :8076
-
-Mesaj de eroare blocant (nu doar avertisment): `amessagebox("Nu ati completat ziua cursului
-valutar!",48,"Atentie")`, apoi `This.clb_zi_curs.SetFocus()` si `plReturn = .F.` - `Case`-ul
-opreste executia `Do Case` (Otherwise nu se mai atinge), iar `inainte_de_do_termin` returneaza
-`.F.`, ceea ce (conform conventiei din restul clasei) blocheaza inchiderea formularului / trecerea
-la pasul urmator.
-
-## 4. Cine mai citeste poDate.zi_curs
-
-Cautare `zi_curs` in `.vc2`/`.prg`/`.sc2` si in sursele Oracle
-(`docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`):
-
-**a) Validari de formular (camp obligatoriu):**
-- `frm_date_aviz_lucrare.inainte_de_do_termin` :8076 - necondiionat (vezi punctele 1-2).
-- `frm_date_factura.inainte_de_do_termin`, `ofacturare.vc2:9484`:
- ```
- Case poDate.in_valuta = 1 And Empty(Nvl(poDate.zi_curs,{})) And Type('thisform.clb_zi_curs.visible')<>'U'
- ```
- Aici validarea E DEJA dublu conditionata: pe `in_valuta = 1` SI pe existenta controlului
- (`Type(...)<>'U'` - devine 'U' daca controlul a fost eliminat cu `RemoveObject`). Deci pe factura
- in lei, sau pe orice tip unde controlul a fost eliminat, validarea nu ruleaza deloc. Comentariul
- `*!* modificare v 2.0.56` de langa arata ca exact acest lucru a fost REZOLVAT anterior pentru
- formularul de factura.
-
-**b) Populare implicita / sincronizare (fara conditie de in_valuta):**
-- `oDateFactura.Init`, `COMUN\programe\ofacturare_comun.prg:247`: `.zi_curs = ldData` -
- necondiionat, seteaza mereu data documentului curent (ldData = azi, ajustat la luna/anul
- curent de facturare) INAINTE de blocul care seteaza `.in_valuta` (linia 248-250).
-- `oDateFactura.Reset`, `ofacturare_comun.prg:496`: `.zi_curs = .Data` - la fel, necondiionat.
-- `frm_date_aviz.Clb_dataact.Text_simplu1.LostFocus` (:7603-7604) si
- `frm_date_aviz.Clb_dataireg...LostFocus` (:7610-7611): `poDate.zi_curs = poDate.dataact`,
- necondiionat (formularul aviz general nu are guard, dar si nu are RemoveObject pe zi_curs).
-- `frm_date_aviz_lucrare.Clb_dataact...LostFocus` (:8186-8187) si
- `...Clb_dataireg...LostFocus` (:8193-8194): idem, necondiionat - zi_curs NU e niciodata
- eliminat in aceasta clasa, deci sincronizarea merge mereu.
-- `frm_date_factura.Clb_dataact...LostFocus` (:9805-9808) si `...Clb_dataireg...` (:9824-9827):
- ACESTEA SUNT deja conditionate: `If Type('thisform.clb_zi_curs.visible')<>'U' ... zi_curs =
- dataact ... Endif` (comentariu `*!* modificare v 2.0.56`). Cand controlul e eliminat, sincronizarea
- se opreste - dar valoarea RAMASA de la Init/Reset nu se sterge, ramane cea de la creare.
-
-**c) Consum efectiv in SQL (trimis catre Oracle, cursoare de articole):**
-`COMUN\programe\ofacturare.prg:266-308` (identic in `factureaza2`, :751-816) - alegerea SQL-ului de
-populare a articolelor se face pe `tnTip`, NU pe `in_valuta`:
-```
-Case Inlist(tnTip, 48, 49) -> cursor_articole_k(?poDate.zi_curs, ...)
-Case tnTip = 45 -> cursor_preturi(?poDate.zi_curs, ...)
-Case Inlist(tnTip, 1,22,5,29,7,10,23) -> cursor_preturi(?poDate.zi_curs, ...)
-Case Inlist(tnTip, 2,26,6,52) -> cursor_contract(?poDate.zi_curs, ...)
-Case Inlist(tnTip, 3,21,25,28,42,47) -> cursor_comanda(?poDate.zi_curs, ...)
-Case tnTip = 4 -> cursor_avize(...) [FARA zi_curs]
-Case Inlist(tnTip, 41) -> cursor_gestiune(?poDate.zi_curs, ...)
-Case tnTip = 30 -> cursor_aviz_nir(...) [FARA zi_curs]
-Case tnTip = 27 -> cursor_lucrare(?poDate.zi_curs, ...)
-Case Inlist(tnTip, 8,9,24) -> cursor_retur(?poDate.in_valuta, ...) [FARA zi_curs]
-```
-Descoperire cheie: pentru tipurile 8, 9, 24 (retur) SI 30 (aviz pe NIR), SQL-ul NU trimite deloc
-`poDate.zi_curs` catre Oracle - `zi_curs` gol sau completat nu are niciun efect pentru aceste
-tipuri. Acesta e motivul real pentru care eliminarea controlului la tip 8/9 e sigura (mai puternic
-decat simpla existenta a unei valori implicite).
-
-Pentru tipurile care TRIMIT zi_curs, comportamentul in Oracle e diferit:
-- `cursor_preturi` (`docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:2138+`) apeleaza NECONDITIONAT
- `pack_facturare.verifica_cursuri_valute(V_DATA_CURS, V_ID_UTIL)` (linia 2153). Aceasta procedura
- (`:16247-16274`) verifica cursul pentru TOATE valutele distincte din `FACT_VPRETURI_UTILIZATOR`
- ale utilizatorului curent (nu doar valuta documentului!) si arunca
- `RAISE_APPLICATION_ERROR(-20005, 'Nu este setat cursul din data de ... !')` daca oricare dintre
- ele nu are curs care sa acopere `V_DATA_CURS` - EXCLUDE explicit moneda nationala
- (`AND A.ID_VALUTA <> pack_facturare.nid_moneda_nationala`). Deci: chiar pe un document in LEI
- (`in_valuta=0`), daca utilizatorul are liste de preturi in valuta configurate si data trimisa
- (implicita sau nu) nu are curs setat, apelul PICA cu -20005 - INDIFERENT de vizibilitatea
- selectorului pe formular. Riscul nu vine din camp gol, ci din "camp cu o data pentru care nu
- exista curs in tabela CURS".
-- `cursor_articole_k` (`:3595-3701`) si `cursor_lucrare` (`:3173-3593`, foloseste `V_DATA_CURS`
- pentru comenzi_elemente) - `cursor_articole_k` NU apeleaza `verifica_cursuri_valute`, doar face
- `LEFT JOIN CURS ... WHERE DATA <= V_DATA_CURS AND DATA2 >= V_DATA_CURS` - daca nu gaseste, cade
- silentios pe `NVL(D.CURS,0)` (pret gresit, nu eroare). `cursor_lucrare` (:3186-3218) INSA face
- o verificare proprie, similara: daca articolele comenzii au valute fara curs pe `V_DATA_CURS`,
- arunca acelasi `-20005`.
-- Exista deja o rutina de recuperare la acest cod de eroare: `ofacturare.prg:313-317`
- ```
- If lnSucces < 0
- AMESSAGEBOX(goExecutor.oPrelucrareEroare(), 16, "Eroare")
- If goExecutor.nEroare = 20005
- vizualizeaza_curs(poDate.zi_curs)
- ENDIF
- ```
- Deci sistemul ANTICIPEAZA deja cazul "curs lipsa la data respectiva" si deschide un ecran de
- gestiune a cursurilor - independent de validarea din formularul de date.
-
-**d) Afisare / etichetare (fara risc):**
-- `frm_facturare_articole.Init` (:15097-15098) si `frm_facturare_articole2.Init` (:19004-19005):
- `If !Empty(Nvl(poDate.zi_curs,{})) Then Thisform.lb_cursuri.Caption = "Curs valutar (" +
- Dtoc(poDate.zi_curs) + ")"` - deja tolereaza gol (nu afiseaza nimic), fara eroare.
-- `frm_date_factura.do_cauta_valuta` (:9344-9359) - dupa alegerea valutei, muta focusul pe
- `clb_zi_curs` DACA exista (`Type(...)<>'U'`), altfel pe `clb_serie_act`. Deja conditionat.
-- `onom_curs.vc2` (`ck_zi_curs`, `tx_zi_curs`) - ecran DIFERIT, de administrare a cursurilor
- valutare in sine (nu are legatura cu `poDate.zi_curs`; e o cautare "dupa ziua cursului" generica).
-
-## 5. Valoarea implicita azi si de unde vine
-
-Vine din `oDateFactura.Init`/`Reset`, necondiionat de tip sau de `in_valuta`:
-- `Init` (`ofacturare_comun.prg:235-247`): `ldData = Ttod(get_ora())`, ajustat la luna/anul curent
- de facturare (`gnAn`/`gnLuna`) daca `get_ora()` cade in alta luna; apoi `.zi_curs = ldData`.
-- `Reset` (`ofacturare_comun.prg:486-496`): `.zi_curs = .Data` (unde `.Data` a fost deja setat tot
- din `ldData`-ul curent).
-
-Deci implicit `zi_curs` = data curenta (get_ora, ajustata la perioada de facturare deschisa), NU
-`Date()` brut si nu neaparat `dataact`/`dataireg` (desi acestea pornesc de la aceeasi `ldData`).
-Ulterior, cat timp controlul `clb_zi_curs` exista pe formular, orice editare a `dataact`/`dataireg`
-resincronizeaza `zi_curs = dataact` prin evenimentele `LostFocus` (vezi punctul 4b). Daca formularul
-ar ascunde controlul FARA sa elimine obiectul si fara sa goleasca proprietatea, campul ar ramane
-la valoarea implicita de la Init/Reset (sau la ultima valoare sincronizata inainte de ascundere).
-
-## 6. Precedent: tip cu campul ascuns care se salveaza corect
-
-DA, exista deja, dar in `frm_date_factura` (formularul de FACTURA), nu in `frm_date_aviz_lucrare`:
-
-```
-COMUN\clase\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 ^
-```
-
-Pentru tip 8 si 9 (facturi de retur - care pot fi chiar in valuta, vezi `ofacturare_comun.prg:248`:
-`INLIST(m.tnTip, 5,6,7,9,10,52) -> .in_valuta = 1`), controlul `clb_zi_curs` e eliminat COMPLET de
-pe formular, necondiionat de `in_valuta`, si documentul se salveaza corect. Motivele, in ordine de
-robustete:
-1. Validarea din `inainte_de_do_termin` (:9484) e deja garda cu `Type(...)<>'U'`, deci se
- auto-dezactiveaza cand controlul nu mai exista.
-2. SQL-ul de populare articole pentru tip 8/9 e `cursor_retur(?poDate.in_valuta,...)`
- (`ofacturare.prg:306-307`) - NU trimite deloc `poDate.zi_curs`, deci nu poate cauza -20005 din
- cauza acestui camp.
-3. Chiar daca ar fi trimis, `poDate.zi_curs` tot ar avea valoarea implicita de la Init/Reset
- (punctul 5) - nimic nu-l goleste la `RemoveObject`.
-
-Aceasta e "reteta" cerinta de punctul 6: eliminarea vizuala e sigura pentru ca (a) validarea are
-deja garda pe existenta controlului, si (b) proprietatea `poDate.zi_curs` nu e niciodata golita -
-ramane pe implicitul din Init/Reset.
-
-Pentru `frm_date_aviz_lucrare` (linia :8076) NU exista un tip cu campul ascuns - `clb_zi_curs` nu e
-eliminat pentru nici tip 27, nici tip 30. Motivul plauzibil: tip 27 (aviz pe lucrare) chiar
-foloseste `zi_curs` in `cursor_lucrare` pentru articolele comenzii (posibil in valuta), independent
-de `poDate.in_valuta` al documentului-aviz insusi - deci acolo campul NU e un candidat sigur pentru
-ascundere pe baza lui `in_valuta`. Pentru tip 30, SQL-ul (`cursor_aviz_nir`) nu foloseste `zi_curs`
-deloc, deci validarea de acolo e superflua dar inofensiva (campul e mereu populat implicit).
-
-## Ramas de verificat
-
-- Nu am gasit inca daca decizia 15 / S4d intentioneaza sa includa si `frm_date_aviz_lucrare` in
- formularul unificat, sau doar `frm_date_factura`/`frm_date_aviz`. Din cod, `frm_date_aviz_lucrare`
- e un formular de sine statator, fara control de valuta, folosit doar pentru tnTip 27 si 30 - daca
- planul S4d nu-l tinteste explicit, linia :8076 e in afara scopului imediat.
-- Nu am verificat ce se intampla in `cursor_articole_k` (tip 48/49) si `cursor_gestiune` (tip 41)
- fata de `verifica_cursuri_valute` - din citire, `cursor_articole_k` nu apeleaza acea procedura
- (cade silentios pe curs 0), dar nu am verificat `cursor_gestiune`.
-- Nu am verificat cum decide `frm_date_factura.Init` ce alte tipuri (in afara de 8,9) ar putea fi
- candidate pentru ascunderea lui `clb_zi_curs` conform deciziei 15 - doar am confirmat mecanismul
- existent si conditia dubla deja implementata la validare (in_valuta + Type<>'U').
diff --git a/docs/erori_deschise.md b/docs/erori_deschise.md
new file mode 100644
index 0000000..13b01f9
--- /dev/null
+++ b/docs/erori_deschise.md
@@ -0,0 +1,12 @@
+# Erori deschise — formular facturare unificat
+
+Erori observate la rulare, neinvestigate inca. Se sterge intrarea cand e reparata.
+
+## 1. `Alias 'CRSGESTIUNE' is not found.` la parasirea combo-ului de gestiune
+
+- **Unde:** `FRM_FACTURARE_ARTICOLE2.GRD_FACTURA.CGESTIUNE.CCBOGESTIUNE.LOSTFOCUS`, linia 5
+- **Linia:** `REPLACE nume_gestiune WITH crsGestiune.nume_gestiune, id_gestiune WITH crsGestiune.id_gestiune IN crsFactura`
+- **Mediu:** MARIUSM_AUTO, 09.09.2026
+- **De verificat:** cine creeaza `crsGestiune` si pe ce cale de cod ajunge `LostFocus` sa ruleze
+ inainte (sau dupa inchiderea) cursorului — probabil combo-ul isi pierde focusul intr-un context
+ in care cursorul nu a fost creat sau a fost deja inchis.
diff --git a/docs/handoff_13_formular_unificat.md b/docs/handoff_13_formular_unificat.md
deleted file mode 100644
index 81fd2dd..0000000
--- a/docs/handoff_13_formular_unificat.md
+++ /dev/null
@@ -1,798 +0,0 @@
-# Handoff — #13 formular unificat de facturare + editare prin regenerare
-
-Sesiune: 11.08.2026, **runda 17** (istoricul de mai jos e cumulativ; blocul rundei 14 e pastrat ca
-atare). Runda 13 predase dupa cinci proiectari si deciziile 44-50.
-
-> ## RUNDA 17 — „Urmatorul bloc de lucru" S-A GOLIT. Proiectarea lui #13 e INCHEIATA.
->
-> Runda 17 a executat **exact cele doua sarcini** care mai ramasesera (punctele 4 si 5 din lista de
-> jos) si **nu a deschis niciuna noua**.
->
-> > ### DECIZIA 66 (runda 17) RASTOARNA DECIZIA 64 — citeste asta inainte de orice paragraf despre asezare
-> > **Motivul discountului sta LANGA DISCOUNT, in banda de totaluri, nu ca a treia sectiune jos.**
-> > Formularea lui Marius: *„motiv discount vreau sa fie langa discount, nu a treia coloana"*.
-> > **Randul de jos revine la DOUA sectiuni** (incasare, alte date), fiecare pe jumatate de latime —
-> > adica exact decizia 57, punctul 2, neatinsa. **Argumentul „~440 px fiecare, strans" cade odata cu
-> > decizia 64.** Mai jos, in istoricul cumulativ al rundei 16, decizia 64 apare inca in vigoare in
-> > cateva paragrafe: **sunt istorie, nu stare curenta.** Locurile decisive sunt corectate; daca
-> > gasesti unul necorectat, **decizia 66 castiga**. Enuntul complet, cu regula de activare adaugata de
-> > proiectare (campul e activ **doar cand discountul nu e zero**): **in plan**, la „Decizia 66".
->
-> **O singura decizie noua, 66**, deci numerotarea se opreste la **66**.
-
-> ### AUDIT DE INCHIDERE (18.08.2026) — planul e curatat de marcajele „deschis" ramase in urma
-> Verificare ceruta de Marius inainte de a inchide sesiunea: **e planul finalizat?** Raspuns: **da ca
-> proiectare**, dar avea **noua intrebari fantoma** — blocuri „De decis de Marius" si „ramane deschis"
-> care supravietuisera deciziilor care le inchisesera. Un agent proaspat le-ar fi citit ca sarcini si
-> ar fi redeschis lucruri transate. **Toate au fost stinse**, fiecare cu decizia care o inchide, in
-> **8 linii** din plan (verificat prin diff fata de o copie de siguranta: zero modificari colaterale):
-> - trei blocuri **„De decis de Marius"** (S5c, S8b, S11) → inchise de deciziile **51**, **52**, **53**
-> si **56**; textul ramane ca **inventar al recomandarilor acceptate**, nu ca intrebari;
-> - doua afirmatii „ramane deschisa asezarea campului de motiv" → inchise de **decizia 66**;
-> - „din intrebarea 7 ramane deschisa partea de tipuri 48/49" → inchisa de **decizia 60**.
->
-> **Ce a ramas deschis, si e corect asa — trei puncte, toate de implementare, niciunul blocant:**
-> 1. **Relistarea unei facturi vechi deja trimise** (decizia 62, rest semnalat): dupa decizia 59 ar
-> produce N randuri de discount in loc de unul, deci hartie diferita de originalul din eFactura.
-> Relistarea nu e modificare, deci `EsteInEFactura` n-o acopera. **Nedecis, semnalat lui Marius.**
-> 2. **`PROC_TVAV` ca parametru** (consecinta 3 a deciziei 54): doar daca se cere reproducere exacta
-> peste o modificare legala de cota. **De decis separat.**
-> 3. **De unde se reconstituie `IN_STOC`** (cerinta rundei 17): preconditie de proiectare a lui S8,
-> trei variante scrise, niciuna aleasa.
-> **Cod: neatins** — nici un `.vc2` / `.sc2` / `.prg` deschis macar. **Zero Oracle** in aceasta runda,
-> nici macar `SELECT`. **Niciun commit dat de aceasta sesiune.**
->
-> **Punctul 4 — golul `IN_STOC` din S8 — INCHIS**, prins acolo unde cerea handoff-ul precedent (in nota
-> de executie a lui S8, nu la S12). Trei editari in plan, toate verificate pe disc dupa ce sesiunea de
-> la #6 a rescris `docs\` in paralel:
-> - `plan_13:3520-3546` — caseta „CERINTA DE EXECUTIE ADAUGATA IN RUNDA 17";
-> - `plan_13:3567-3569` — criteriul intra in „gata cand" al lui S8;
-> - `plan_13` la S10, consecinta 1 — marcata **PRELUAT**, ca sa nu se redescopere.
->
-> **Punctul dur, si e mai greu decat suna cerinta:** valoarea istorica a lui `IN_STOC` **nu e stocata
-> nicaieri** — nu e coloana pe `VANZARI_DETALII` (verificat pe DB inca de la S10), traieste doar in
-> temp. Deci „S8 incarca `IN_STOC` din document" **nu e implementabil ca atare azi**. De unde se
-> reconstituie e o **preconditie de proiectare a lui S8** — trei variante scrise in plan (din urma
-> lasata in rulaje/gestiune; nomenclatorul curent ca aproximatie **declarata**; coloana noua, deci
-> migrare DB inainte de EXE). **Nu s-a ales niciuna** si nu se presupune niciuna.
->
-> **Punctul 5 — mockup v9 — LIVRAT.** `docs\mockup_13_formular_unificat.html`, 71 336 octeti (era
-> 67 075 la v8). Asezarea e acum **varianta D** cu **randul de jos in doua** si motivul discountului in
-> banda de totaluri (deciziile 57 + 66):
-> antet strans pe doua randuri fara titluri de grup; panoul „Discount pe document" **disparut**; banda
-> de totaluri **in interiorul panoului Articole, dupa `.gridbar`**, deci lipita de grid, cu procentul
-> de discount editabil pe loc, **motivul discountului imediat dupa suma pe care o explica** (decizia
-> 66) si totalul mare singur la dreapta; sub ea, **doua** sectiuni colapsabile egale
-> (incasare · alte date), cu **rezumatul continutului pe randul inchis**.
-> Legenda are acum 5 callout-uri (2 si 4 repurpozate, 5 nou). In text au intrat deciziile
-> **52, 53, 54, 59, 60, 61, 62, 63+65**. Raport: `docs\cercetare\mockup_v9_modificari.md`.
-> **Verificat de sesiunea principala, nu preluat din raport:** 0 taguri nechise, 0 inchideri
-> neasteptate, `
-
-
-
-
- Datele documentului si articolele in aceeasi fereastra, fara incarcarea prealabila a tuturor
- articolelor din toate politicile de preturi. Acelasi formular la introducere, la modificare, la
- copiere si la proforma.
-
-
- Mockup, nu implementare. Campurile, etichetele si coloanele sunt cele reale, verificate pe cod la
- 09.08.2026 — rapoartele sunt in docs\cercetare\.
- Plan: docs\plan_13_unificare_formular_facturare.md
- Asezarea e varianta D (decizia 57, runda 15), cu motivul discountului in banda de totaluri
- (decizia 66, runda 17).
-
-
-
1Formularul
-
- Deschis pe o factura in lei, emisa pe baza de comanda. Antetul e blocat — butonul din bara lui
- arata creionul. Asezarea e varianta D: antetul strans pe doua randuri, fara panou separat de
- discount, banda de totaluri lipita de grid pe toata latimea — cu procentul si motivul discountului
- chiar in ea — si randul de jos cu doua sectiuni colapsabile, incasare si alte date. La introducerea
- unui document nou arata identic, cu antetul deschis si campurile goale.
-
Un singur buton. Creionul deschide antetul si devine discheta; discheta salveaza doar
- antetul si redevine creion. Nicio bifa — nici cele patru de azi, pe serie, numar, data si
- scadenta. Fara valuta si fara data de curs — factura e in lei si niciun articol nu are pret in
- valuta (sectiunea 4). Cat anume deschide, si de ce nu chiar tot in prima etapa:
- sectiunea 2.
-
2
Randul de jos, doua sectiuni
-
Incasarea si alte date (analitice, delegat/transport, adresa de facturare, text aditional)
- stau colapsate, una langa alta, nu una sub alta (decizia 57). Sunt independente — se poate tine
- deschisa doar una — iar randul inchis arata rezumatul continutului, nu doar titlul: cand
- incasarea e completata arata suma si modalitatea, cand nu e nimic completat rezumatul spune asta.
- Campurile din interior stau pe orizontala, doua randuri fiecare. A treia sectiune, pentru
- motivul discountului, a fost incercata si respinsa — motivul sta langa discount, in banda de
- totaluri (decizia 66 rastoarna decizia 64).
- Incasarea ramane cea deosebita (decizia 41): e singura cu efecte laterale reale —
- alocare/dezalocare de numere — deci garda de non-alocare la deschidere se scrie si se testeaza
- intr-un singur loc, si e singura blocata pe un document deja emis (decizia 25). Tot pe document
- emis, analiticele se vad dar nu se editeaza de aici — sectiunea 2.
-
3
Un singur buton de adaugare
-
Adauga articole deschide un meniu cu optiunile potrivite sursei — sectiunea 3.
- Dispare gridul de sus cu toate articolele din toate politicile.
-
4
Banda de totaluri, lipita de grid
-
Baza, discount articole, discount document si TVA, desfacute pe un singur rand, cu totalul
- mare singur la dreapta (decizia 57). Discountul de document se editeaza pe loc, procentul langa
- suma; bifa „se pune in evidenta…" de pe panoul care disparea s-a mutat aici, discret. Repartizarea
- pe cote de TVA e automata si proportionala (decizia 59) — nu se cere nimic utilizatorului.
-
5
Motivul discountului, langa discount
-
Singura bucata din reparatia discountului de document care cere UI nou (decizia 61): text
- optional, ajunge in AllowanceChargeReason din eFactura (ReasonCode
- ramane 95). Sta in banda de totaluri, imediat dupa suma pe care o explica
- (decizia 66) — nu ca sectiune separata jos, cum se stabilise la decizia 64. Ia latimea ramasa
- intre discount si TVA; e activ doar cand discountul de document nu e zero — un motiv fara
- discount n-are ce explica.
-
-
-
2Modificarea antetului, fara sa treci prin articole
-
- Protectia antetului nu e o inventie: formularul de azi de modificare are deja patru bife, cate una
- pe camp, care deblocheaza serie, numar, data si scadenta. Ce se schimba e ca toate patru dispar,
- inlocuite de un singur buton in bara panoului, care isi schimba imaginea: creion cat timp
- antetul e blocat, discheta cat timp e deschis.
-
-
-
-
-
-
1 · antet blocat
-
-
Document
- antet blocat
-
-
-
FF
-
1 244
-
06.09.2026
-
IONESCU V.
-
-
-
-
Nimic nu se poate schimba din greseala. Documentul se poate citi in liniste.
- Butonul arata creionul: apasarea deschide.
-
-
-
-
2 · antet deschis
-
-
Document
- antet deschis
-
-
-
FF
-
1 244
-
06.09.2026 ▾
-
IONESCU V. F4
-
-
-
-
Tot antetul e editabil, si campurile de identitate. Butonul a devenit discheta:
- a doua apasare salveaza antetul si il blocheaza la loc, cu creionul inapoi.
-
-
-
-
- Un singur ciclu, doua stari: creion → deschis → discheta → salvat si blocat → creion.
- Termina ramane neschimbat si salveaza tot documentul; butonul de antet nu il inlocuieste,
- ci acopera cazul in care nu vrei sa treci prin articole.
-
-
- de adaugat Un singur camp de antet nu are azi control nicaieri:
- eFactura. Procedura il scrie la fiecare apel, dar valoarea vine din inregistrare sau e
- fortata zero — nimeni nu il poate schimba. Daca butonul deschide tot antetul, il deschide si pe
- el, langa tipul SAF-T.
-
-
- exista deja Comutatorul nu e un tipar nou in suita: fereastra de
- rulaje face exact asta pe acelasi buton but_modifica, schimbandu-i imaginea in
- save_sus.bmp cand intra in editare — verificat pe cod, rulaje.vc2:4716-4773.
- Se copiaza reteta de acolo.
-
-
-
-
-
Actiune
Ce salveaza
Cum
-
-
Butonul de antet, a doua apasare
-
tot antetul, adica exact cele 14 campuri pe care le stie procedura: ruta,
- delegat, agent, masina, data/ora expedierii, adresa de facturare, listare detaliata,
- text aditional, tip SAF-T, eFactura, plus serie / numar / data / scadenta
-
pe locpack_facturare.modifica_date_factura.
- Nu atinge articolele si nu recalculeaza nicio suma. Zece campuri se scriu neconditionat
- in VANZARI, deci apelul trimite antetul intreg, nu doar ce s-a schimbat;
- cele patru de identitate se propaga dupa ID_FACT in inca cinci tabele.
-
Termina
-
tot documentul, ca azi
-
ruta se alege dupa ce s-a schimbat — vezi sectiunea 7
-
-
-
-
- Asta acopera cazul in care vrei sa corectezi doar delegatul sau data scadentei: apesi creionul,
- corectezi, apesi discheta, inchizi. Articolele nici nu se ating.
-
-
-
- Ce deschide efectiv butonul — si de ce nu chiar tot, deocamdata.
- „Tot antetul” ramane intentia, dar campurile nu au aceeasi ruta de scriere. S-a cautat exhaustiv,
- si in Oracle si in tot codul VFP: pentru o parte din ele nu exista nicio procedura care sa le
- schimbe pe un document deja emis. Nu e o scapare de proiectare, e starea codului de azi.
-
-
-
-
Grup de campuri
Etapa I
Etapa II, cu regenerare
-
-
cele 14 — serie, numar, data, scadenta, ruta, delegat, masina, agent,
- data/ora expedierii, adresa de facturare, text aditional, listare detaliata, tip SAF-T,
- eFactura
-
se deschid salvate pe loc
-
la fel
-
tip document, client, valuta, zi curs, sursa, gestiune sursa, politica de preturi,
- si incasarea
-
blocate cu explicatie la hover
-
se deschid modificarea lor marcheaza documentul pentru
- regenerare, aplicata la Termina
-
analiticele — venit / cheltuiala, sectie, responsabil, lucrare
-
doar afisare se modifica din editarea notei
- contabile, nu de aici
-
-
-
-
- Alegerea de a le tine blocate in etapa I, in loc sa se deschida cu avertisment: un camp
- care se lasa modificat dar nu se salveaza e o capcana. O modificare pierduta in tacere e mai rea
- decat un camp inca blocat, iar hover-ul spune de ce.
-
-
-
3Un singur buton de adaugare, cu meniu
-
- In loc de doua butoane („adauga tot” si „alege”), unul singur care deschide un meniu — acelasi
- tipar folosit deja de butonul de modificare din lista de facturi. Optiunile se schimba dupa sursa
- documentului, cu doua constante: ultimele doua optiuni sunt aceleasi peste tot —
- Cauta in lista de preturi…, cu pretul din politici, si Alege din nomenclator…, cu
- pretul tastat. Sursa umple documentul, nu il inchide: pe o factura din comanda se poate adauga
- oricand un articol liber, si se poate si sterge — clientul mai vrea ceva, sau vrea sa schimbe.
-
-
-
-
-
Factura din comanda
-
-
Adauga articole
-
Adauga tot din comanda
-
Alege din comanda…
-
Cauta in lista de preturi…
-
Alege din nomenclator…
-
-
-
-
Factura din contract
-
-
Adauga articole
-
Adauga tot din contract
-
Alege ratele de facturat…
-
Cauta in lista de preturi…
-
Alege din nomenclator…
-
-
-
-
-
-
Factura din avize
-
-
Adauga articole
-
Adauga tot din avize
-
Alege avizele…
-
Alege liniile din avize…
-
Cauta in lista de preturi…
-
Alege din nomenclator…
-
-
-
-
Factura din lista de preturi
-
-
Adauga articole
-
Cauta in lista de preturi…
-
Alege din nomenclator…
-
Retur de articole…
-
Fara document sursa
-
-
-
-
-
-
Factura de returexista deja
-
-
Adauga articole
-
Alege facturile de returnat…
-
Alege liniile de returnat…
-
Cauta in lista de preturi… nou aici
-
Alege din nomenclator… nou aici
-
-
-
-
Factura venita din ROAAUTOla modificare
-
-
Adauga articole
-
Cauta in lista de preturi…
-
Alege din nomenclator…
-
Liniile devizului nu se ating
-
-
-
-
-
-
-
Cele doua mecanisme de retur
Cum e azi
Ce se schimba
-
-
Factura de retur document de sine statator
-
exista deja alegi facturile clientului dintr-un browse cu
- selectie multipla, iar liniile se populeaza din ele: gestiunea si pretul de achizitie
- vin neschimbate din linia originala, pretul de vanzare se recalculeaza pe curs doar
- daca moneda nu e nationala. Antetul primeste singur textul „RETUR FACTURA …”.
-
se muta ca atare. Nu se reproiecteaza nimic din ce functioneaza — in special nu
- mostenirea gestiunii si a pretului de achizitie.
-
Retur de articole intr-o factura de vanzare normala
-
alt mecanism, complet separat: factura sursa se alege per articol, iar gestiunea
- nu vine din factura sursa, ci se alege. Butonul e vizibil doar pe facturile din lista de
- preturi.
-
capata si alegerea la nivel de document, dupa modelul de mai sus; calea per-articol
- ramane, pentru cand returnezi un singur lucru
-
Cantitate partiala si stergere
-
exista deja coloana isi schimba capul in
- Cant. max. de returnat, serverul calculeaza maximul, iar o linie stearsa isi
- elibereaza cantitatea inapoi
-
nimic — se pastreaza intocmai, ca si interdictia de retur dintr-un retur
-
Articole din afara facturilor sursa
-
nu se poate lista de articole este continutul
- facturilor alese, deci nu ai de unde alege altceva — aceeasi cauza ca la comanda
-
optiunea din lista de preturi devine disponibila si aici. O linie de retur fara
- factura originala e permisa, ca pe orice alt document — returul nu face exceptie.
- Consecinta: pe acele linii gestiunea si pretul de achizitie se aleg, nu se
- mostenesc, iar maximul returnabil calculat pe server nu se aplica, pentru ca nu exista
- cantitate originala fata de care sa se limiteze.
-
-
-
-
-
- „Alege…” deschide un dialog de selectie cu o coloana de bifat si criterii de cautare, dupa modelul
- importului din ROAACNPRO: buton activ doar cand documentul are sursa, populare aditiva in cursorul
- local, nicio scriere in baza pana la salvare. Spre deosebire de modelul acela, la zero rezultate
- se spune de ce, nu se inchide in tacere.
-
-
- Azi „adauga tot” exista, dar e o iconita fara caption si fara tooltip, asezata lateral intre doua
- griduri — si nu acopera contractele: tipurile 2, 6, 26 si 52 lipsesc din conditiile lui de
- vizibilitate, desi avizele sunt acolo.
-
-
- decis„Adauga tot din comanda” / „Adauga tot din avize” raman
- incarcari complete — S4 nu se restrange la o lista de preturi (decizia 39). Grila care le
- alimenteaza (crsarticole) nu e doar sursa listei: e si registrul cantitatii ramase de
- facturat, citit ca sa se decida inchiderea automata a comenzii sau a avizului cand o linie se
- sterge. Cautarea pe server ramane cum se vede mai sus (fara incarcare in masa); ce se decupleaza e
- bookkeeping-ul cantitatii ramase, intr-un registru propriu — ca sa poata disparea incarcarea si pe
- comanda si pe aviz fara sa strice inchiderea automata a documentului sursa.
-
-
-
4Valuta si data cursului
-
- Doua concepte diferite, care azi impart acelasi camp mereu vizibil. Campul „Data curs valutar”
- nu e eliminat niciodata in functie de valuta — doar pe retur — deci apare si pe facturi in lei
- unde nu are ce cauta.
-
-
-
-
Caz
Ce e in document
Ce arata antetul
-
-
-
Factura in lei, articole in lei
-
tot in lei, niciun pret din politica in valuta
-
fara valutafara data curs
- Nimic de ales, nimic de convertit.
-
-
-
Factura in lei, articole cu pret in valuta
-
documentul e in lei; unele articole au pretul din politica in valuta si se convertesc
-
apare Data curs valutar
- Cu explicatia langa el: preturile in valuta se convertesc in lei la cursul acestei
- zile; documentul si contabilitatea raman in lei.
-
-
-
Factura in valuta Invoice, credit note, retur valuta, factura fiscala valuta pe contract
-
documentul insusi e in valuta; articolele au pret in valuta
-
ValutaData curs valutar
- Amandoua, ca azi.
-
-
-
-
-
- Al treilea caz nu se alege din formular: e decis de tipul documentului la deschidere, iar
- selectorul de valuta e scos din formular cand documentul nu e de tip valuta. Deci „factura in
- valuta” nu e o bifa pe care o pune operatorul, ci felul documentului.
-
-
- Unificarea rezolva o problema care azi nu e rezolvabila. Cazul al doilea nu se poate sti la
- deschiderea antetului — se afla abia dupa ce se incarca articolele, cand antetul de azi e deja
- inchis. In formularul unificat antetul si articolele sunt in aceeasi fereastra, deci campul poate
- aparea in momentul in care intra pe grid primul articol cu pret in valuta. Din acelasi motiv
- dispare si mecanismul bug-ului #16: nu mai exista un antet inchis la care sa te intorci din
- formularul de curs.
-
-
- decisValidarea cursurilor se restrange la valuta cautata (decizia
- 42). Pe varianta filtrata a cursoarelor, verifica_cursuri_valute nu mai ruleaza
- global la deschiderea formularului, ci doar pe valuta articolului adus in grid. Un curs lipsa pe
- alta valuta nu mai e semnalat la deschidere, ci abia cand se ajunge la un articol pe acea
- valuta — diferenta e asumata, se consemneaza la testare, nu e regresie.
-
-
-
5Discountul pe linie
-
- Verificat pe formularul de azi si pe tabela. Raspunsul e mai simplu decat parea: si procentul, si
- valoarea exista deja — dar nu in grid.
-
-
-
-
Ce
Cum e azi
Ce se schimba
-
-
-
Procent si valoare unitara, ca intrare pentru operator
-
exista deja in dialogul de articol care se deschide la
- fiecare adaugare: trei campuri — procent, suma in lei, suma in valuta — orice tastezi in
- unul recalculeaza pe celelalte.
-
Dialogul dispare odata cu unificarea. Cele doua campuri devin coloane in grid,
- cu acelasi calcul in spate.
-
-
-
Ce se stocheaza
-
o singura coloanaVANZARI_DETALII.DISCOUNT_UNITAR,
- NUMBER(22,6) — valoare absoluta pe unitate. Nu exista coloana de procent.
- Aceeasi coloana e si pe politica de pret, deci discountul poate veni din politica.
-
Nimic. Modelul de date nu se atinge — procentul ramane doar mod de introducere.
-
-
-
Discountul in grid, azi
-
inconsecvent pe factura in lei coloana e read-only; pe
- factura in valuta e editabila, dar nu are handler de recalcul — o editare directa in
- celula schimba valoarea fara sa refaca totalurile.
-
Se repara odata cu mutarea in grid: aceleasi validari ca in dialogul de azi.
-
-
-
-
-
- De verificat separat, inainte de a incepe: daca discountul unitar apare pe rapoartele tiparite si
- daca e transmis in eFactura si SAF-T. Daca nu apare pe hartie, documentul tiparit nu explica
- totalul.
-
-
- decisDiscountul de DOCUMENT (nu cel de linie, de mai sus) se
- repartizeaza proportional pe cote de TVA, nu pe cota maxima cum face codul de azi (decizia 59).
- E automat, nu cere nimic de la operator. In banda de totaluri (sectiunea 1) se vede o singura suma;
- pe factura tiparita, cu cote mixte, pot aparea mai multe randuri „Discount X % Factura", cate unul
- per cota.
-
-
-
6De unde se intra in formular
-
- Cerinta e ca formularul sa poata fi deschis cu sursa deja completata, fara sa o mai alegi.
- Doua cai fac deja exact asta.
-
-
-
exista Din pagina Comenzi
-
Butonul de pe randul de comanda trimite comanda selectata si deschide formularul cu ea
- completata. Ascuns cand comanda e deja facturata.
-
exista Din programul de contracte
-
Butonul de pe grila de contracte trimite contractul selectat si deschide acelasi formular,
- cu contractul completat. Nu mai alegi nimic.
-
generic Din meniu
-
Fara sursa precompletata — alegi comanda sau contractul in formular, ca pana acum.
-
-
- Ce merita schimbat, si atat: sursa se transmite azi prin variabile globale, nu ca parametru.
- De aceea calea generica de comanda e obligata sa goleasca explicit globalul inainte de apel, ca sa
- nu ramana precompletata cu ce era in sesiune — iar calea de contract nu face acelasi lucru.
- Un parametru explicit inchide subiectul. Nu presupune nicio integrare noua de contracte.
-
-
-
-
-
7Ce se scrie la Termina
-
- Un singur formular, dar nu o singura cale de scriere. ID_FACT se pastreaza in
- toate cazurile.
-
-
-
-
Ce s-a schimbat
Cum se scrie
Efect
-
-
-
Antet — cele 14 campuri pe care le stie procedura
-
pe locmodifica_date_factura
-
aceeasi procedura ca butonul de antet pe a doua apasare; propaga serie / numar / data dupa ID_FACT
-
-
-
Antet — tip document, client, valuta, zi curs, sursa, gestiune sursa, politica de preturi,
- si tot ce tine de incasare
-
regenerare
-
verificat pe cod: nu exista nicio cale de a le scrie pe un document emis — nici in
- Oracle, nici in VFP. Singura ruta e drumul de emitere, adica regenerarea. Pana cand ea
- exista (etapa II), campurile raman blocate.
-
-
-
Antet — analiticele: venit / cheltuiala, sectie, responsabil, lucrare
-
nu de aici
-
se editeaza din editarea notei contabile, care le trateaza la nivel de linie de
- nota. Formularul unificat le arata, nu le scrie — ca sa nu existe doua ferestre care
- modifica acelasi camp cu intelesuri diferite.
-
-
-
Explicatia si codul fiscal al unei linii
-
pe locmodifica_explicatie_articol
-
doua coloane, nicio suma
-
-
-
Cantitati, preturi, linii adaugate sau sterse, discount, gestiune, cota TVA
-
regenerare stergere + reemitere, in aceeasi tranzactie
-
documentul vechi sters = 1; cel nou scris pe drumul normal de emitere; notele si rulajele refacute
-
-
-
Nimic
-
nimic
-
documentul ramane neatins
-
-
-
-
-
- decisUn singur cod de scriere contabila (decizia 35).
- Regenerarea de mai sus scrie pe acelasi drum si la emitere, si la editare (etapa II):
- scrie_factura2 → contabilizeaza_articol, cu parametrul de cont de la
- sectiunea 10. Canalul oscrie_in_fisiere, folosit azi de #6, nu intra in #13 —
- doua implementari ale aceleiasi reguli de contare, una in pachet si alta in VFP, ar trebui tinute in
- pas manual la fiecare schimbare. Nu exista in acest formular editare directa a randului din
- ACT_TEMP.
-
-
-
8Ce trebuie verificat inainte
-
-
de verificat
- ID_FACT refolosit la reemitere. Azi se ia din secventa, neconditionat.
- Varianta care il cauta dupa numar, serie si data exista in pachet, dar e comentata — si
- filtreaza STERS = 0, deci trebuie citita inainte de stergere.
-
de verificat
- Stergerea si reemiterea in aceeasi tranzactie, fara commit intre ele.
-
decis
- La reemitere se scriu valorile din formular, nu se reciteste sursa (decizia 54). Intrebarea
- nu mai e ce garda punem peste re-derivare — e daca re-derivarea chiar se produce; raspunsul lui
- Marius: nu trebuie sa se produca. Fara avertizare si fara confirmare, a fost respinsa explicit.
-
decis
- Atasamentul PDF al documentului vechi se sterge la reemitere, nu se remigreaza (decizia 53).
- Documentul reemis porneste curat; PDF-ul se regenereaza la prima listare.
-
decis
- Facturile de marfa in custodie (tipurile 48 si 49) sunt editabile prin #13 (decizia 60).
- Cu restrictia pastrata: pe ele nu se pot adauga articole gestionabile
- (IN_STOC <> 0).
-
decis
- Singura restrictie de modificare e ca documentul sa nu fi fost trimis in eFactura (decizia
- 62). Fara nicio conditie de data, fara retroactivitate.
-
decis
- Auditul (data + utilizator pentru adaugare, modificare si stergere) se afiseaza in gridul din
- frm_facturi, nu in formularul unificat (deciziile 63 si 65). Formularul nu capata
- niciun control nou din cerinta de audit.
-
decis
- do_modifica de pe frm_facturi ramane activ pentru multi-selectie
- (decizia 52). Formularul unificat preia doar cazul cu un singur document.
-
de verificat
- Descarcarea de gestiune pe proforma, pe partea Oracle.
-
de verificat
- Discountul unitar in listari si in eFactura / SAF-T.
-
de verificat
- Validarea datei de curs pe avizul de lucrare — acolo e ceruta neconditionat, deci
- ascunderea campului ar bloca finalizarea. Se repara impreuna, nu doar se ascunde.
-
de verificat
- Legatura dintre linia de retur si linia originala. In program se acumuleaza perechi
- articol-factura si se trimit la salvare, dar daca serverul le pastreaza intr-o coloana nu se
- poate stabili din codul de aici. De asta depinde daca formularul poate arata din ce factura
- vine fiecare linie de retur.
-
raspuns
- Ce face pachetul ROAAUTO cand factura primeste o linie pe care devizul nu o stie:
- nimic — nu citeste deloc tabelele de vanzari. Nu mai blocheaza nicio estimare, vezi
- sectiunea 9.
-
raspuns
- Nepotrivirea de afisare ROAAUTO intre ecranul de deviz si factura retiparita —
- decizia 28: acceptata. Conditia e ca MANOPERA si MATERIALE sa fie conform devizului;
- restul articolelor pot exista pe factura fara sa apara pe deviz. Nu se cere cod nou in ROAAUTO.
- Vezi sectiunea 9.
-
raspuns
- Stergerea unei linii venite din comanda — decizia 29: fara protectie. Se sterge
- ca oricare alta; comanda ramane cu cantitatea nefacturata si va aparea, corect, facturata
- partial. Nu se cere confirmare, nu se marcheaza „refuzat”.
-
raspuns
- Coordonarea cu #6 — decizia 30: nu se coordoneaza. #13 incepe dupa ce #6 se
- termina, deci nu exista doi scriitori simultan pe acelasi fisier. Decizia 26 (analiticele
- read-only in #13) ramane — motivul ei e semantic, nu de calendar. Decizia 38: fluxul de
- editare al lui #6 (editare directa a randului din ACT_TEMP, prin
- oscrie_in_fisiere) nu se retrage odata cu #13 — coexista cu regenerarea prin
- pack_facturare, iar decizia despre unificarea lor se ia mai tarziu, dupa ce #13
- livreaza si se vede in practica daca intretinerea celor doua drumuri doare cu adevarat.
-
decis
- Bug-ul de dezalocare POS se repara in trecere, odata cu mutarea antetului din sectiunea 2
- (decizia 40) — nu e o mutare pur mecanica, testarea trebuie sa acopere si dezalocarea POS pe
- calea veche.
-
raspuns
- Cu ce cont de venit intra un articol fara politica de pret. Nu printr-o politica de pret
- implicita — decizia 24 s-a retras. Decizia 27: contul de venit se deriva,
- din CORESP_CONT_VENCHELT pentru articolele gestionabile si din
- NOM_ARTICOLE.CONT (sau, implicit, 704) pentru cele negestionabile; derivarea
- se face in VFP (decizia 27-bis), pack_facturare ramane neatins. Reteta si
- costurile: sectiunea 10.
-
-
-
9Facturile venite din ROAAUTO
-
- ROAAUTO emite facturi din formularul lui de devize, dar prin acelasi pachet si in aceleasi tabele.
- Formularul unificat le vede fara niciun cod special. Ce lipseste nu e recunoasterea, ci scrierea.
-
-
-
-
Intrebare
Raspunsul de pe cod
-
-
Scrie in aceleasi tabele?
-
da acelasi PACK_FACTURARE, acelasi drum prin
- tabela de staging catre VANZARI_DETALII. Tip de document -12.
-
Se vad in editorul nou?
-
da deja, testat pe date reale — detectia liniilor nu
- filtreaza dupa tipul documentului.
-
Se pot adauga articole la emitere?
-
da prin Alte servicii, la emiterea facturii finale.
- Articolele vin din nomenclatorul brut, sunt limitate la cele fara stoc, iar
- pretul se tasteaza — nu vine din politici. Raman linii proprii, nu se cumuleaza in
- manopera sau materiale.
-
Se pot modifica dupa emitere?
-
nu butonul se blocheaza imediat ce comanda are numar de
- factura, metoda de stornare a comenzii e goala, iar gridul din editorul nou e read-only.
- Singurul instrument asupra unei facturi emise e stergerea ei intreaga. Asta e
- capacitatea care se cere.
-
Cum arata liniile lor?
-
cele venite din deviz nu sunt articole: sunt sume cumulate pe categorii — manopera,
- materiale, avans, discount — pe pseudo-articole cu cod negativ. Langa ele pot sta articole
- reale. Niciunele nu au gestiune, nici macar cele reale.
-
-
-
-
- Ce se cere: aceeasi adaugare de articole si la modificarea documentului, nu doar la emitere —
- si nu numai pentru facturile auto, ci pentru orice tip de factura, din lista de preturi sau direct
- din nomenclator.
-
-
- corectie„Alte servicii” nu e jumatatea de drum pe care o
- credeam. Mecanismul acela functioneaza tocmai pentru ca ocoleste contabilizarea:
- facturile de deviz merg pe o cale paralela, care nu genereaza nicio nota contabila de venit.
- Pe fluxul normal de facturare, unde nota se genereaza, un articol fara politica de pret e
- respins cu eroare. Deci nu se generalizeaza un mecanism existent — se rezolva altfel (mai jos).
-
-
- rezolvatDevizul nu se dezechilibreaza. Pachetul ROAAUTO
- nu citeste deloc tabelele de vanzari — nici antetul, nici liniile. Legatura pe care o face
- dupa emitere e in sens invers: pune numarul documentului pe comenzile si lucrarile lui. Deci o
- linie adaugata din formularul unificat nu strica niciun total si nu cere niciun apel suplimentar
- catre ROAAUTO.
-
-
- decisNepotrivirea de afisare e acceptata (decizia 28).
- Totalul devizului se calculeaza din structura proprie ROAAUTO, deci nu va arata niciodata
- linia adaugata; in schimb factura retiparita o va arata, pentru ca relistarea citeste
- direct liniile documentului. Conditia ceruta de Marius e alta: MANOPERA si MATERIALE sa fie
- conform devizului — restul articolelor pot exista pe factura fara sa apara in ecranul de
- deviz. Nu se cere cod nou in ROAAUTO ca sa aduca ecranul de deviz la zi.
-
-
-
-
-
10Contul de venit pentru articole adaugate din nomenclator
-
- Intrebarea ramasa deschisa in sectiunea 8: cu ce cont de venit intra un articol adaugat
- „Alege din nomenclator…”, fara politica de pret. Decizia 27 (mai jos) nu s-a schimbat; reteta prin
- care ajungea la pack_facturare s-a abandonat intre runda 8 si runda 9-10, in favoarea
- unui parametru nou.
-
-
-
- respinsDecizia 24 — articolul ales din nomenclator
- primeste id_pol-ul unei politici de pret implicite. Retrasa in runda 8: evita cod
- nou in pack_facturare, dar cu pretul unei configurari cu contabilul (care politica,
- cu ce SCC) si al unui cont de venit uniform pentru orice articol adaugat asa.
- Inlocuita de decizia 27.
-
-
-
Decizia 27 — contul de venit se deriva, pe doua ramuri
-
-
-
Articol
Sursa contului de venit
-
-
gestionabil cont de gestiune clasa 3xx
-
CORESP_CONT_VENCHELT.CONT_VENIT, cautat pe CONT = contul de
- gestiune al liniei
-
negestionabil
-
NOM_ARTICOLE.CONT, daca e deja cont de clasa 6xx sau 7xx;
- altfel, implicit 704
-
-
-
-
-
- respinsDecizia 27-bis — reteta VFP in 4 pasi: calculeaza
- contul, cauta o politica a carei nota il are deja, insereaza articolul in ea cu
- pack_preturi.adauga_politica_pret_art, trimite id_pol. Abandonata in
- runda 9 (decizia 34): intrebarea deschisa era cum alege programul nota contabila de vanzare pe
- factura din comanda, care nu are politica de pret (decizia 32) — iar raspunsul lui Marius se
- refoloseste direct pentru articolul ad-hoc. Nu mai e nevoie de politica tehnica, nici de
- interogarea inversa pe SCC, nici de inserarea articolului intr-o politica.
-
-
-
Decizia 34 — contabilizeaza_articol primeste contul, printr-un parametru nou
-
- Marius, textual: „poti sa adaugi parametrul contul contabil la contabilizeaza_articol.”
- Verdictul de proiectare, in trei randuri, pentru ca schimba forma literala a cererii:
- contabilizeaza_articol ia azi un singur parametru,
- detalii_articol VANZARI_DETALII_TEMP%ROWTYPE — contul nu intra pe el literal, ar fi
- cosmetic. Intra ca coloana nouaVANZARI_DETALII_TEMP.CONT_VENIT VARCHAR2(4) NULL,
- populata printr-un parametru nouV_CONT_VENIT IN VARCHAR2 DEFAULT NULL, adaugat
- la coada lui adauga_articol_factura (procedura chemata direct din VFP) —
- contabilizeaza_articol il primeste automat, fara sa i se schimbe semnatura.
- Precedentul e in aceeasi lista de parametri: V_TAXCODE si V_LOT sunt deja
- doi parametri adaugati ulterior, la coada, cu DEFAULT NULL, iar apelul VFP e pozitional
- si se opreste la V_LOT.
-
-
- Cei trei apelanti interni nu se ating deloc — scrie_factura2,
- scrie_factura_avize_retur si scrie_aviz_retur fac
- SELECT * BULK COLLECT intr-un TABLE OF ...%ROWTYPE, deci coloana noua le
- traverseaza fara nicio schimbare de cod. Ramura noua se activeaza doar pe
- detalii_articol.cont_venit IS NOT NULL: infasoara blocul FACT-024 (garda
- ramane litera cu litera pe ramura veche — o linie fara politica si fara cont trimis continua
- sa cada pe eroare), n-are cursor deloc, deci descarca_gestiune ruleaza exact o data
- prin constructie — bug-ul de set multi-rand din ramura veche nu se mosteneste, fara sa se repare
- ramura veche.
-
-
- de retinut la implementare Parametrul se cableaza in doua locuri
- VFP, nu unul: frm_facturare_articole.do_scrie_articole si
- frm_facturare_articole2.do_scrie_articole sunt doua clase distincte, fiecare cu apelul
- ei RPC propriu. Daca se vrea CONT_VENIT pastrat si dupa fapt in
- VANZARI_DETALII, lista de coloane explicita din scrie_in_vanzari (24 de
- coloane azi) trebuie extinsa — altfel coloana traieste doar in VANZARI_DETALII_TEMP si
- ACT_TEMP. Articolul compus nu e o gaura aici: e exclus structural — proprietatea
- COMPUS traieste pe perechea (articol, politica), prin ID_POL_ART, iar o
- linie fara politica n-are asa ceva.
-
-
-
Decizia 36 — SCD si CU_TVA pe ramura fara politica
-
- Nota veche mai furniza si SCD, CU_TVA, IN_VALUTA,
- EXPLICATIE, ID_VENCHELT, ID_SECTIE — nu doar contul.
- Verificarea n-a gasit nicio sursa alternativa in cod pentru primele doua (nici optiune de firma
- existenta, nici cont pe partener, nici flag de scutire pe articol sau client), deci sunt decizii de
- produs, si Marius le-a luat:
-
-
-
-
Camp
Sursa noua
-
-
SCD
-
o optiune de firma noua, cu 4111 ca implicit — acelasi tipar in trei
- niveluri deja folosit de pack_facturare.scrie_incasare2 pentru
- RF_CONT_INCASARE_*: parametru explicit → optiune de firma → constanta
- hardcodata daca optiunea lipseste. Mecanismul (tabelul OPTIUNI,
- PACK_SESIUNE.getoptiunefirma, ecranul generic frm_optiuni) exista
- de 15+ ani, deci cheia noua nu cere niciun cod VFP nou, doar randul in tabel.
- ASCD nu se atinge — se calculeaza deja din V_SCD.
-
CU_TVA
-
derivat din cota liniei, nu fixat: 1 daca proc_tvav > 0,
- altfel 0. Elimina prin constructie riscul gasit la verificarea adversariala: cu
- CU_TVA = 1 fixat, o linie scutita ar fi intrat in comparatia de maxim din
- nproc_tva_max si ar fi putut imprumuta coloana si taxcode-ul ei liniei de
- discount a intregii facturi. Diferenta fata de ce face azi nota e intentionata, se
- consemneaza la testare.
-
-
-
-
- Lista de parametri noi ramane la unul singur, V_CONT_VENIT: SCD
- vine din configurare, CU_TVA se deriva in pachet din date deja prezente pe rand.
-
-
-
Decizia 37 — cheia optiunii de firma
-
- RF_CONT_ART_FARA_POL, aliniata la familia RF_CONT_INCASARE_* — aceleasi
- optiuni care alimenteaza azi SCD in acelasi pachet, deci apar grupate alaturi in
- ecranul de optiuni. VARTYPE = 'CHARACTER', VARVALUE = '4111',
- PROGRAM = 'ROAFACTURARE', dar PROGRAME larg — apelul traieste in
- COMUN\clase\ofacturare.vc2, prezent in toate cele sapte produse ale suitei.
- Fara validare de cont, nici la salvare nici la citire — acelasi tipar ca
- RF_CONT_INCASARE_*, care nu valideaza de 15 ani. Garda gratuita ramane lungimea: un
- VARVALUE peste 4 caractere da ORA-12899 la
- INSERT INTO ACT_TEMP — esec zgomotos, nu cont tacut gresit. Un cont inexistent in
- planul de conturi, scris din greseala in ecran, ajunge pe nota neschimbat — risc acceptat constient,
- acelasi pe care produsul il are deja pe optiunile de tip cont.
-
-
-
- Intrebarea lui Marius, verificata: „In ROAACNPRO si pe factura din comanda / contract se
- adauga articole fara politica — de ce nu si aici?” Raspuns, neschimbat fata de v7:
- ROAACNPRO nu cheama deloc contabilizeaza_articol — are propria contabilizare,
- pack_acn.salveaza_regdoc. Pe contract, articolele vin din
- cursor_contract / cursor_preturi, cu id_pol deja atasat de
- cursor. Deci FACT-024 ramane blocantul pe linia ad-hoc — parametrul de mai sus e
- cum se evita, nu un motiv sa fie sarit.
-
-
-
Ce nu e gratuit
-
-
Regresie pe toata suita, nu doar ROAFACTURARE.pack_facturare e comun la
- ROACONT / ROAGEST / ROACONTRACTE / ROAAUTO / ROAACNPRO, si ramura noua e atinsa de apelul comun
- din ofacturare.vc2.
-
Doua clase VFP cablate separat.frm_facturare_articole.do_scrie_articole si
- frm_facturare_articole2.do_scrie_articole isi construiesc fiecare propriul apel RPC —
- parametrul se adauga in ambele, nu o singura data.
-
Lista de coloane a lui scrie_in_vanzari trebuie extinsa explicit daca se
- vrea CONT_VENIT pastrat si dupa fapt in VANZARI_DETALII, nu doar in
- VANZARI_DETALII_TEMP / ACT_TEMP.
-
Un cont fara precedent (cazul 704) intra direct pe linie, fara sa mai treaca
- printr-o politica sau o nota existenta — spre deosebire de reteta veche, nu mai cere configurare
- cu contabilul, dar nici nu mai e validat impotriva planului de conturi (decizia 37).
-
-
-
-
-
11Puncte marunte ramase
-
- Nu blocheaza nimic din ce e mai sus; se inchid la implementarea povestii respective. Enumerate ca sa
- nu se piarda intre runde — se merge pe recomandare daca Marius nu
- spune altfel.
-
-
-
-
Punct
Poveste
Se merge pe
-
-
Textul tooltip-urilor pentru analiticele read-only si pentru grupul de incasare blocat
-
S3b
formularea propusa in raport, sectiunile 2.2 si 5.3
-
Eager vs. lazy pentru lookup-urile Oracle din Init (delegat / masina
- ultimei facturi, casa)
-
S3b, S3
lazy, ca sa nu se plateasca la fiecare depliere
-
_checkbox1 vs. chkDetaliat — campul unic de „listare
- detaliata”
-
S3b, S1
nedecis — se inchide pe cod la implementare, nu prin alegere
-
Forma lui toSursa: obiect scatter (duck-typing) sau clasa dedicata
-
S3c
duck-typing, ca azi — o clasa noua n-ar schimba nimic functional
-
Conversia comenzii si a contractului: un commit sau doua
-
S3c
un singur commit — aceleasi trei fisiere comune, separarea nu reduce
- regresia
-
goComanda = '' redundant la Cw3.do_actiune dupa conversie
-
S3c
se lasa, marcat explicit „intentionat” in diff
-
Contractul cu doua meniuri (articole vs. rate): eticheta generica sau diferentiata pe
- OPT_FACTURARE
-
S4b
diferentiata — „Alege ratele de facturat…” e gresita pe contractele cu
- articole
-
„Alege facturile de returnat…” — ramane doar la antet sau capata incarcare aditiva din
- bara
-
S4b
ramane la antet in etapa I; mutarea e poveste separata
-
But_renunt1 / But_reset1 capata Caption pentru
- consistenta cu bara etichetata
-
S4b
da — decizia 13 cere etichete, nu iconite mute
-
Ordinea si formularea optiunilor din xmenu() per sursa
-
S4b
tabelul din sectiunea 3 a raportului
-
UX-ul contractului cu doua surse pe acelasi grid conceptual (crsarticole
- filtrat + crsarticole1)
-
S4
de confirmat vizual la mockup, nu pe hartie
-
-
-
-
-
diff --git a/docs/plan_13_executie.md b/docs/plan_13_executie.md
new file mode 100644
index 0000000..1905b85
--- /dev/null
+++ b/docs/plan_13_executie.md
@@ -0,0 +1,146 @@
+*!* 03.09.2026
+*!* agent documentatie (orchestrat de team-lead, sesiune plan13-s2)
+*!* Coloana "Stare" era stale din 27.08.2026 (marca NEINCEPUT povesti de mult inchise si probate).
+*!* Adusa la zi pe baza `docs\handoff_plan13_executie_continua.md` (fisierul de stare viu — ramane
+*!* sursa de adevar, se citeste ACOLO intai). Rezolvata si capcana de numerotare de mai jos, prin
+*!* sectiunea separata "Firul geometrie (designer editabil)".
+
+# Plan #13 - executie pe stories
+
+Tabel de urmarire pentru executia planului `docs\plan_13_unificare_formular_facturare.md`,
+conform metodei de executie (liniile 1954-2015 din plan, decizia 55). Nu e reproiectare - fiecare
+story are proiectarea proprie in plan si/sau in `docs\cercetare\`. Actualizat dupa fiecare story
+inchisa. **Sursa de adevar pentru stare e `docs\handoff_plan13_executie_continua.md`** - acest
+tabel e o rasfrangere a lui, tinuta pentru titluri scurte, fisiere atinse si dependente.
+
+**Capcana de numerotare — REZOLVATA (03.09.2026).** Numele `S6`/`S7`/`S8`/`S8b`/`S8c` din acest
+tabel se refera strict la povestile din acest plan ("Test pe flux real", "Actiunea si garzile",
+"Incarcarea documentului in formular" etc.). Un lant separat, comis tot pe `plan13-s2`, a folosit
+ACELEASI nume pentru firul "designer editabil" (cererea separata a lui Marius,
+`docs\sinteza_designer_editabil.md`). Cele doua nu au nicio legatura. Firul de geometrie are acum
+randuri proprii, cu prefixul `S8-geometrie-*`, in sectiunea **„Firul geometrie (designer
+editabil)"** de sub tabelul principal — nu se mai confunda cu povestile de aici.
+
+## Vocabular de stare
+
+- **INCHISA SI PROBATA** — cod comis + proba automata verde.
+- **INCHISA FARA COD** — inchisa prin decizia lui Marius, fara implementare (cu decizia citata).
+- **LIVRATA, PROBA MANUALA DATORIE** — codul e comis si probat automat, dar criteriul oficial
+ „gata" e o proba manuala UI pe care Marius n-o poate face acum (mandatul din §1 al handoff-ului).
+- **PARTIALA** — ce s-a livrat si ce a ramas, explicit.
+- **NEINCEPUT** — chiar neinceput.
+
+## Tabel stories
+
+| Story | Nume scurt | Fisiere atinse (din plan) | Depinde de | Stare | Nota de executie |
+|---|---|---|---|---|---|
+| S1 | Inventar campuri + alegerea bazei | (inventar, fara cod) | - | **INCHISA FARA COD** — aprobata de Marius, 09.08.2026 | `docs\S1_inventar_campuri_formular_unificat.md` |
+| S2 | O singura procedura `factureaza` | `COMUN\programe\ofacturare.prg`, `Clase\ofundal_facturare.vc2` (decizia 67 + completare + corectie review) | S1 | **LIVRATA, PROBA MANUALA DATORIE** — comisa pe `plan13-s2`, 21.08.2026; netestata manual la momentul comiterii (decizia lui Marius). De atunci exercitata cu succes indirect, prin documente reale emise care trec prin `factureaza`, la S6 (`docs\raport_s6_flux_real.md`) si S9 (`docs\raport_s9_7_oracle.md`, `docs\raport_s9_7_vfp_proba.md`) — proba manuala UI dedicata ramane datorie deschisa | `docs\nota_executie_s2.md`, `docs\raport_s2_implementare.md`, `docs\cercetare\s2_factureaza_unificare.md`, `docs\review_s2.md`, `docs\handoff_13_s2.md` |
+| S3 | Portare logica antet in formularul unificat (spart in S3-1..S3-4, decizia 68) | `ofacturare.vc2`, `ofacturare_antet.prg` (nou, S3-2), `ofacturare.prg` (S3-4) | S2 | **LIVRATA, PROBA MANUALA DATORIE** — S3-1..S3-4d COMISE pe `plan13-s2` (COMUN `89dd30a`, `27bdf58`, `c269fdf`, `4f6af10`, `359f478`, `02df236`, `e538590`, `409ce90`, `e96fd3e`); Q8 (numarul ars) COMISA, doar pe calea unificata. Implementarea e completa; proba manuala pe tip 1 a fost refuzata de Marius (22.08.2026), iar `factureaza` nu e apelabila headless | `docs\nota_executie_s3.md`, rapoartele si review-urile S3-1/S3-2/S3-3, `docs\raport_b1_rerulare_s3_3.md`, `docs\raport_q8_numar_ars.md`, `docs\review_q8_numar_ars.md`, `docs\raport_adaptare_paritate_q8.md`, `docs\handoff_13_s3.md` |
+| S3b | Sectiune pliata: alte date + analitice | `caut_ora.vc2`, `ferestre_cere_date.vc2`, `ofacturare.vc2`, `omodificari.vc2` | S3 | **PARTIALA** — implementata aproape integral, comisa pe `plan13-s2`. Criteriul „gata" din 5 puncte (`docs\cercetare\s3b_alte_date_analitice.md` §10): **(1) paritate emitere pe 4 tipuri de incasare — TRECUT**, `test_s3b_emitere_paritate_2.prg` PASS 20/0 (`docs\raport_s3b_criteriu1_pasat.md`); **(2) non-alocare la toggle de pliere — TRECUT**, `test_s3b_incasare_nealocare.prg` PASS 14/0 (`docs\handoff_13_s3b_asezare.md`); **(3) blocarea grupului de incasare pe document emis — CADUC pentru S3b, amanat la S8c** (decizia 25); **(4) analitice read-only — CADUC, rasturnat de decizia 72** (raman editabile); **(5) paritate delegat/transport/adresa/text — FACUT**, cu o inconsecventa vizuala minora ramasa (`Ct_clb_delegat`/`Ct_clb_masina` editabile pe proforma, unde calea veche le scotea) [^1] | `docs\handoff_13_s3b_varianta_b.md`, `docs\raport_s3b_varianta_b.md`, `docs\handoff_13_s3b_reasezare_grila.md`, `docs\handoff_13_s3b_asezare.md`, `docs\cercetare\s3b_alte_date_analitice.md` §10, `docs\cercetare\s3b_bloc5_ce_ramane.md` |
+| S3c | Sursa ca parametru, nu ca global | `ferestre_contracte.vc2`, `ocomenzi.vc2`, `ofacturare.prg`, `ofacturare_comun.prg`, `ofundal_facturare.vc2`, `oproceduri_facturare.prg` | S2. Atinge cod comun intregii suite - nu se face impreuna cu alta modificare | **INCHISA SI PROBATA (S3c-1/2/3/4-tinta1)** + **INCHISA FARA COD (S3c-4-tinta2 si S3c-5)**, 31.08.2026 — S3c-1/S3c-2/S3c-3: `toSursa` la coada in `Init`/`factureaza`/`facturare_contracte`/`facturare_comenzi`, test 55/0, comis 27.08.2026. S3c-4 tinta 1 (`ocomenzi.vc2:do_factura`): LIVRATA, test 18/0. S3c-4 tinta 2 (ROACONTRACTE) si S3c-5 (sincronizare cross-produs, 6 produse): mutate intr-o **poveste separata prin decizia lui Marius**, nu se mai ating la planul #13 (detaliu in §9 al handoff-ului) | `docs\nota_executie_s3c.md`, `docs\raport_s3c_1_implementare.md`, `docs\handoff_13_s4_s3c.md`, `docs\propunere_s3c_4_apelanti_reali.md`, `docs\propunere_s3c_5_sincronizare.md` |
+| S4 | Cautarea articolelor pe server, in linie | `ofacturare.prg`, `ofacturare.vc2` | S3 | **PARTIALA** — S4-1 (Oracle articole server) INCHISA SI PROBATA, 23.08.2026 (identic byte-cu-byte pe filtru NULL fata de baseline); S4-2 (functii Oracle remainder/plafon) INCHISA SI PROBATA, 24.08.2026 (114 randuri numai adaugate in `PACK_FACTURARE`, zero stergeri); S4-3 (cautare in linie, `ofacturare_cautare.prg` nou) INCHISA SI PROBATA, 27.08.2026, teste 41/0, 50/0, 39/0; S4-4 (decuplare Rol A, decizia 6 varianta C) LIVRATA, PROBA MANUALA DATORIE, test paritate 18/0; **S4-5 (Rol B) PARTIALA** — garda `If Used(lcCursor)` in `do_sterge` LIVRATA (repara bug LIVE preexistent, test 10/10), dar plafonul Rol B pe tipul `23` a fost implementat, testat si **REVENIT** in aceeasi sesiune (garda structural moarta); ramane deschis prin deciziile 7 si 8 din handoff §2 (nedecise) [^2] | `docs\raport_s4_1_aplicare.md`, `docs\scripturi_oracle_13.md`, `docs\cercetare\s4_cautare_articole_server.md`, `docs\raport_s4_3_implementare.md`, `docs\raport_s4_4_vfp_implementare.md`, `docs\raport_s4_4_oracle_varianta_c.md`, `docs\propunere_s4_5_rol_b.md`, `docs\raport_s4_5_implementare.md` |
+| S4b | Bara de butoane si meniul de adaugare | `ofacturare.vc2` | S4 | **INCHISA FARA COD** — decizia 9 varianta 3 (31.08.2026): mecanismul v2 (`but_incarca_articole` -> `do_incarca_articole`) e pastrat neatins; alegerea selectiva devine poveste separata (datoria 19) | `docs\propunere_s4b_bara_butoane.md` |
+| S4c | Discount pe linie, mutat din dialog in grid | `ofacturare.vc2`, `ofacturare_comun.prg`, `oproceduri_facturare.prg`, `xmlefactura.prg` | S4 | **LIVRATA, PROBA MANUALA DATORIE** — handlere `LostFocus` pe cele doua campuri de discount + `recalc_discount_linie` nou, camp `procdisc` nou; repara si un defect preexistent (`cProcentDiscount` editabila dar legata la camp inexistent); test 26/0/0, write-back verificat independent | `docs\propunere_s4c_discount_grid.md` |
+| S4d | Data cursului valutar, numai cand are sens | `ofacturare.prg`, `ofacturare.vc2`, `ofacturare_comun.prg` | S4 | **LIVRATA, PROBA MANUALA DATORIE** — metoda noua `do_actualizeaza_vizibilitate_curs`, apelata din 3 puncte (sink comun `do_calculeaza_totaluri`, `Init`, `do_incarca_articole`); test 32/0/0, inclusiv traseul complet al erorii Oracle `-20005`, write-back verificat independent | - |
+| S4e | Lista de preturi si pe factura din comanda | `ofacturare.prg`, `ofacturare.vc2` | S4-1, S4-3 | **INCHISA SI PROBATA** — S4e-1 acoperit de S4-3 (prin `do_adauga_articol_cautat`, acceptat de Marius ca solutie finala, nu se redeschide); S4e-2 GATA (decizia 44); S4e-0 GATA 31.08.2026 (deblocarea `do_adauga_articol`); S4e-3 GATA 31.08.2026 (validare cantitate/stoc, tipurile `3,4,21,25,28,42,47`, test 62/0/0); S4e-4 GATA (proba de neregresie a registrului, fara cod nou, test 15/0/0); S4e-5 GATA (probe repetate pe tip 4/21 + captura dialog, test 37/0/0) | `docs\nota_executie_s4e.md`, `docs\recon_s4e_stare_reala.md`, `docs\raport_s4e_2_implementare.md`, `docs\raport_s4e_0_implementare.md`, `docs\raport_s4e_3_implementare.md`, `docs\raport_s4e_4_implementare.md` |
+| S4f | Returul in formularul unificat | `ofacturare.vc2` | S2, S4e | **INCHISA** (08.09.2026) — stare veche din acest tabel depasita, vezi `docs\handoff_plan13_executie_continua.md` §4.0; `do_adauga_articol_cautat` deleaga returul (tip 8/9/41) la `do_adauga_articol` | `docs\raport_s4f_retur.md` |
+| S4g | Adaugare articole la modificarea documentului | `ofacturare.vc2`, `ofacturare_comun.prg` | S4e + deciziile de mai sus. Nu blocheaza etapa I | **INCHISA** (08.09.2026) — stare veche din acest tabel depasita, vezi `docs\handoff_plan13_executie_continua.md` §4.0; decizia 34/optiunea B aplicata (Oracle `FACT-032` + VFP `deriva_cont_venit_fara_pol`) | `docs\raport_s4g_oracle.md`, `docs\raport_s4g_vfp.md` |
+| S5 | Acoperirea tuturor tipurilor de document | `ofacturare.prg` | S4 | **INCHISA SI PROBATA**, 01.09.2026 — cod COMUN `1f89c18` (v2), teste conform §6 al handoff-ului | `docs\propunere_s5_acoperire_tipuri.md`, `docs\matrice_goluri_s5_form2.md`, `docs\verificare_s5_tabel_sursa.md` |
+| S5b | Proforma si copierea pe formularul unificat | `ofacturare.prg`, `ofacturare.vc2`, `ofacturare_comun.vc2`, `oproceduri_facturare.prg` | S5 | **INCHISA SI PROBATA**, 01.09.2026 — COMUN `76e7398` (emiterea proformei pe formularul unificat, v2) + `d6cae36` (v1, calea de copiere); teste `080321f` (UI, 20/0/2) + testul de rutare (22/0/0). Ramane o singura datorie neblocanta: clauza de gestiune probata prin paritate, nu prin `id_gestiune > 0` (M3) | `docs\propunere_s5b_proforma_copiere.md`, `docs\raport_s5b_implementare.md`, `docs\raport_verificare_s5b_disc.md` |
+| S5c | Factura din proforma (decizia 43) | `cmd_butoane.vc2`, `ocomenzi.vc2`, `ofacturare.prg`, `ofacturare.vc2`, `ofacturare_comun.prg`, `ofacturare_comun.vc2`, `ofacturare_editare.prg`, `oinit_optiuni.prg`, `xmlefactura.prg` | S5b | **INCHISA SI PROBATA**, 01.09.2026 — proba capat-la-capat prin UI RULATA, 20/0/2; vezi si golul de produs semnalat separat (nu al lui S5c) in handoff §4.0a | `docs\raport_s5c_test_ui.md` |
+| S6 | Test pe flux real - formularul unificat | (test, nu cod nou) | S5 | **PARTIALA** — INCHIS 02.09.2026 cu proba partiala: **4 din 7** surse au acum comparatie v1/v2 pe document real emis (0/7 la pornire), **7 defecte de productie gasite, 6 reparate si comise** (3 cu proba doar partiala) | `docs\raport_s6_flux_real.md`, `docs\propunere_s6_test_flux_real.md`, `docs\raport_s6_1_lista_preturi.md`, `docs\raport_s6_3_aviz_retur.md`, `docs\raport_s6_4_transfer.md`, `docs\raport_s6_5_valuta.md`, `docs\raport_s6_6_listare_intrare.md` |
+| S7 | Actiunea si garzile | `ofacturare_comun.vc2`, `ofacturare_editare.prg` | S6, si inchiderea perimetrului cu #6 | **INCHISA SI PROBATA**, 02.09.2026 — cod revizuit integral si comis, COMUN `70eddfa`; cele 5 cerinte de review inchise (cens octeti 13=13, metoda cu toate cele 3 inregistrari). Metoda ramane schela, fara apelant, pana cand S8 cableaza a treia optiune de meniu | `docs\propunere_s7_actiune_garzi.md`, `docs\raport_s7_actiune_garzi.md`, `docs\verif_s7_doua_fapte.md` |
+| S8 | Incarcarea documentului in formular | `ferestre_cere_date.vc2`, `ofacturare.prg`, `ofacturare.vc2`, `ofacturare_comun.prg`, `ofacturare_editare.prg`, `ofacturare_stoc.prg` | S7 | **INCHISA SI PROBATA**, 02.09.2026 — pasii 1-8 GATA, proba finala `test_s8_editare_incarcare.prg` 307/0, CINCI rulari consecutive identice verificate pe md5/diff. Decizia 1 (`IN_STOC`) INCHISA de Marius (handoff §2). Defect nou, neblocant, in afara perimetrului: **G10 incalcat pentru avize** | `docs\propunere_s8_incarcare.md`, `docs\raport_s8_pas7b_proba.md`, `docs\raport_s8_defect5_incasat.md`, `docs\nota_s8q_aplicare_etapa6.md` |
+| S8b | Rutarea scrierii dupa schimbarea tipului | `ferestre_cere_date.vc2`, `ofacturare.vc2` | S8 | **INCHISA SI PROBATA**, 03.09.2026 — rutarea scrierii la editare, COMUN `0a41327`, ROAF `e5530fe`; proba 54/0, trei rulari consecutive identice, toate cele patru rute exercitate pe traseul real | `docs\raport_s8b_implementare.md` |
+| S8c | Buton comutator antet + salvare separata | `lb_tx.vc2`, `rulaje.vc2` | S8 | **NEINCEPUT** — mentionata in handoff doar ca alternativa paralela posibila cu S9 (mai mica, poate rula in paralel), fara cod scris pana acum | - |
+| S9 | Stergere + reemitere intr-o tranzactie, `ID_FACT` pastrat | `oscrie_in_fisiere.prg` | S8b | **PARTIALA — IN LUCRU (03.09.2026)** — S9-1..S9-7 INCHISE SI PROBATE (S9-6 `PACK_CONTAFIN.nIdFactFortat` aplicat/probat pe `MARIUSM_AUTO`; S9-7 cablaj VFP aplicat si probat, sweep P1-P6/CN1-CN4 verde, COMUN `658acc6`/`cc79734`, ROAF `5886b3f`/`119474e`). **S9-8** (testul de flux: reemitere identica + cu modificari, pe aviz/comanda/contract/ELSE) **IN LUCRU** in aceasta sesiune. Datorii neinchise: proba vizuala UI dupa scoaterea garzii, neregresia pe ROACONTRACTE pentru scriptul #9 | `docs\propunere_s9_stergere_reemitere.md`, `docs\propunere_s9_6_pack_contafin.md`, `docs\propunere_s9_7_cablare_idfact.md`, `docs\raport_s9_7_oracle.md`, `docs\raport_s9_7_vfp_aplicare.md`, `docs\raport_s9_7_vfp_proba.md` |
+| S10 | Pretul care nu trebuie re-derivat | `ofacturare.prg`, `ofacturare.vc2`, `ofacturare_editare.prg` | S9 | **NEINCEPUT** — decizia 3 (`PROC_TVAV` ca parametru) care il blocheaza e INCHISA (handoff §2), deci pornirea nu mai e conditionata de o decizie in asteptare | - |
+| S11 | Legaturile ramase pe `ID_VANZARE` | (verificare + cod punctual, vezi plan) | S9 | **NEINCEPUT** | - |
+| S12 | Test pe flux real - regenerarea | (test, nu cod nou) | S10, S11 | **INCHISA** - criteriul (toate cele patru familii trec scenariul B) atins prin sweep 4/4 pe `test_s9_8_flux.prg`, 04.09.2026 | `docs\raport_s12_inchidere.md` |
+| S14 | Audit: creare, modificare, stergere document | `ofacturare_editare.prg` | S9 | **INCHISA**, 04.09.2026 — criteriul din plan bifat pe date reale (documentele reemise 1195/1196); vezi datoriile deschise in raport | `docs\raport_s14_oracle.md`, `docs\raport_s14_vfp_transport.md`, `docs\raport_s14_vfp_grid.md`, `docs\raport_s14_inchidere.md` |
+| S13 | Diff, review, changelog, documentatie | toate cele de mai sus (inchidere de etapa) | toate stories anterioare - livrare finala | **NEINCEPUT** | - |
+
+[^1]: In plus, nedus in niciun raport separat pana acum: `lb_total_mod` e cod viu dar inert
+(`docs\raport_s3b_lb_total_mod.md`, recomandat pentru alta poveste); euristica „205/210 dezalinieri
+de coloana" din `verifica_grila.ps1` ramane neinvestigata.
+
+[^2]: Tipul `41` (S4-5) ramane definitiv in afara perimetrului curent — fix-ul necesar e proiectat
+in `docs\propunere_s4_5_rol_b.md` §7, dar nefacut, ca sa nu arate tacit stoc din gestiuni gresite.
+
+## Firul geometrie (designer editabil)
+
+Firul separat, comis tot pe `plan13-s2`, prin care Marius poate aranja controalele formularului cu
+mana in designerul VFP (`docs\sinteza_designer_editabil.md`). A folosit intern aceleasi litere
+`S6`/`S7`/`S8b`/`S8c` in documentele lui proprii (`docs\handoff_s6_designer_editabil.md`,
+`docs\handoff_s7_containere.md`, `docs\handoff_s8b_transa_a_si_ghid.md`,
+`docs\handoff_s8c_transa_c.md`) si, intr-o etapa ulterioara, etichetele `S8h`-`S8p`/Etapa 6 — **fara
+nicio legatura** cu povestile din tabelul de mai sus. Randurile de aici sunt rasfrangerea acelei
+etape ulterioare (sursa: `docs\handoff_plan13_executie_continua.md` §3); tot firul e **INCHIS SI
+COMIS**.
+
+| Bloc | Ce | Stare | Commit |
+|---|---|---|---|
+| S8-geometrie-h..m | Ancorare nativa vs. geometrie din cod; bitul `Bottom(4)` scos de pe controalele asezate din cod | **INCHISA** | COMUN `e2eca46` |
+| S8-geometrie-n | Test de geometrie mutat din scratchpad in arborele de teste | **INCHISA SI PROBATA**, 8/8 pasi | COMUN `4063277`, ROAF `20eb547` |
+| S8-geometrie-p | Dependenta rupta reparata: `Clase\ofacturare_util.vc2` intrat in versionare + `SET CLASSLIB` in `roafacturare.prg` | **INCHISA** — fara ea, `plan13-s2` era rupt la checkout curat | ROAF `fe3eef8` |
+| S8-geometrie-o | Proba de rezolutie 1366x768 + diagnosticul benzii de totaluri | **INCHISA SI PROBATA** — la 1366x768 maximizat, deficit 98px, preexistent, nu regresie | COMUN `261f547`, ROAF `6257df6`, `3b312a0` |
+| Etapa 6 | 5 fisiere de test reparate (`ObjExists` facut recursiv in 3; substitutia `opt_incasat.Value` -> `seteaza_mod_incasare` aplicata doar pe siturile formei NOI) | **INCHISA SI PROBATA** — `test_s3b_emitere_paritate_2` 20/0, `test_s3b_emitere_reala` 1/0, `test_s3_controale` 20/0, zero aparitii ale erorii 1734 | COMUN `34a1f30` |
+
+## Ordinea de executie rezultata din dependente
+
+```
+S1 (GATA)
+ -> S2 (GATA implementare, in asteptare review/aprobare)
+ -> S3c (paralel cu S3, atinge alt fisier comun - nu impreuna cu alta modificare)
+ -> S4e (STALE: aici in arbore ca "porneste dupa S2"; depinde de fapt de S4-1 si S4-3 -
+ vezi randul S4e din tabel si `docs\nota_executie_s4e.md` §6)
+ -> S4f (dupa S4e)
+ -> S3
+ -> S3b
+ -> S4 (proiecteaza intai punctul 2, neproiectat)
+ -> S4b
+ -> S4c
+ -> S4d
+ -> S4g (dupa S4e + deciziile anterioare; nu blocheaza etapa I)
+ -> S5
+ -> S5b
+ -> S5c
+ -> S6 (test pe flux real)
+ -> S7 (dupa inchiderea perimetrului cu #6)
+ -> S8 (varianta IN_STOC fixata in nota de executie S8, runda 17)
+ -> S8b
+ -> S9
+ -> S10
+ -> S11
+ -> S14
+ -> S12 (dupa S10 si S11)
+ -> S8c
+ -> S13 (inchidere finala, dupa toate)
+```
+
+Observatii pe ordine:
+- S3c si S4e nu depind de S3/S4 - pot fi luate in paralel cu ramura S3, dar **un singur scriitor pe
+ fisier**: S3c atinge `ofacturare.prg`/`oproceduri_facturare.prg`, S2 le-a atins deja si le-a
+ eliberat (S2 e inchisa la nivel de implementare), deci nu se suprapun.
+- S4g explicit "nu blocheaza etapa I" - poate aluneca dupa S6/S7 fara sa opreasca lantul principal.
+- S8c e paralela cu S9 (ambele depind doar de S8), dar scrie in fisiere diferite (`lb_tx.vc2`,
+ `rulaje.vc2` vs `oscrie_in_fisiere.prg`) - fara conflict de scriitor.
+- **Starea reala la 03.09.2026** (handoff §6): lantul e dus pana la S9 (S9-1..S9-7 inchise,
+ S9-8 in lucru); ordinea ramasa e **S10 -> S11 -> S12 -> S14 -> S13**, cu **S8c** paralela.
+ Actualizare 04.09.2026: **S12 inchisa** (`docs\raport_s12_inchidere.md`) - vezi §4.0 al
+ handoff-ului pentru starea curenta. **S14 inchisa** (`docs\raport_s14_inchidere.md`) - ramane
+ doar **S13** (inchiderea de etapa), cu **S8c** in continuare paralela.
+
+## Cele 3 puncte de implementare ramase deschise — TOATE INCHISE (handoff §2, 31.08.2026)
+
+Sursa initiala: `docs\handoff_13_formular_unificat.md`. Cele trei decizii ale lui Marius care le
+inchid sunt in `docs\handoff_plan13_executie_continua.md` §2.
+
+1. **Relistarea unei facturi vechi deja trimise** (decizia 62) — **INCHISA**: toate facturile se
+ tiparesc dupa regula noua, fara versionare dupa data. Facturile trimise la ANAF nu se mai pot
+ retrimite.
+2. **`PROC_TVAV` ca parametru** (consecinta 3 a deciziei 54) — **INCHISA, DA devine parametru**:
+ caile de copiere si modificare pastreaza cota documentului original; blocheaza S10.
+3. **De unde se reconstituie `IN_STOC`** — **INCHISA, varianta (2)**: valoarea curenta din
+ nomenclator, fara migrare DB si fara reconstituire din rulaje; blocase S8, acum livrat si probat.
diff --git a/docs/plan_13_unificare_formular_facturare.md b/docs/plan_13_unificare_formular_facturare.md
index 8e8d007..d896f9a 100644
--- a/docs/plan_13_unificare_formular_facturare.md
+++ b/docs/plan_13_unificare_formular_facturare.md
@@ -1,4254 +1,4610 @@
-# Plan #13 — formular unificat de facturare + editare prin regenerare
-
-Sursa: `COMUN\docs\todos.txt` punctul 13.
-Mockup: `docs\mockup_13_formular_unificat.html` (versiunea 5).
-Cercetare pe cod, toata in `docs\cercetare\`: `inventar_controale_formulare.md`,
-`proforma_copiere_puncte_intrare.md`, `import_roris_roaacnpro.md`, `discount_pe_articol.md` si
-`discount_verificare2.md` (a doua il corecteaza pe primul), `modifica_antet_bifa.md`,
-`valuta_si_curs.md`, `buton_comutator_picture.md`, `modifica_date_factura_parametri.md`,
-`retur_si_lista_preturi.md`, `factura_retur_document.md`, `roaauto_facturi.md`,
-`roaauto_articole_lista_preturi.md`, `cont_venit_articol_fara_politica.md`.
-Stare: **propunere, neinceput**. Analiza facuta pe cod la 09.08.2026, in sase runde.
-
-## Cerinta, asa cum a fost formulata
-
-Trei lucruri intr-un singur punct:
-
-1. **Unificarea formularelor** — `date_factura` / `date_aviz` sa intre in formularul de facturare,
- ca sa nu mai fie doua ferestre pentru acelasi document.
-2. **Fara incarcarea prealabila a tuturor articolelor** din toate politicile de preturi — pot fi mii
- si dureaza mult aducerea lor de pe server.
-3. **Editarea facturii / avizului prin regenerare**, in toate variantele (politici de preturi,
- comanda, contract, aviz): formularul se redeschide completat ca inainte de salvarea initiala, se
- fac modificarile ca la introducere, iar la confirmare documentul initial se marcheaza `sters = 1`
- si se salveaza unul nou — ca sa se vada ce s-a modificat.
-
-Decizia lui Marius, 09.08.2026: **intai unificarea, apoi editarea prin regenerare.** Explicit
-**nu** pe calea editarii directe a notelor / rulajelor / articolelor.
-
-## Deciziile lui Marius, 09.08.2026 — luate, nu de reluat
-
-1. **#13 coexista cu #6**, nu il inlocuieste.
-2. **`ID_FACT` se pastreaza**, ca la orice modificare. Documentul reemis nu-si schimba identitatea.
-3. **Toate datele se pastreaza, inclusiv numarul documentului.** Scopul e modificarea documentului,
- nu emiterea altuia.
-4. **Antetul care intra in generarea lui `ID_FACT` (serie, numar, data) are cale proprie de
- modificare** — nu trece prin regenerare.
-5. **Un singur formular, aceeasi infatisare la introducere si la modificare.** Fara banda de
- avertisment, fara coloane cu valorile initiale, fara panou de diferente.
-6. **Se integreaza si modificarea de antet, si modificarea de articol care exista azi** — sa nu
- ramana trei actiuni de modificare pe acelasi document.
-
-## Deciziile lui Marius, runda 3 (09.08.2026) — luate, nu de reluat
-
-7. **`frm_alte_date` intra in formular**, in sectiunea pliata. Se inchide intrebarea ramasa deschisa
- in runda 2 (recomandarea de atunci — „ramane dialog” — **cade**).
-8. **Sectiunea pliata primeste in plus analiticele**: venit / cheltuiala, sectie, responsabil (si,
- prin simetrie, lucrare). Antetul vizibil ramane aerisit, cu **controalele grupate** pe intelesuri,
- nu insirate.
-9. **Un singur buton comutator pe antet.** Antetul se deschide blocat. Un singur `but_modifica`
- (creionul) il deblocheaza si **isi schimba imaginea in discheta lui `but_salvare`**; a doua
- apasare salveaza **doar antetul** si il blocheaza la loc. Un singur control, nu bifa plus buton —
- mai compact. **Toata factura se salveaza in continuare din `Termina`.** Rostul ramane acelasi:
- antetul se editeaza intentionat, nu din greseala, si se poate corecta fara a trece prin articole.
-
- **Butonul singur deschide tot antetul. Nu mai exista bife individuale** — nici cele patru de azi
- (serie / numar / data / scadenta). Un singur control comanda toata protectia antetului.
-
- *Istoric, ca sa nu se reia:* runda 3 propusese un buton `Modificare / Salveaza` care bloca **tot
- documentul** — respins, protectia e doar pe antet. Runda 4 propusese **bifa + buton separat** —
- respins la 09.08.2026 in favoarea butonului comutator. Runda 5 propusese **pastrarea celor patru
- bife individuale sub buton** — respins la 09.08.2026: bifele dispar cu totul.
-
- **Verificat pe cod la 09.08.2026** (`docs\cercetare\buton_comutator_picture.md`): **tiparul exista
- deja in suita si se copiaza, nu se inventeaza.** `frm_rulaje.se_modifica_assign`
- (`COMUN\clase\rulaje.vc2:4716-4773`) comuta exact asa **o singura instanta** de `but_modifica`
- intre creion si discheta — nu instantiaza a doua clasa. Trei lucruri de retinut din el:
- - se rescriu **impreuna** `.cpicturedown`, `.cpictureup` **si** `.Picture`, plus `.ToolTipText`,
- urmate de `.Refresh()`. Numai `.Picture` nu ajunge: hover-ul standard din
- `buton.MouseEnter` / `MouseLeave` (`_cmd_base.vc2:88-97`) rescrie `Picture` din `cPictureUp` /
- `cPictureDown`, deci iconita veche ar reveni la primul mouse-over;
- - numele de fisier se dau **fara cale** (`"save_sus.bmp"`), rezolvate prin `SET PATH` — care
- include si `GRAFICE`, si `COMUN\GRAFICE` (`Programe\roafacturare.prg:85-108`). Calea relativa
- `..\grafice\...` din clasa e buna doar la design-time;
- - imaginile exista: `COMUN\grafice\save_sus.bmp` / `save_jos.bmp` (discheta),
- `modific_sus.bmp` / `modific_jos.bmp` (creion, perechea folosita de clasa).
-
- Clasa de salvare din biblioteca se numeste **`but_salveaza`**, nu `but_salvare`
- (`cmd_butoane.vc2:340-352`); e sursa numelor de imagini, dar nu se instantiaza. Clasa
- `but_modifica` e la `cmd_butoane.vc2:184-198`. Butoanele **nu** au `do_activeaza` /
- `do_dezactiveaza` — pe ele se lucreaza direct pe `.Enabled`.
-
- **Consecinta asupra celor patru bife individuale** (serie / numar / data / scadenta, vezi I):
- **se elimina**, si **odata cu ele se abandoneaza si conditia lor** de azi
- (`chkSerieAct.Enabled = !EMPTY(NVL(poRec.numar_act,0))`, `ofacturare_comun.vc2:5736-5750`).
- Decis de Marius la 09.08.2026: **butonul deschide tot**, fara conditii pe camp. Un singur control,
- o singura regula. Cat de departe merge „tot” — vezi **decizia 19**: exact cat scrie
- `modifica_date_factura`, parametru cu parametru.
-10. **Proforma foloseste acelasi formular.**
-11. **Copierea foloseste acelasi formular**, ca document nou, cu antetul editabil.
-12. **Formularul trebuie sa *poata* fi apelat cu sursa deja completata** — din pagina de comenzi cu
- comanda, si din programul de contracte cu contractul, fara ca utilizatorul sa mai aleaga ulterior.
- **Nu se integreaza contractele acum**; nu depinde de #10.
-13. **Un singur buton de adaugare a articolelor, cu `xmenu()`** — nu doua butoane separate „adauga
- tot” si „alege”. Optiunile din meniu se schimba dupa sursa si acopera **comanda, contractul si
- avizele**, cu alegere selectiva acolo unde are sens (de exemplu o singura rata de contract).
- Butoanele de linie stau deasupra tabelului.
-14. **Discountul pe articol, procent si valoare absoluta**, amandoua accesibile.
-15. **Data cursului valutar apare doar cand are sens.** Sunt doua concepte diferite, care azi impart
- acelasi camp mereu vizibil: (a) **factura in valuta**, unde si articolele au pret in valuta, si
- (b) **factura in lei cu articole care pot avea pret in valuta**, convertite in lei la cursul din
- data cursului, cu documentul si contabilitatea in lei. Formularul trebuie sa fie **ergonomic si
- simplu** — campul nu apare cand nu e nimic de convertit.
-
-### Deciziile lui Marius, runda 6 (09.08.2026)
-
-16. **Lista de preturi e disponibila mereu, indiferent de sursa — si liniile suplimentare se pot si
- sterge.** Pe o factura din comanda sau din contract trebuie sa se poata **adauga si sterge**
- articole libere din lista de preturi, nu doar articole din sursa. Cazul real, formulat de Marius:
- clientul a comandat ceva, iar la facturare mai vrea ceva in plus sau vrea sa schimbe — deci
- documentul trebuie sa poata devia de la comanda, in ambele sensuri. Sursa umple documentul, nu il
- inchide. Optiunea „Cauta in lista de preturi…" ramane in meniul butonului de adaugare **pentru
- toate sursele**, inclusiv pentru documentele deja emise care se modifica.
- **Verificat pe cod** (`docs\cercetare\retur_si_lista_preturi.md`, B): **contractul o are deja**
- (`crsarticole` e populat de `cursor_preturi` / `cursor_contract` cu lista intreaga, al doilea grid
- e un adaos, nu o restrictie), **comanda nu** — `cursor_comanda` umple `crsarticole` **doar** cu
- articolele comenzii (`ofacturare.prg:266-308`). Deci golul real e pe comanda, si e in **continutul
- cursorului**, nu in vreun `Visible` de buton. Reteta exista deja in produs: ramura de copiere
- adauga lista de preturi peste cursorul sursei cu `APPEND FROM` (`ofacturare.prg:454-473`) — se
- generalizeaza ea, nu se inventeaza alta.
-17. **Returul intra in formularul unificat, cu tot cu alegerea facturilor sursa.** Factura de retur
- facuta din facturi anterioare e un caz de acoperit explicit — lipsea si din mockup, si din
- proiectare. *Vezi sectiunea N.*
- **Sunt doua mecanisme distincte, si prima cercetare l-a vazut doar pe al doilea:**
- (a) **factura de retur ca document** (tipurile 8, 9, si avizul 24) — alege facturile sursa **la
- nivel de document**, cu selectie multipla, si isi populeaza liniile din ele; **gestiunea si
- pretul de achizitie vin neschimbate din linia originala**, verificat in `cursor_retur_document`.
- **Exista deja si merge** — nu se reproiecteaza. Vezi N.1;
- (b) **`But_retur`** — retur de articole intr-o factura de vanzare normala (tipurile 1, 5, 7, 10),
- unde factura sursa se alege **per articol**, iar gestiunea nu se mosteneste, ci se alege. Vezi N.2.
- Sunt doua fluxuri de cod independente, fara punct comun. Decizia 17 le duce pe amandoua in
- formularul unificat; ce se proiecteaza nou e (b) ridicat la nivel de document, nu (a).
-18. **Facturile emise din ROAAUTO intra in perimetru la modificare.** ROAAUTO le emite din formularul
- lui, dar scrie tot in `VANZARI_DETALII`, si pe ele trebuie sa se poata adauga articole din lista
- de preturi. **Emiterea ramane la ROAAUTO** — se unifica doar modificarea.
- **Verificat pe cod** (`docs\cercetare\roaauto_facturi.md`): acelasi `PACK_FACTURARE`, acelasi drum
- `VANZARI_DETALII_TEMP` -> `VANZARI_DETALII`, tip de document **`-12`**, pe care editorul lui #6 il
- **vede deja**, testat pe date reale.
- **Precizarea lui Marius, 09.08.2026, verificata pe cod**
- (`docs\cercetare\roaauto_articole_lista_preturi.md`): in ROAAUTO **exista deja adaugarea de
- articole reale**, pe langa liniile generice — mecanismul „Alte servicii” din `frm_incasare_finala`.
- Deci descrierea „doar linii sintetice cu `id_articol` negativ” din primul raport e **incompleta**.
- Nuanta care conteaza pentru proiectare: sursa lui e **nomenclatorul brut**, nu lista de preturi,
- articolele oferite sunt **fara stoc** (`in_stoc = 0 and in_crm = 1`), iar **pretul se tasteaza
- manual** — nu vine din politici. Ce se cere e ca **acelasi lucru sa fie posibil si la modificarea
- documentului**, nu doar la emitere, **si nu numai pentru facturile auto, ci pentru orice tip**,
- cu **ambele surse**: lista de preturi (cu pret calculat) sau nomenclatorul (cu pret tastat).
- **Vezi O.**
-19. **Toti parametrii lui `modifica_date_factura` trebuie sa fie modificabili din butonul de antet.**
- Butonul comutator nu deschide un subset ales de noi: daca procedura Oracle stie sa scrie un camp
- de antet, formularul trebuie sa aiba controlul prin care acel camp se poate schimba.
- **Verificat pe cod** (`docs\cercetare\modifica_date_factura_parametri.md`): sunt 15 parametri,
- din care **14 sunt campuri** — al 15-lea, `V_ID_VANZARE`, e identitatea randului si nu se
- editeaza. Din cele 14:
- - **13 au deja control** in `frm_modifica_factura` si se muta ca atare in antetul unificat;
- - **`V_EFACTURA` nu are niciun control nicaieri** (`ofacturare_comun.vc2:4576` il forteaza `0`
- la selectie multipla, altfel vine din `Scatter`) — **primeste unul**, e singurul camp nou-nout
- cerut de decizia asta;
- - `V_TIP_SAFT` are control, dar ascuns dupa `gl406` (`:5739-5741`) — ramane conditionat, nu se
- forteaza vizibil.
- Vezi I-bis pentru contractul procedurii, care impune si **cum** se cheama, nu doar ce se trimite.
-20. **Din nomenclator se aleg si articole gestionabile, si negestionabile.** Filtrul `in_stoc = 0`
- al lui ROAAUTO **nu se preia** — acolo e o ocolire a subiectului gestiunii, nu o regula de produs.
- Consecinta acceptata: pe documentele auto vor coexista linii care descarca stoc cu linii care nu
- descarca, caz care azi nu exista nicaieri. *Vezi J si O-bis, intrebarea 2.*
- **Intrebarea care insotea decizia — „cu ce cont de venit intra un articol fara politica de pret”
- — s-a inchis prin cercetare: nu exista cont de venit pe linie.** Vezi **J-bis**.
-
-### Deciziile lui Marius, runda 7 (09.08.2026)
-
-21. **Cand `NOM_ARTICOLE.CONT` e gol pe un articol negestionabil, se aplica un fallback la un cont
- implicit.** Nu se accepta `NULL` (comportamentul de azi al liniilor „Alte servicii" din ROAAUTO) si
- nu se refuza adaugarea articolului. Contul anume se alege la implementare.
- **Atentie la perimetru:** decizia priveste **contul de gestiune** (`VANZARI_DETALII.CONT`). Cand a
- fost luata nu se stia inca faptul, stabilit mai tarziu in aceeasi runda, ca pe linie exista **doua**
- conturi cu surse diferite — cel de venit (`NOTE_CONTABILE.SCC`, prin politica de pret) nu e acoperit
- de aceasta decizie si e inca deschis. *Vezi J-bis.*
- Ipoteza de la care a pornit Marius — corespondenta 3xx -> 7xx dintr-un tabel — **nu s-a confirmat
- ca tabel**, dar intentia ei da: legatura articol -> cont de venit exista, prin politica de pret si
- `NOTE_CONTABILE`, configurata manual de contabil.
-22. **Linia de retur fara factura originala e permisa.** Pe tipurile 8, 9, 24, „Cauta in lista de
- preturi…" si „Alege din nomenclator…" se comporta ca pe orice alt document — nu apar doar pentru
- corectii si nu sunt marcate special. Consecinta acceptata: gestiunea si pretul de achizitie se
- aleg (nu se mostenesc), iar maximul returnabil de pe server nu se aplica acelei linii. *Vezi N.3.*
-23. **Secventierea deciziei 18: `pack_auto` se cerceteaza acum**, inainte de orice estimare, nu cand ii
- vine randul la livrare. *Vezi O, „Secventierea".* **Rezultat:** riscul tehnic nu exista —
- `PACK_AUTO` nu citeste `VANZARI` / `VANZARI_DETALII` deloc. Decizia 18 nu mai trebuie sa fie ultima.
-24. ~~**Articolul ales din nomenclator primeste `id_pol`-ul unei politici de pret implicite.**~~
- **RETRASA in runda 8, inlocuita de decizia 27.** Ramane in plan doar ca sa nu fie reintrodusa:
- politica implicita ar fi evitat codul nou in `pack_facturare`, dar cu pretul unei intrebari de
- configurare cu contabilul si al unui cont de venit uniform pentru orice articol adaugat asa.
- Marius a ales in loc corespondentele `CORESP_CONT_VENCHELT`. *Vezi decizia 27 si J-quater.*
-25. **Butonul de antet deschide tot; ce nu se poate salva pe loc forteaza regenerare.** La a doua
- apasare, cei **14 parametri** merg prin `modifica_date_factura`, iar orice camp schimbat din
- **grupul B** (tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi)
- sau **C** (incasare) **marcheaza documentul pentru regenerare**, aplicata la `Termina`. Decizia 9
- ramane intacta ca intentie — butonul chiar deschide tot antetul —, dar ruta de scriere se bifurca
- dupa camp, nu dupa buton. *Vezi G-bis.*
- **Consecinta pe etape:** in **etapa I** regenerarea nu exista inca, deci acele campuri nu au unde
- sa se salveze. **Planul le tine blocate in etapa I**, cu explicatie la hover, si le deschide odata
- cu etapa II. Motivul alegerii, in lipsa unei instructiuni contrare: un camp care se deschide dar nu
- se salveaza e o capcana — pierderea tacuta a unei modificari e mai rea decat un camp inca blocat.
-26. **Analiticele raman read-only in #13; editarea lor e a lui #6.** Venit/cheltuiala, sectie,
- responsabil si lucrare se **afiseaza** in sectiunea pliata, cu valoarea de antet, dar nu se
- editeaza din formularul unificat — cine vrea sa le schimbe trece prin editarea notei contabile.
- Motivul: sunt deja editabile acolo, **la nivel de linie de nota**, iar #13 le-ar scrie uniform pe
- tot documentul — doua ferestre care scriu acelasi camp cu semantici diferite, cu risc ca #13 sa
- suprascrie tacit o diferentiere facuta din #6. **Zero suprapunere intre fire.** *Vezi G-bis.*
- Asta **nuanteaza decizia 8**: analiticele intra in sectiunea pliata ca **afisare**, nu ca editare.
-
-### Deciziile lui Marius, runda 8 (09.08.2026)
-
-27. **Contul de venit vine din corespondente si din nomenclator, nu dintr-o politica de pret
- implicita. Decizia 24 se retrage.** Regula, pe doua ramuri:
- - **articol gestionabil** (cont de gestiune de clasa 3xx): contul de venit se ia din tabelul de
- corespondente `CORESP_CONT_VENCHELT` — `select id_ccv, cont, cont_chelt, cont_venit, sters,
- dataoras, cont_aprovizionare, cont_diferente from coresp_cont_venchelt`, cautand pe `CONT`
- (contul de gestiune al liniei) si luand `CONT_VENIT`;
- - **articol negestionabil**: se foloseste `NOM_ARTICOLE.CONT` **daca e deja un cont de clasa 7xx
- sau 6xx**; altfel, implicit **704**.
-
- Motivul respingerii politicii implicite: ea muta problema in configurare (cine creeaza politica,
- cu ce `SCC`, una sau mai multe) si obliga la o intrebare cu contabilul inainte de orice livrare.
- Corespondentele exista deja ca date de productie si leaga contul de gestiune de cel de venit —
- exact relatia cautata, doar ca sub alt nume decat s-a cautat in runda 7.
-27-bis. ~~**Regula din 27 se implementeaza FARA cod nou in `pack_facturare`.**~~ **RELAXATA de decizia
- 34 si inchisa de decizia 35** — pachetul se modifica punctual, si e singurul cod de contare, si la
- emitere si la editare. Textul de mai jos ramane doar ca istoric al rationamentului.
- (Marius, runda 8, dupa
- prima formulare a lui 27). Motivul: pachetul e mare si e folosit de toate produsele suitei — o
- ramura noua acolo e un risc peste tot, nu doar in ROAFACTURARE.
- Deci **regula de derivare a contului de venit se aplica pe partea VFP**, inainte ca articolul sa
- plece spre Oracle, iar `contabilizeaza_articol` ruleaza **neschimbata**. Calea de verificat:
- VFP calculeaza contul de venit dupa regula de mai sus si alege un `id_pol` a carui nota are deja
- acel `SCC`, astfel incat `FACT-024` sa nu se mai poata declansa.
- **Modificarea pachetului ramane planul B**, folosit doar daca se dovedeste ca nu exista nicio cale
- dinspre VFP. *Vezi J-quater;* fezabilitatea: `docs\cercetare\coresp_cont_venchelt.md`, punctul 8.
-
- **PREMISA A FOST VERIFICATA (Marius, runda 8):** „in ROAACNPRO, dar si la factura din comanda /
- contract, se adauga articole fara politica de preturi — de ce nu se poate si aici?" **Raspuns:
- observatia e reala, dar niciunul din cele doua exemple nu e un articol fara politica.** ROAACNPRO
- nu cheama deloc `contabilizeaza_articol` (are propria contabilizare, `pack_acn.salveaza_regdoc`);
- pe contract, articolele vin din `cursor_contract` / `cursor_preturi`, care le livreaza **cu `id_pol`
- atasat**. `FACT-024` ramane blocantul. *Detalii, cu dovezi: J-quater, punctul 1.*
- **REZULTAT: calea VFP exista si e mai buna decat modificarea pachetului** — se sprijina pe un RPC
- existent (`pack_preturi.adauga_politica_pret_art`) si aduce, pe langa `SCC`, si `CU_TVA` /
- `IN_VALUTA`, pe care un fallback in pachet ar fi trebuit sa le hardcodeze. *Vezi J-quater, punctul 3.*
- **Planul B (modificarea `pack_facturare`) se abandoneaza.**
-28. **Pe factura ROAAUTO pot exista si alte articole decat cele de pe deviz.** Nepotrivirea de afisare
- dintre ecranul de deviz si factura retiparita (O, intrebarea 1) **e acceptata**: cerinta e ca
- **MANOPERA si MATERIALE sa fie conform devizului**, plus orice alte articole adaugate. Nu se cere
- cod nou in ROAAUTO ca sa aduca ecranul de deviz la zi. *Vezi O, intrebarea 1.*
-29. **Stergerea unei linii venite din comanda ramane fara protectie.** Linia se sterge ca oricare alta;
- comanda va aparea, corect, ca **facturata partial**. Nu se adauga confirmare, nu se marcheaza
- „refuzat", nu se ajusteaza numararea acoperirii. *Vezi S4e.*
-30. **Nu se coordoneaza cu firul #6.** #13 **incepe dupa ce #6 se termina**, deci suprapunerea pe
- fisiere nu se poate produce si nu e nevoie de impartire de perimetru. Consecinta pe interdictii:
- cele doua fisiere ale lui #6 raman intangibile **cat timp #6 e in lucru**, dar restrictia expira
- odata cu el, nu cere negociere. Decizia 26 (analiticele read-only in #13) ramane in picioare — ea
- tine de semantica, nu de coliziunea de lucru. *Vezi „Relatia cu #6".*
-
-### Deciziile lui Marius, runda 9 (10.08.2026)
-
-**31. Datele din Dev nu sunt baza de proiectare.** Fiecare client isi defineste propriile politici de
-pret, fiecare cu nota ei contabila de vanzare salvata pe un `ID_SET`. Orice masurare pe `MARIUSM_AUTO`
-vale ca **dovada ca un mecanism exista** si ca sursa de concluzii **structurale**, niciodata ca harta a
-ce e configurat la client. Nicio decizie de proiectare nu se sprijina pe numarul de politici sau de note
-gasite pe Dev. *(Generalizeaza regula „zero cazuri in date nu e dovada" in ambele sensuri: nici prezenta
-nu e dovada.)*
-
-**32. Intrebarea de raspuns inainte de orice implementare a contului de venit:** cum alege programul nota
-contabila de vanzare la **factura pe baza de comanda**, care **nu are politica de pret**? Daca acel
-mecanism se poate refolosi pentru articolul adaugat ad-hoc, **reteta in 4 pasi din J-quater se
-abandoneaza** in favoarea lui. Vezi J-quater, „Intrebarea deschisa care poate anula toata reteta".
-
-**34. `contabilizeaza_articol` primeste un parametru de cont contabil. Decizia 27-bis e RELAXATA.**
-Marius, 10.08.2026, textual: *„poți să adaugi parametrul contul contabil la `contabilizeaza_articol`."*
-Consecinta: **reteta in 4 pasi din J-quater se abandoneaza.** Nu mai e nevoie de politica tehnica, nici de
-interogarea inversa pe `SCC`, nici de inserarea articolului in politica. VFP calculeaza contul dupa regula
-deciziei 27 si **il trimite direct**.
-**Ce rămâne de proiectat, si nu e „doar un parametru":** contul nu e singurul lucru care venea de pe nota.
-`cursor_articol` aducea si `SCD`, `CU_TVA`, `IN_VALUTA`, `EXPLICATIE`, `ID_VENCHELT`, `ID_SECTIE`, iar bucla
-care il consuma apeleaza **si** `scrie_nota` **si** `descarca_gestiune`. Pe un articol fara politica,
-`FACT-024` sare inainte. Deci e nevoie de **parametru + ramura fara politica**, care sa furnizeze ce
-furniza nota si sa ruleze `descarca_gestiune` **exact o data**. Obiectia rundei 8 („`CU_TVA` si `IN_VALUTA`
-n-au sursa in afara lui `NOTE_CONTABILE`") **nu mai e blocanta, e proiectare** — de reevaluat daca se pot
-deriva din document.
-**Constrangeri de forma, ca sa nu se strice suita:** parametru nou **cu `DEFAULT NULL`**, la finalul listei,
-si ramura inerta cand lipseste — apelanții existenți nu se schimba. `pack_facturare` e comun **intregii
-suite**, deci cere regresie pe ROACONT / ROAGEST / ROACONTRACTE / ROAAUTO / ROAACNPRO, nu doar ROAFACTURARE.
-**Ramura noua nu moșteneste bug-ul de set multi-rand** din L.0-ter.
-**PROIECTATA** — `docs\cercetare\canal_cont_venit_fara_politica.md`, sectiunea „Proiectarea parametrului
-de cont contabil", liniile 13-227. Verdictul, in trei randuri, pentru ca schimba forma modificarii:
-`contabilizeaza_articol` primeste azi **un singur parametru**, `detalii_articol
-VANZARI_DETALII_TEMP%ROWTYPE` — deci contul **nu intra literal pe ea**, ar fi cosmetic. Intra ca
-**coloana noua `VANZARI_DETALII_TEMP.CONT_VENIT VARCHAR2(4) NULL`**, populata printr-un parametru nou
-`V_CONT_VENIT IN VARCHAR2 DEFAULT NULL` la **coada lui `adauga_articol_factura`** (procedura chemata
-direct din VFP), pe care `contabilizeaza_articol` o primeste automat: cei trei apelanti interni fac
-`SELECT * BULK COLLECT` intr-un `TABLE OF ...%ROWTYPE`, deci `scrie_factura2`,
-`scrie_factura_avize_retur` si `scrie_aviz_retur` **nu se ating deloc**.
-> **Corectie de nume, runda 11 — mecanismul insa rezista.** Al doilea apelant e **`scrie_factura_avize`**
-> (`:6708-6749`), nu `scrie_factura_avize_retur`, care nici nu cheama `contabilizeaza_articol`.
-> **Verificat pe cod ca toti trei apelantii reali** — `scrie_factura2` (`:6039-6063`),
-> `scrie_factura_avize` (`:6708-6749`), `scrie_aviz_retur` (`:7097-7106`) — fac intr-adevar
-> `SELECT * BULK COLLECT INTO` un `TABLE OF VANZARI_DETALII_TEMP%ROWTYPE`, **fara lista explicita de
-> coloane**. Deci coloana noua curge automat prin toti trei si **niciunul nu se atinge**; concluzia
-> proiectarii sta, doar doua din cele trei nume erau gresite. In `scrie_factura_avize`, `tab_detalii(i)`
-> e modificat inainte de apel doar pe `.cantitate` / `.id_rata` — `CONT_VENIT` ramane neatins. Efectul cerut de Marius e exact
-acelasi; doar mecanica de livrare difera de formularea literala. Precedentul e in aceeasi semnatura:
-`V_TAXCODE` si `V_LOT` sunt deja doi parametri adaugati ulterior, la coada, cu `DEFAULT NULL`, iar apelul
-VFP e pozitional si se opreste la `V_LOT`.
-Ramura noua se activeaza pe `detalii_articol.cont_venit IS NOT NULL`, **infasoara si blocul `FACT-024`**
-(garda ramane litera cu litera pe ramura veche: o linie fara politica **si** fara cont trimis cade in
-continuare cu `FACT-024`), n-are cursor deloc — deci `descarca_gestiune` ruleaza **exact o data prin
-constructie** si bug-ul de set multi-rand nu se mosteneste, fara sa se repare ramura veche.
-**Doua hardcodari raman decizii deschise pentru Marius**, nu descoperiri: `SCD = '4111'` si `CU_TVA = 1`
-— vezi „Ce ramane de decis" mai jos.
-
-**VERIFICATA ADVERSARIAL** — `docs\cercetare\parametru_cont_contabilizeaza_articol.md`. Proiectarea
-rezista; patru rezultate schimba insa detalii de executie:
-
-- **Parametrul se cableaza in DOUA locuri VFP, nu unul.** `ofacturare.vc2:14069` si `:18089` **nu** sunt
- o duplicare a aceleiasi metode, cum se presupusese: sunt **doua clase distincte**,
- `frm_facturare_articole.do_scrie_articole` (`:13967-14195`) si
- `frm_facturare_articole2.do_scrie_articole` (`:18003-18221`), fiecare construindu-si separat apelul RPC.
-- **`CU_TVA = 1` nu e inofensiv, cum spunea proiectarea.** Actualizarea lui `nproc_tva_max` /
- `nid_jtva_coloana` / `nTaxCode` e chiar in interiorul lui `IF V_CU_TVA = 1` (`:12537-12558`), iar
- comparatia `nproc_tva_max < V_PTVA` **se uita doar la rata, nu la suma**. O linie fallback cu TVA real
- 0% ar intra deci in comparatia de maxim si, daca e prima linie a documentului (`nproc_tva_max` porneste
- `-1`, `:1885`), **castiga** — iar coloana si taxcode-ul ei ajung sa descrie **linia de discount a
- intregii facturi** (`:6164-6184`). Combinatia e ingusta (linie scutita + discount global + acea linie e
- „maximul" de pana atunci), dar efectul e real. Motivul pentru care decizia ii apartine lui Marius e
- acum concret, nu formal.
-- **`INSERT INTO VANZARI_DETALII ... FROM VANZARI_DETALII_TEMP` are lista de coloane explicita** — 24 de
- coloane, `PACK_FACTURARE:13705-13757`, in `scrie_in_vanzari`. Deci daca se vrea `CONT_VENIT` pastrat si
- dupa fapt in `VANZARI_DETALII`, **lista trebuie extinsa explicit**; altfel coloana traieste doar in
- `VANZARI_DETALII_TEMP` si `ACT_TEMP`.
-- **Articolul compus nu e o gaura in proiectare** — e exclus structural, nu prin presupunere. `COMPUS`,
- asa cum il citeste `contabilizeaza_articol` (`:7279-7283`), e definit in `VCRM_POLITICI_PRET_ART` ca
- proprietate a **perechii (articol, politica)**, identificata prin `ID_POL_ART`. O linie fara politica
- n-are `ID_POL_ART`, deci intrebarea nu se poate pune.
-
-**Golul `ntip = 4` — INCHIS in runda 11.** Cercetat (`docs\cercetare\gol_ntip4_factura_din_avize.md`) si
-**verificat adversarial** (`docs\cercetare\verif_goluri_ntip_aviz.md`). Trei rezultate, dintre care doua
-schimba ce trebuie scris in pachet:
-
-- **`ntip = 4` e exclus structural — dar nu prin garda pe care o presupunea proiectarea.** Blocajul nu e
- `FACT-024` din `contabilizeaza_articol`, ci **o functie mai devreme**: `adauga_articol_factura`, ramura
- `WHEN ntip = 4` (`:5080-5103`), cauta randul sursa din `VANZARI_DETALII` prin `A.ID_POL = V_ID_POL`
- **fara handler de exceptie**. Cu `V_ID_POL = NULL` — exact cazul liniei fara politica — comparatia nu
- se poate potrivi niciodata, deci apelul cade cu `ORA-01403` **la adaugarea articolului**, in bucla
- `do_scrie_articole` (`ofacturare.vc2:13967-14106`), care ruleaza intotdeauna inaintea `Do Case`-ului
- (`:14282`). Linia nu ajunge niciodata la `contabilizeaza_articol`; ramura noua n-are nimic de tratat
- acolo, si **nu are nevoie de garda defensiva** (ar fi redundanta peste doua straturi independente).
-- **GOL REAL, mai ingust decat parea, dar efectiv atins: `SCD` pe avize.** Ramurile de aviz care chiar
- ajung la `contabilizeaza_articol` — `ntip IN (28,29)` → `SCD = '461'`, restul avizelor „simple"
- (`21, 22, 24, 27`) → `SCD = '418'` (`:7413-7422`) — **sunt accesibile cu `cont_venit` populat**, pentru
- ca `adauga_articol_factura` nu cere `id_pol` pe niciunul din ele. Ramura noua, care ia `SCD` din
- optiunea deciziei 36 (`4111`), l-ar scrie **necontitionat de `ntip`** → **cont contabil gresit pe
- aviz**. Deci ramura noua **alege `SCD` dupa `ntip`**: `'461'` pentru `IN (28,29)`, `'418'` pentru
- celelalte avize atinse, si abia pe restul optiunea `RF_CONT_ART_FARA_POL`.
- **Verificarea a restrans lista:** `ntip IN (23,25,30,41,42,47)` **nu ajung deloc** la
- `contabilizeaza_articol` — sunt deviate mai devreme, in `scrie_factura2`, spre `transfera_articol`
- (`23,25,30,41`) sau direct spre `descarca_gestiune` (`42,47`). Golul nu li se aplica.
-- **Al doilea gol confirmat: garda `ntip = 46`.** `nTipNotaPlata` **este** `46`, iar `scrie_nota` e
- sarita azi intentionat pentru el (`IF ntip <> nTipNotaPlata`, `:7441`). Un articol fara politica poate
- ajunge si pe acest tip. **Ramura noua trebuie sa reproduca garda** — altfel scrie o nota care azi e
- sarita deliberat.
-
-**CORECTIE la proiectare — al doilea apelant intern e numit gresit peste tot.** Nu
-`scrie_factura_avize_retur`, ci **`scrie_factura_avize`** (`:6692-7058`) — care e chiar handler-ul Oracle
-al lui `ntip = 4`, apelat din `ofacturare.vc2:14318`; apelul catre `contabilizeaza_articol` e la `:6858`,
-in interiorul lui `IF articole_aviz(j).custodie = 1`. `scrie_factura_avize_retur` (`:6264-6657`) **nu
-cheama deloc** `contabilizeaza_articol` — insereaza direct in `VANZARI_DETALII_TEMP` din
-`VANZARI_DETALII`. Iar `scrie_aviz_retur` (`:7085-7171`) **n-are niciun apelant VFP gasit** in tot
-`COMUN\` si in tot proiectul — posibil cod mort sau apelata din alt produs. Greseala e propagata in
-`canal_cont_venit_fara_politica.md:67` si `nota_contabila_fara_politica.md:103`; se citeaza de acum
-lista corectata de mai sus.
-
-**Nota de metoda, valabila pentru toate rapoartele:** presupunerea ca liniile din exportul
-`PACK_FACTURARE` au un **offset constant `+17`** fata de rapoartele vechi e **falsa**. Nu exista offset
-universal (masurat: `+9` fata de `nota_contabila_fara_politica.md`, `0` fata de alte rapoarte). Numerele
-de linie se **re-verifica direct pe fisier**, niciodata prin corectie presupusa.
-
-**Nu se implementeaza** — decizia 30 sta, #13 incepe dupa #6.
-
-**33. Mockup-ul nu se republica la v7.** Se duce la **v8** cu rezultatele verificarilor rundei 9 si abia
-atunci se republica — o singura citire a HTML-ului, o singura republicare. Url-ul artifact rămâne la v6
-pana atunci.
-
-### Deciziile lui Marius, runda 10 (10.08.2026)
-
-**35. Un singur cod de scriere contabila: `pack_facturare`, si la emitere si la editare.
-`oscrie_in_fisiere` NU se foloseste in #13.** Marius, 10.08.2026, textual: *„nu doresc folosirea scrie in
-fisiere ci doar `pack_facturare` la emitere si la editare pentru ca nu vreau sa intretin doua coduri."*
-
-**Ce anuleaza:** impartirea propusa la finalul rundei 9 — „emiterea prin parametrul deciziei 34, editarea
-prin canalul generic catre `ACT_TEMP`, care nu cere nimic in pachet" — e **respinsa**. Canalul
-`actactan` / `tact` → `COMUN\programe\oscrie_in_fisiere.prg` → `pack_contafin.SCRIE_IN_ACT` exista si e
-folosit azi in productie de fluxul de editare al lui #6, dar folosirea lui in #13 ar insemna **doua
-implementari ale aceleiasi reguli de contare** — una in pachet, pe emitere, alta in VFP, pe editare —
-tinute in pas manual la fiecare schimbare a regulii deciziei 27. Motivul e de **intretinere**, nu tehnic,
-si nu se reargumenteaza cu „canalul exista deja".
-
-**Ce impune:** editarea prin regenerare (etapa II) scrie pe **exact acelasi drum** ca emiterea —
-`scrie_factura2` → `contabilizeaza_articol`, cu parametrul de cont de la decizia 34. Nu exista ramura de
-scriere separata pentru documentul reemis si nu exista editare directa a randului din `ACT_TEMP` din #13.
-
-**Ce nu atinge decizia 35:**
-- **fluxul lui #6** ramane cum e (`ofacturare_comun.vc2:3796-3821` → `frm_modific2024`) — decizia priveste
- #13; retragerea lui e alt subiect si alt perimetru — **inchis de decizia 38: coexista, se decide dupa
- ce #13 livreaza**;
-- **stergerea** documentului vechi din S9 ramane pe drumul existent (`do_sterge` → `oscrie_in_fisiere` +
- `pack_contafin.finalizeaza_stergere_nota`), pentru ca acolo **nu exista al doilea cod de intretinut**:
- `pack_facturare` nu are echivalent de stergere a notei, iar drumul de stergere e comun intregii suite.
- *Presupunere declarata, de infirmat daca Marius vrea si stergerea mutata in pachet — ar fi alt mandat si
- alta suprafata de risc.*
-
-**Ce castiga:** regula deciziei 27 traieste intr-un singur loc, si o corectie pe ea nu trebuie facuta de
-doua ori. **Ce costa:** etapa II nu mai are cale ieftina — depinde de parametrul deciziei 34 exact cat
-depinde etapa I, deci **S9 nu poate porni inaintea parametrului**, iar regresia pe suita se plateste o
-singura data, dar obligatoriu.
-
-**36. Cele doua campuri ramase fara sursa pe ramura fara politica — decis.** Verificarea a stabilit intai
-ca **nu exista in cod nicio sursa alternativa** pentru ele: nici optiune de firma existenta, nici cont pe
-partener, nici flag de scutire pe articol sau client (`parametru_cont_contabilizeaza_articol.md`,
-sectiunea 4). Deci sunt decizii de produs, si Marius le-a luat asa:
-
-- **`SCD` — fix, dar citit din configurare, nu hardcodat.** O optiune de firma, cu **`4111` ca implicit**.
- **PROIECTATA** — `docs\cercetare\optiune_firma_cont_debit.md`. **Costul e mult mai mic decat parea:
- tiparul exact exista deja in productie, in acelasi pachet, pe acelasi camp.**
- `pack_facturare.scrie_incasare2` (`PACK_FACTURARE:13161-13234`) isi ia `V_SCD` in **trei niveluri**:
- parametru explicit daca a fost dat → **optiunea de firma** (`RF_CONT_INCASARE_BONFISCAL` s.a.m.d., cate
- una per tip de incasare) → **constanta hardcodata** daca optiunea lipseste. Se copiaza identic, si se
- inlocuieste punctual linia `SCD := '4111'` din proiectarea ramurii noi.
- Mecanismul are 15+ ani: tabelul `OPTIUNI` (458 randuri azi), `PACK_SESIUNE.getoptiunefirma`, si un
- **ecran de editare complet generic** peste tabel (`frm_optiuni` / `frm_optiuni_nou`,
- `COMUN\clase\oOptiuni.vc2`) — deci **cheia noua nu cere niciun cod VFP nou**, doar randul in tabel.
- Nu exista `ID_FIRMA`: fiecare firma are schema Oracle proprie, deci `OPTIUNI` din schema de conexiune
- **este** deja „optiunile firmei curente".
- **Dubla plasa de siguranta, si asta acopera integral cerinta lui Marius:** implicitul `4111` traieste si
- in randul din `OPTIUNI` (scris de migrare, editabil fara recompilare), si hardcodat langa
- `getoptiunefirma` — deci si o instalare veche fara migrare, si un rand golit din ecran cad tot pe `4111`.
- `getoptiunefirma` intoarce `''` cand nu gaseste, ceea ce in Oracle e `IS NULL`, deci ambele cazuri se
- trateaza cu aceeasi conditie.
- **`ASCD` nu trebuie atins** — se calculeaza deja din `V_SCD`, deci primeste automat valoarea corecta
- indiferent de sursa.
- **`PROGRAME` se pune larg, nu doar `ROAFACTURARE`** — intrebarea a ramas deschisa in raport, dar se
- inchide combinand-o cu masuratoarea de regresie: apelul catre `adauga_articol_factura` traieste in
- `COMUN\clase\ofacturare.vc2`, fisier prezent si folosit in **toate cele sapte produse**, deci ramura noua
- e atinsa de toata suita, exact ca `RF_CONT_INCASARE_*` (care listeaza sase produse).
-- **`CU_TVA` — derivat din cota liniei**, nu fixat: `1` daca `proc_tvav > 0`, altfel `0`. Asta **elimina
- prin constructie** efectul gasit la verificare: o linie scutita nu mai intra in comparatia de maxim din
- `nproc_tva_max`, deci nu mai poate imprumuta coloana si taxcode-ul ei liniei de discount a intregii
- facturi. Pretul e o regula in plus in pachet si un comportament **diferit de ce face azi nota** pentru o
- linie scutita — diferenta e intentionata, nu accidentala, si se noteaza ca atare la testare.
-
-Deci lista parametrilor noi ramane la **unul singur** (`V_CONT_VENIT`): `SCD` vine din configurare, iar
-`CU_TVA` se deriva in pachet din date deja prezente pe rand.
-
-**37. Cheia optiunii si validarea — decise (10.08.2026).**
-- **Cheia: `RF_CONT_ART_FARA_POL`**, aliniata la familia `RF_CONT_INCASARE_*` — adica exact optiunile care
- alimenteaza azi `SCD` in acelasi pachet. Cele cinci apar astfel **grupate alaturi in ecranul de
- optiuni**, ceea ce le face inteligibile impreuna. Incape in `OPTIUNI.VARNAME` (`VARCHAR2(30)`).
- `VARTYPE = 'CHARACTER'`, `VARVALUE = '4111'`, `PROGRAM = 'ROAFACTURARE'`, `PROGRAME` larg (vezi 36).
-- **Fara validare de cont**, nici la salvare, nici la citire — se copiaza tiparul existent. Motivul:
- niciuna dintre optiunile de tip cont nu e validata azi nicaieri, iar `RF_CONT_INCASARE_*` traieste asa
- de 15 ani; a introduce validare aici ar fi o imbunatatire noua, nu continuarea unui tipar, si ar cere
- fie cod nou in pachet, fie prima logica per-cheie din ecranul generic `COMUN\clase\oOptiuni.vc2` —
- fisier al intregii suite. **Garda gratuita ramane lungimea:** un `VARVALUE` peste 4 caractere da
- `ORA-12899` la `INSERT INTO ACT_TEMP`, deci esec zgomotos, nu cont tacut gresit.
- *De consemnat la testare ca risc acceptat constient:* un cont inexistent in planul de conturi, scris din
- greseala in ecran, ajunge pe nota neschimbat — acelasi risc pe care produsul il are deja, nu unul nou.
-
-### Deciziile lui Marius, runda 11 (10.08.2026)
-
-**38. Fluxul de editare al lui #6 nu se retrage odata cu #13. Coexista, si se decide mai tarziu.**
-Intrebarea pusa la finalul rundei 10 — daca decizia 35 („un singur cod de scriere contabila") obliga la
-rerutarea editarii lui #6 pe acelasi drum — primeste raspuns: **nu acum**. #6 ramane pe editarea directa
-a randului din `ACT_TEMP` (`ofacturare_comun.vc2:3796-3821` → `frm_modific2024` → `oscrie_in_fisiere`),
-#13 merge pe regenerare prin `pack_facturare`. Cele doua traiesc separat, pe povesti separate.
-**Ce inseamna concret:** decizia 35 se citeste strict ca perimetru al lui #13 — nu se proiecteaza si nu
-se planifica nicio retragere a fluxului lui #6 in aceasta poveste, si nu se adauga in #13 nicio piesa
-care sa pregateasca acea retragere. Subiectul **nu e inchis definitiv**: se redeschide dupa ce #13
-livreaza regenerarea si se vede in practica daca intretinerea celor doua drumuri doare cu adevarat.
-Pana atunci nu se reargumenteaza in niciun sens.
-
-**39. S4 ramane integrala: se desface si registrul de cantitate ramasa.** Proiectarea rundei 11 a aratat
-ca `crsarticole` nu e doar sursa gridului, ci **registrul cantitatii ramase de facturat** — scris de
-`do_sterge` la stergerea unei linii (`ofacturare.vc2:14640-14669`) si citit prin
-`Calculate Sum(cantitate) To lnCantitateRamasa` ca sa se decida **inchiderea automata** a comenzii /
-avizului (`:14303-14311`, `:14334-14338`). Varianta ieftina ar fi fost sa se restranga S4 la lista de
-preturi; Marius a ales varianta intreaga: **bookkeeping-ul se decupleaza de cursorul incarcat in masa**,
-ca sa poata disparea incarcarea si pe comanda si pe aviz.
-**Consecinta, declarata explicit:** S4 nu mai e o poveste de performanta pe formular, ci atinge
-**inchiderea automata a documentelor sursa** — cea mai mare suprafata de regresie din etapa I, si
-singura care poate lasa o comanda deschisa (sau o poate inchide prematur) fara ca operatorul sa vada
-ceva. Criteriul de „gata" al lui S4 include de acum, obligatoriu, **paritate pe inchiderea automata**:
-acelasi document sursa, aceleasi linii facturate partial, acelasi `INCHISA` la final, pe fiecare tip cu
-document sursa. Registrul nou trebuie sa fie sursa unica — nu o a doua copie tinuta in pas cu prima,
-altfel povestea introduce exact tipul de dublura pe care decizia 35 il refuza in alta parte.
-
-**40. Bug-ul de dezalocare POS se repara in S3b, in trecere.** Vezi `L.4`. Consecinta acceptata: diff-ul
-lui S3b **nu mai e o mutare pur mecanica**, deci testarea lui trebuie sa acopere si dezalocarea POS pe
-calea veche, nu doar paritatea de emitere.
-
-**41. Sectiunea pliata are DOUA comutatoare, nu unul si nu cinci.** Grupul de **incasare** — singurul cu
-efecte laterale reale (alocare / dezalocare de numere) si singurul blocat pe document emis prin decizia
-25 — primeste comutator propriu. Delegat/transport, adresa, text aditional si analiticele stau impreuna
-sub al doilea. Motivul e izolarea riscului: garda de non-alocare la toggle
-(`opt_incasat.ProgrammaticChange`) se scrie si se testeaza **intr-un singur loc**, nu pe cinci stari.
-
-**42. Validarea de curs valutar se restrange la valuta articolului cautat.** Pe varianta filtrata a
-cursoarelor, `verifica_cursuri_valute` nu mai ruleaza global, ci doar pe valuta randului adus.
-**Schimbare de comportament asumata:** un curs lipsa pe **alta** valuta nu mai e semnalat la deschiderea
-formularului, ci abia cand se ajunge la un articol pe acea valuta. Se consemneaza la testare ca
-diferenta intentionata fata de azi, nu ca regresie.
-
-#### Puncte marunte ramase din proiectarile rundei 11 — se merge pe recomandare daca Marius nu spune altfel
-
-Nu blocheaza nimic; se inchid la implementarea povestii respective. Enumerate ca sa nu se piarda intre runde.
-
-| # | Punct | Poveste | Se merge pe |
-|---|---|---|---|
-| a | Textul exact al tooltip-urilor pentru analiticele read-only si pentru grupul de incasare blocat | S3b | formularea propusa in raport, sectiunile 2.2 si 5.3 |
-| b | Eager vs. lazy pentru lookup-urile Oracle din `Init` (delegat / masina ultimei facturi, casa) | S3b, S3 | **lazy**, ca sa nu se plateasca la fiecare depliere; deschis si in `s3_portare_antet.md` §5 |
-| c | `_checkbox1` vs. `chkDetaliat` — care devine campul unic de „listare detaliata" | S3b, S1 | **INCHIS (runda 12)**, pe cod: sunt **doua controale distincte** in `frm_alte_date`, nu o duplicare — nu exista nimic de ales. `docs\cercetare\s4c_discount_in_grid.md`, sectiunea 11 |
-| d | Forma lui `toSursa`: obiect scatter (duck-typing) sau clasa dedicata | S3c | **duck-typing**, ca azi — o clasa noua n-ar schimba nimic functional |
-| e | Conversia comenzii si a contractului: un commit sau doua | S3c | **un singur commit** — ating aceleasi trei fisiere comune, separarea nu reduce regresia, doar amana testarea pe ROACONTRACTE |
-| f | `goComanda = ''` redundant la `Cw3.do_actiune` dupa conversie | S3c | **se lasa**, marcat explicit „intentionat" in diff, ca sa nu para omisiune la review |
-| g | Contractul are doua meniuri (articole vs. rate): eticheta generica sau diferentiata pe `OPT_FACTURARE` | S4b | **diferentiata** — „Alege ratele de facturat…" e gresita pe contractele cu articole |
-| h | „Alege facturile de returnat…" ramane doar la antet sau capata incarcare aditiva din bara | S4b | **ramane la antet** in etapa I; mutarea e o poveste separata |
-| i | `But_renunt1` / `But_reset1` primesc `Caption` pentru consistenta cu bara etichetata | S4b | **da** — decizia 13 cere etichete, nu iconite mute; exceptia ar fi inconsecventa |
-| j | Ordinea si formularea optiunilor din `xmenu()` per sursa | S4b | tabelul din sectiunea 3 a raportului, ca propunere |
-| k | UX-ul contractului cu doua surse pe acelasi grid conceptual (`crsarticole` filtrat + `crsarticole1`) | S4 | de confirmat vizual la mockup, nu pe hartie |
-
-### Ce s-a dovedit ca exista deja (deciziile 10, 11, 12, 14)
-
-Verificat pe cod la 09.08.2026; rapoartele complete sunt in `docs\cercetare\`
-(`proforma_copiere_puncte_intrare.md`, `discount_pe_articol.md`,
-`inventar_controale_formulare.md`, `import_roris_roaacnpro.md`).
-
-- **Proforma nu e tip de document si nu are formular propriu.** E valoarea `PROFORMA` din combo-ul
- „Tip document” (`ct_clb_fdoc._combobox1`, `RowSource = "FACTURA,PROFORMA,BON FISCAL"`,
- `ofacturare.vc2:8745-8754`), care seteaza `nIdTipDoc = 23` si, prin setter,
- `eProforma = 1` (`ofacturare_comun.prg:593-599`, `nIdTipDocProforma = 23` la `:104`). Deci intra in
- formularul unificat **fara nimic de portat**. Specific proformei si de pastrat: serie si numar
- proprii, realocate la comutarea din combo (`ofacturare.vc2:9415,9427-9428`); **fara nota contabila
- si fara atasamente**, prin garzile `poDate.eProforma = 0`
- (`ofacturare.prg:1960,1996,2052,2063,2103`); raport propriu (`:1638-1643`, `COMUN\Rapoarte\proforma.fr2`);
- relistarea pe cale separata (`ofacturare_comun.vc2:7230-7264`).
-- **Copierea foloseste deja acelasi formular, cu antetul editabil.** `do_copiaza` -> `copiere_factura`
- -> `factureaza(tip, toFactura)` -> `frm_date_factura` precompletat de
- `completeaza_setari_document(toFactura, .T.)` (`ofacturare_comun.prg:362-412`). Numar nou se aloca
- **intotdeauna**, neconditionat de copiere (`ofacturare.prg:208,211`). Nimic din traseu nu blocheaza
- controale de antet.
-- **Butonul de facturare din pagina de comenzi exista deja in ROAFACTURARE**: `ct_comenzi.do_factura`
- (`ocomenzi.vc2:1580-1596`) face `SCATTER NAME goComanda MEMO` si cheama `facturare_comenzi` ->
- `factureaza(3)`; butonul `But_factura1` (`ocomenzi.vc2:932-937`) e ascuns cand comanda e deja
- facturata (`:2199-2203`), si e montat pe Page5 (`ofundal_facturare.vc2:604`, `Ferestre\fundal.sc2:206`).
-- **Precompletarea contractului vine din programul de contracte** (`ROACONTRACTE`):
- `ferestre_contracte.vc2:1538-1549` si `:1605` -> `facturare_contracte` -> `factureaza(2/6/52)`,
- cu contractul deja completat — exact ce cere decizia 12, si **functioneaza azi**. In ROAFACTURARE
- exista, in plus, calea din meniu **fara** precompletare (`ofundal_facturare.vc2:886-897`), unde
- utilizatorul alege contractul in formular. Cele doua coexista; #13 nu adauga o lista de contracte
- in ROAFACTURARE si **nu depinde de #10**.
-- **Discountul pe articol are deja si procent, si valoare — dar intr-un dialog separat.** Vezi K.
-- **Deblocarea antetului exista deja**, dar sub forma a patru bife individuale in
- `frm_modifica_factura`; in formularul unificat ele sunt inlocuite de un singur buton comutator.
- Vezi I.
-- **Data cursului valutar nu e conditionata azi de valuta.** Vezi M.
-
-### Canalul de precompletare e un global, nu un parametru
-
-`factureaza(tnTip, toFactura)` (`ofacturare.prg:81-82`) nu are parametru pentru sursa: comanda si
-contractul se transmit prin globalele `goComanda` / `goContract`, citite in `oDateFactura.Init`
-(`ofacturare_comun.prg:301-328` comanda, `:261-297` contract). De aceea calea generica de comanda e
-obligata sa scrie explicit `goComanda = ''` inainte de apel (`ofundal_facturare.vc2:899-902`), altfel
-ar ramane precompletata cu ce era in sesiune. **Calea generica de contract nu face resetarea
-simetrica** (`:886-897`) — de verificat daca `goContract` poate ramane populat intr-o sesiune si
-precompleta tacit un document nou. Decizia 12 se implementeaza corect prin **parametru explicit**, nu
-prin inca un global.
-
-## Relatia cu #6 — transata: #13 incepe dupa #6
-
-`plan_06_editare_factura.md` rezolva **aceeasi problema de fond** (o factura emisa nu se poate
-corecta fara ca notele si rulajele sa ramana in urma) pe calea opusa: editare directa in
-`frm_modific2024`, cu `id_fact` pastrat. Planul #6 a respins explicit regenerarea, cu motivul ca
-*"emiterea face verificari de stoc si alte protectii dependente de tipul documentului; la
-regenerare acestea ar esua pe date care intre timp s-au schimbat"*.
-
-Argumentul acela **cade partial** daca stergerea si reemiterea se fac in aceeasi tranzactie, in
-ordinea corecta — vezi sectiunea "Stocul" mai jos. Dar nu cade complet: raman verificarile care nu
-tin de stoc (configurare politica / contract / cota TVA, vezi `adauga_articol_factura`).
-
-Cele doua nu se exclud tehnic, dar **se suprapun pe aceleasi fisiere** si, mai important, produc
-doua semantici diferite pentru "am corectat factura":
-
-| | #6 — editare directa | #13 — regenerare |
-|---|---|---|
-| Punct de intrare | registru jurnal + formular facturi | formularul de facturi |
-| Utilizator vizat | contabil | operatorul de facturare |
-| `ID_FACT` | pastrat prin constructie | **pastrat, prin cerinta** (vezi E) |
-| Serie, numar, data | neschimbate | neschimbate (cale proprie, vezi F) |
-| `COD`, `ID_VANZARE` | `COD` nou, `ID_VANZARE` pastrat | ambele noi |
-| Notele si rulajele | rescrise din formularul de note | **regenerate din articole**, ca la emitere |
-| Documentul sursa (comanda/aviz/contract) | neatins | **eliberat si reconsumat** |
-| Efort | mediu (in curs, S1–S3 livrate) | mare |
-
-**Decizia lui Marius (09.08.2026): coexista, cu roluri separate.** #6 ramane calea contabilului
-pentru corectii pe nota — si e singura cale posibila din registrul jurnal din ROACONT/ROAGEST, unde
-nu exista contextul de facturare (`poDate`, `crsfactura`, politici, serii). #13 devine calea
-operatorului de facturare: modific documentul, notele si rulajele se refac singure.
-
-**Coliziune de lucru: nu exista. DECIS (decizia 30): #13 incepe dupa ce #6 se termina.** Sesiunea de
-la #6 a atins `COMUN\clase\ofacturare_comun.vc2` (`do_editare_factura`, `:3715-3869`), a creat
-`COMUN\programe\ofacturare_editare.prg` si a adus `omodificari.vcx` in proiect (`97d1613`) — dar
-implementarea lui #13 nu porneste cat timp acestea sunt in lucru, deci **nu e nevoie nici de
-impartire de perimetru, nici de coordonare intre fire.** Cele doua buguri semnalate (L.0 si L.0-bis)
-raman semnalate catre #6, nu reparate din #13.
-Ce **nu** decade odata cu coordonarea: **decizia 26** — analiticele raman read-only in #13. Motivul ei
-e semantic (#6 le editeaza la nivel de linie de nota, #13 le-ar scrie uniform pe tot documentul), nu
-o problema de calendar.
-
----
-
-## Ce s-a stabilit din cod
-
-### A. Formularul unificat exista deja ca prototip, oprit din 2017
-
-`frm_facturare_articole2` (`COMUN\clase\ofacturare.vc2:15741-19355`) **este** formularul cerut la
-punctul 13, la nivel de controale:
-
-- are deja campurile de antet mutate din `frm_date_factura`: `Clb_serie_act1`, `Clb_nract`,
- `Clb_dataact`, `Clb_zi_curs`, `Clb_data_scadenta`, `Ct_clb_nume_client`, `Ct_clb_responsabil`,
- `Ct_clb_sectie`, `Ct_clb_lucrare`, `Ct_clb_venchelt`, `Ct_clb_altele`, `Ct_clb_valuta`,
- `clb_fdoc`, `Ed_tx_simplu1` (`:15744-15812`);
-- **nu** are `grd_articole`, `grd_contracte`, `cb_politici_preturi`, `cb_contracte`, casetele de
- cautare `txtCodmat` / `txtArticole` — adica exact partea care azi consuma incarcarea in masa;
-- are grid editabil in linie, cu combouri `combosql` din `cautare.vcx` pe `cCodMat.cboCodmat`,
- `cDenumire.cCboDenumire`, `cGestiune.cCboGestiune` (`:16751-16881`), plus `But_nou1`;
-- e lansat de `factureaza2` (`COMUN\programe\ofacturare.prg:590-1080`), care se cheama numai daca
- `gnFacturareNou = 1` **si** utilizatorul raspunde DA la un `AMESSAGEBOX` (`:87-92`).
-
-**Cat de mort e prototipul.** In `factureaza2`, deschiderea formularului de date si incarcarea
-articolelor sunt inchise cu `If .F.`: `:707-711` (formularul de date), `:826-829` (executia
-cursorului de articole), `:838` (verificarea de "nu exista articole"), `:985-1008` (`crspolitici`
-si `crscontracte`). `Init`-ul lui `frm_facturare_articole2` are 92 de linii (`:18988-19080`) fata
-de 368 la `frm_facturare_articole` (`:14976-15344`) si **nu completeaza niciun camp de antet** —
-controalele sunt acolo, logica nu.
-
-**Drift-ul dintre `factureaza` si `factureaza2`** (fork din 08.06.2017, nesincronizat): lipsesc din
-`factureaza2` tipurile 51 si 52, ramura `llCopiere` / `toFactura`, completarea `codmatc` /
-`codnc8` / `codcpv`, `GetInstitutiePublica`, `GetSoldClient`, filtrul `RORTC` pe `jtva_coloane`,
-tratarea `eProforma`, `verifica_numar(16, ...)` pentru chitanta, `cursor_retur_document`,
-`cursor_avize` cu tip 23. **Concluzie: nu se continua cu doua proceduri.** Se merge pe una singura,
-cu un parametru de mod, altfel divergenta se reia imediat (exact tiparul care a produs problema
-reparata la #8).
-
-### B. Nu doua formulare, ci patru
-
-Fluxul de azi are **patru** ferestre. Runda 2 numarase trei; a patra, `frm_articol_factura`
-(`ofacturare.vc2:1108-2659`), se deschide **pentru fiecare articol adaugat**, din
-`do_adauga_articol` (`:12873`, `ofrmadarticol.Show(1)`, doar daca `!tlImplicit`) — si e locul in care
-se introduce azi discountul pe linie (vezi K). Formularul unificat o desfiinteaza, deci campurile ei
-trebuie sa aiba unde sa se mute.
-
-Celelalte trei:
-
-1. `frm_date_factura` (`ofacturare.vc2:8482-9869`) sau `frm_date_aviz` (`:6566-7618`) —
- 17, respectiv 13 metode `do_cauta_*`, plus `do_schimba_tipdoc`, `inainte_de_do_termin` si un
- `Init` de 234 / 247 de linii;
-2. `frm_facturare_articole` (`:10968-15739`) — compunerea;
-3. `frm_alte_date` (`COMUN\clase\ferestre_cere_date.vc2:2219-3353`) — **aratat dupa** confirmarea
- articolelor, din `inainte_de_do_termin` (`ofacturare.vc2:14921-14941`): delegat, auto, agent,
- adresa de facturare, incasare (numerar / chitanta / bon fiscal / POS), text aditional. Aloca si
- numere proprii (bon fiscal, POS, chitanta).
-
-Punctul 13 vorbeste doar despre primele doua. **Decizia 7 le aduce pe toate trei**: `frm_alte_date`
-intra in formular, ca zona pliata. Recomandarea din runda 2 („ramane dialog in prima etapa”) e
-respinsa.
-
-Ce inseamna concret, din inventarul de controale: se muta patru grupuri — delegat si transport
-(`Ct_clb_delegat`, `Ct_clb_masina`, `Ct_clb_agent`, `Clb_dataora_exp`), incasare (radiogrupul
-`opt_incasat` cu patru optiuni, `Cb_casa`, `Clb_serie_chit`, `Clb_nrchit`, `Clb_incasat`,
-`cmdModificaBon`, `chkPOS`, `chkDetaliat`, `cboTipFactura`), adresa de facturare
-(`clb_adresa_facturare`) si textul aditional (`Ed_tx_simplu1`) —
-`ferestre_cere_date.vc2:2343-2638`. **Masina de stari se muta ca atare, nu se rescrie**:
-`actualizeaza_tipincasare` (`:2698-2856`) comuta vizibilitatea pe cele patru valori si aloca sau
-dezaloca numarul de chitanta (`:2783`), de bon fiscal (`:2807`) sau de POS (`:2844`). Riscul semnalat
-in runda 2 nu dispare, dar e localizat: **alocarea de numere trebuie sa ramana legata de aceleasi
-evenimente**, nu de deschiderea formularului.
-
-Peste ele coboara analiticele din antet (decizia 8): `Ct_clb_venchelt`, `Ct_clb_sectie`,
-`Ct_clb_responsabil`, `Ct_clb_lucrare`.
-
-### C. Incarcarea articolelor — de ce dureaza si ce inlocuieste
-
-`factureaza` executa, inainte de a deschide compunerea, **un singur apel** care aduce toate
-articolele disponibile: `pack_facturare.cursor_preturi` (`ofacturare.prg:281-286`, corp la
-`PACK_FACTURARE:2121+`), respectiv `cursor_contract` / `cursor_comanda` / `cursor_avize` /
-`cursor_gestiune` / `cursor_retur` dupa tip (`ofacturare.prg:265-311`). Rezultatul intra in
-`crsarticole` si tine gridul de sus.
-
-`cursor_preturi` **nu are filtru pe articol** — semnatura e
-`(V_DATA_CURS, V_TIP, V_ID_VALUTA, V_ID_GESTIUNE_INIT, V_LUNA, V_AN, V_ID_UTIL, V_ID_SUCURSALA)`
-(`PACK_FACTURARE:335-343`). De aici vin miile de randuri.
-
-Mecanismul de inlocuire **exista deja**, in prototip: `combosql` cauta pe server, incremental, cu
-`csourcesql = select codmat, denumire, um, grupa, subgrupa, codbare, id_articol from vnom_articole`
-si `csourcewhere = inactiv = 0` (`ofacturare.vc2:16751-16766`).
-
-**Dar `vnom_articole` e nomenclatorul, nu lista de preturi.** Nu are pret, nota contabila, cota TVA,
-valuta, `id_pol`, `gestionabil`, `pret_cu_tva` — toate vin azi din `cursor_preturi`. Deci partea
-Oracle a lucrarii e o **varianta filtrata pe articol** a cursoarelor de facturare, apelata la
-alegerea liniei, nu la deschiderea formularului. Nu e o simplificare: ramurile pe tip din
-`cursor_preturi` (restaurant, custodie, retur, contract, comanda) trebuie pastrate identic, altfel
-pretul difera intre cele doua cai.
-
-**Legatura cu #12.** Daca articolul poate purta el insusi pretul si nota contabila (varianta C din
-`plan_12`), cautarea in linie devine directa si nu mai are nevoie de o rezolvare separata a listei
-de preturi. #13 nu depinde de #12, dar cine face #12 dupa #13 va rescrie exact bucata asta.
-
-### D. Regenerarea — piesele exista, montajul nu
-
-**1. Stergerea elibereaza deja documentul sursa.** `pack_facturare.sterge_factura`
-(`PACK_FACTURARE:5415-5591`) face, pe langa `sters = 1` pe `VANZARI` si `VANZARI_DETALII`:
-
-- `FACTURAT = 0, ID_UTILFACT = NULL, DATA_FACTURAT = NULL` pe avizele facturate (tip 4 si 24);
-- `STERS = 1` pe `VANZARI_CANTITATI` (cantitatile consumate de pe avize);
-- `STERS = 1` pe `COMENZI_ELEMENTE` cu `CANTITATE < 0` (consumul din comanda);
-- `STERS = 1` pe `VANZARI_CORESP` si pe `CTR_RATE_FACTURI` (contracte in rate, tip 2/6/52).
-
-Adica **exact reversul consumului sursei** — conditia ca reemiterea sa poata reconsuma aceeasi
-comanda / acelasi aviz / aceeasi rata. Sunt si garzi: refuza stergerea daca s-au emis facturi sau
-avize de retur peste document (`:5432-5477`).
-
-**2. Calea VFP de stergere completa exista.** `frm_facturi.do_sterge`
-(`COMUN\clase\ofacturare_comun.vc2:4658-4874`): tranzactie manuala, `oscrie_in_fisiere`, apoi
-`pack_contafin.finalizeaza_stergere_nota` (care cheama `sterge_din_vanzari`). Rulajele si notele
-dispar pe aceasta cale, nu prin `sterge_factura`.
-
-**3. Reconstituirea liniilor exista.** `pack_facturare.cursor_retur_document(..., V_COPIERE = 1, ...)`
-(`PACK_FACTURARE:3932-4045`) reface liniile din `VANZARI_DETALII`, cu `explicatie`, `id_gestiune`,
-`pret_achizitie`, `pretd`, `id_jtva_coloana`, `id_jtva_coloana_ex`, `lot`, `serie`, `id_pol`,
-`pret_cu_tva`, plus `curs` / `multiplicator` din `VANZARI_CURSURI`. E deja folosita, exact asa, la
-copierea unei facturi.
-
-**4. "Redeschide formularul precompletat" exista.** `frm_facturi.do_copiaza`
-(`ofacturare_comun.vc2:3640-3713`) -> `copiere_factura` (`oproceduri_facturare.prg:150-153`) ->
-`factureaza(tip, toFactura)`, iar in `factureaza` ramura `llCopiere` (`ofacturare.prg:255-257`,
-`:458-473`) incarca liniile documentului si adauga peste ele lista de preturi, ca sa se poata
-adauga articole noi. `oDateFactura.completeaza_setari_document(toFactura, .T.)`
-(`COMUN\programe\ofacturare_comun.prg:362-412`) precompleteaza antetul.
-
-**Ce nu se poate refolosi ca atare:** `do_copiaza` **degradeaza intentionat tipul** — factura din
-contract / comanda / aviz devine `tip = 1`, avizele devin `22`, transferurile `10`
-(`ofacturare_comun.vc2:3696-3710`), cu comentariul *"nu are sens sa fie copiata, dar o tratez ca pe
-o factura din lista de preturi"*. La regenerare, degradarea e **exact ce nu trebuie sa se intample**:
-documentul nou trebuie sa ramana pe acelasi tip, ca sa reconsume sursa. Deci se cloneaza structura
-lui `do_copiaza`, nu comportamentul.
-
-### E. `ID_FACT` — cerinta si ce presupune ea
-
-**Cerinta (decizia 2):** documentul reemis pastreaza `ID_FACT`.
-
-**Starea de azi, verificata:** `ID_FACT` se genereaza cu secventa, neconditionat.
-`PACK_CONTAFIN.SET_IDFACT(V_GCS)` e `SELECT SEQ_IdFact.NEXTVAL`
-(`COMUN\docs\PACK_CONTAFIN.pck:3037-3040`), citit cu `get_idFact()` (`:725`), iar `DOCUMENTE`
-primeste rand nou cu acel `ID_DOC` (`:796-808`).
-
-**Dar intuitia „id_fact depinde de numar si data" e corecta istoric:** exista in pachet varianta
-`SET_IDFACT(tdDataAct, tcSerie_Act, tnNrAct, tnId_Ctr)` care cauta intai in `DOCUMENTE` dupa
-`NRACT` + `SERIE_ACT` + `DATAACT` + `ID_CTR` si ia secventa doar la `NO_DATA_FOUND`
-(`:3016-3035`) — **comentata**, deci inactiva.
-
-**Ce inseamna pentru #13** (de proiectat in S9, dupa verificarea din handoff):
-
-- fie se reactiveaza cautarea, sub un comutator folosit **numai** de regenerare — modificarea lui
- `SET_IDFACT` fara comutator ar schimba comportamentul pentru toata suita, ceea ce nu se face;
-- fie se transmite `ID_FACT`-ul cunoscut, ca parametru, pe drumul de scriere;
-- **capcana de ordine**: cautarea filtreaza `STERS = 0`. Daca documentul vechi e marcat sters
- inainte, cautarea nu-l mai gaseste si se genereaza id nou. Deci `ID_FACT`-ul se citeste **inainte**
- de stergere, in aceeasi tranzactie.
-
-Cu `ID_FACT` pastrat, ce ramane de inventariat e mult mai putin decat in varianta cu id nou:
-`ATASAMENTE_VANZARI` si `marcheaza_facturat` merg pe `ID_VANZARE` (care **se schimba**),
-`ANAF_EFACTURA` e gol prin garda, iar `DOCUMENTE` / `ACT` / `RUL` / `JV2007` / `IREG_PARTENERI` merg
-pe `ID_FACT` (pastrat). **`ID_VANZARE` nou ramane singura discontinuitate reala** — de verificat
-daca `DOCUMENTE` primeste un al doilea rand pe acelasi `ID_DOC` sau il refoloseste.
-
-### F. Serie, numar, data — cale proprie, nu regenerare
-
-**Cerinta (deciziile 3 si 4):** toate datele se pastreaza, inclusiv numarul; iar antetul care intra
-in identitatea documentului se modifica pe cale proprie.
-
-Calea exista deja si e exact ce trebuie: `pack_facturare.modifica_date_factura`
-(`PACK_FACTURARE:14392-14463`) face `UPDATE` in loc si **propaga serie / numar / data / scadenta
-pe `VANZARI`, `DOCUMENTE`, `ACT`, `IREG_PARTENERI`, `JV2007`, `RUL`, dupa `ID_FACT`**
-(`:14427-14460`). Tot ea scrie delegat, agent, masina, adresa de facturare, text aditional,
-`dataora_exp`, `listare_detaliata`, `tip_saft`, `efactura`. E procedura din spatele actiunii de azi
-`frm_facturi.do_modifica` -> `frm_modifica_factura`.
-
-**Deci in formularul unificat:** campurile de antet se scriu prin `modifica_date_factura`, nu prin
-regenerare. Regenerarea porneste doar pentru ce atinge sumele. Vezi tabelul din G-bis.
-
-`oGeneratorNumere` (`COMUN\programe\oserii_numere.prg:227-233`) nu incurca: la modificare nu se
-aloca numar nou, deci nu e nimic de dezalocat. Intrebarea despre o eventuala constrangere de
-unicitate pe `VANZARI(SERIE_ACT, NUMAR_ACT)` **dispare** — nu mai exista doua documente nesterse cu
-acelasi numar, pentru ca numarul nu se realoca; ramane doar cazul „vechi sters + nou nesters", care
-e exact situatia de azi de la orice stergere si reintroducere.
-
-### G-bis. Cele trei modificari de azi, si ce se scrie la confirmare
-
-Pe `frm_facturi` exista azi trei actiuni care ating acelasi document, fiecare cu fereastra ei:
-
-| Actiune de azi | Formular | Ce atinge | Sursa |
-|---|---|---|---|
-| `do_modifica` | `frm_modifica_factura` | antet: ruta, delegat, agent, serie, numar, date | `ofacturare_comun.vc2:4538-4637` |
-| `do_modifica_explicatie` | `frm_modifica_articol_factura` | `explicatie` + `taxcode` pe o linie | `:4639-4656` |
-| `do_editare_factura` (#6) | `frm_modific2024` | nota contabila si rulajele | `:3715-3869` |
-| — | — | **cantitati, preturi, linii: nicaieri** | — |
-
-Decizia 6 le comaseaza in formularul unificat. Ruta de scriere se alege dupa ce s-a schimbat:
-
-| Ce s-a schimbat | Cum se scrie | Efect |
-|---|---|---|
-| Serie, numar, data, scadenta, delegat, auto, agent, adresa facturare, text aditional | pe loc, `modifica_date_factura` | propaga dupa `ID_FACT` |
-| Explicatia si `taxcode` pe o linie | pe loc, `modifica_explicatie_articol` (`PACK_FACTURARE:14464-14472`) | doua coloane, nicio suma |
-| Cantitati, preturi, linii adaugate/sterse, discount, gestiune, cota TVA | **regenerare** | vechiul `sters = 1`, documentul nou scris pe drumul de emitere, note si rulaje refacute |
-| Nimic | nimic | documentul nu se rescrie degeaba |
-
-Ultima linie nu e cosmetica: fara ea, orice deschidere a formularului ar produce un document nou si
-ar umple `VANZARI` cu randuri sterse.
-
-**Gol descoperit la S1 (runda 7): tabelul de mai sus nu acopera tot antetul.** Inventarul camp-cu-camp
-(`docs\S1_inventar_campuri_formular_unificat.md`) a gasit trei grupuri de campuri de antet care **nu
-sunt printre cei 14 parametri** ai lui `modifica_date_factura` si pentru care nu s-a gasit alta ruta:
-
-- **analiticele** — venit/cheltuiala, sectie, responsabil, lucrare (grupul „Pliat — analitice” din I);
-- **identitate/sursa, altele decat serie/numar/data/scadenta** — tip document, valuta, zi curs, client,
- sursa/„altele”, gestiune sursa, politica de preturi;
-- **grupul de incasare** — mod incasare, casa, serie si numar de chitanta/bon, suma incasata, POS.
-
-**Verificat (runda 7): `docs\cercetare\rute_scriere_antet.md`.** Cautare exhaustiva in ambele straturi
-— Oracle (pachetul de facturare curent, plus `PACK_CONTAFIN`, `PACK_UPDATE`, `PACK_MIGRARE`; toate
-cele 13 aparitii de `UPDATE VANZARI` inspectate individual) si VFP (indexul complet: 316 fisiere,
-1128 clase, 9281 metode). Rezultatul e neuniform pe cele trei grupuri:
-
-| Grup | Verdict | Ce inseamna |
-|---|---|---|
-| **B** — tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi | **NU**, toate sapte | Controalele traiesc **exclusiv** in wizardul de emitere; nu exista niciun `UPDATE` care sa le atinga dupa emitere. Un „nu" verificabil, nu o absenta de cautare. |
-| **C** — mod incasare, casa, serie/nr chitanta, suma, POS | **NU direct** | Nu exista coloane proprii pe `VANZARI`: incasarea devine ea insasi **o linie de nota contabila** (`scrie_incasare2`). Nicio procedura de tip „modifica incasare". |
-| **A** — sectie, responsabil, lucrare | **DA** | Dar nu prin `modifica_date_factura`, ci prin **mecanismul lui #6**, aterizat chiar pe branch-ul asta (`97d1613`). Vezi mai jos. |
-| **A** — venit/cheltuiala (`ID_VENCHELT`) | **neconfirmat** | Gridul afiseaza coloana `dst_chlt`, dar `do_modifica` nu are caz pentru ea. |
-
-**Descoperirea care conteaza: analiticele sunt deja editabile, dar din #6.** `frm_facturi.do_editare_factura`
-(`ofacturare_comun.vc2:3690-3869`) e acum cablat la `frm_modific2024` (`omodificari.vc2`), incarca
-nota contabila a documentului emis si o rescrie prin `OSCRIE_IN_FISIERE` ->
-`pack_contafin.finalizeaza_modificare_nota`, care **resincronizeaza `VANZARI`**. `do_modifica`
-(`omodificari.vc2:13934-13943`) trateaza explicit `id_lucrare` si `id_responsabil`.
-
-**Doua nuante care schimba proiectarea, nu doar inventarul:**
-1. **Editarea e la nivel de LINIE de nota, nu de antet.** La emitere, cele patru analitice se scriu
- uniform pe tot documentul, din variabilele de sesiune. Prin editorul lui #6, fiecare linie se poate
- edita separat — deci un document poate ajunge cu **sectii diferite pe linii diferite**, stare
- imposibila la emitere. Conteaza pentru orice raportare care presupune „un singur `ID_SECTIE` per
- factura".
-2. **Bug suspectat pe `sectie`** (`omodificari.vc2:13941`): `replace ... id_valuta with
- loCauta.id_sectie` — pare sa scrie in `id_valuta` in loc de `id_sectie`. Daca e real, textul afisat
- se schimba dar coloana nu. **E in perimetrul lui #6** — se semnaleaza, nu se repara aici. Pana la
- verificare, „DA" pentru `ID_SECTIE` e un da cu rezerva.
-
-**Consecinta pentru decizia 9**, acum pe fapte: `but_modifica` **poate salva pe loc doar cei 14
-parametri**. Pentru grupurile B si C nu exista alta cale decat **regenerarea**, care le rescrie oricum
-pe toate, fiind chiar drumul de emitere. Pentru grupul A exista o a treia cale, dar e a lui #6 si
-lucreaza pe alt nivel (linie de nota).
-
-**Tabelul de rutare, completat (deciziile 25 si 26):**
-
-| Ce s-a schimbat | Cum se scrie |
-|---|---|
-| cei **14 parametri** (serie, numar, data, scadenta, ruta, delegat, masina, agent, `dataora_exp`, adresa facturare, text aditional, `listare_detaliata`, `tip_saft`, `efactura`) | **pe loc**, `modifica_date_factura` |
-| explicatia si `taxcode` pe o linie | **pe loc**, `modifica_explicatie_articol` |
-| cantitati, preturi, linii, discount, gestiune, cota TVA | **regenerare** |
-| **grupul B** — tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi | **regenerare** (decizia 25); blocate in etapa I |
-| **grupul C** — incasare | **regenerare** (decizia 25); blocate in etapa I |
-| **grupul A** — venit/cheltuiala, sectie, responsabil, lucrare | **niciuna din #13** — read-only, editarea e a lui #6 (decizia 26) |
-| nimic | nimic |
-
-### G. Stocul — de ce argumentul lui #6 nu inchide subiectul
-
-Verificarea de stoc **nu** e in `adauga_articol_factura`: acolo erorile sunt de configurare
-("Nu a fost gasita cota de TVA", politica / contract lipsa — `PACK_FACTURARE:5125-5180`).
-Descarcarea efectiva de gestiune se face la emitere, in `contabilizeaza_articol` ->
-`descarca_gestiune` (`:7631+`). Plafonul pe cantitate pe care il vede utilizatorul azi vine din
-**cursorul client** `crsarticole` (`frm_facturare_articole.do_adauga_articol`,
-`ofacturare.vc2:12813-13086`) — cursor care in formularul unificat **nu mai exista**, pentru ca nu
-se mai incarca in masa.
-
-Deci, pe #13:
-
-- in timpul compunerii **nu exista plafon** — coincide cu decizia deja luata de Marius pe #6 la
- 08.08.2026 ("editarea unei facturi emise nu are plafon si nu verifica stocul");
-- la finalizare, daca **stergerea ruleaza inaintea reemiterii, in aceeasi tranzactie**, stocul
- consumat de documentul initial e deja eliberat cand se descarca gestiunea pentru documentul nou.
-
-**Aici e riscul tehnic principal.** Azi stergerea si emiterea deschid fiecare propria tranzactie
-(`do_deschide_tranzactie` / `do_inchide_tranzactie` in ambele cai). O tranzactie nu poate fi tinuta
-deschisa peste minutele in care utilizatorul editeaza formularul. Ordinea corecta e deci:
-**citire (fara tranzactie) -> editare -> o singura tranzactie la confirmare, care contine intai
-stergerea, apoi scrierea.** Asta cere mutarea apelului de stergere in interiorul tranzactiei
-deschise de `do_scrie_articole`, nu inaintea ei.
-
-Atentie si la `VANZARI_DETALII_TEMP`, care e GTT `ON COMMIT DELETE ROWS`: umplerea si consumul
-trebuie sa ramana in aceeasi tranzactie — ceea ce e compatibil cu schema de mai sus, dar interzice
-un `commit` intermediar dupa stergere.
-
-### H. Pretul rescris de server la reemitere
-
-`adauga_articol_factura` (`PACK_FACTURARE:4972-5268`) ramifica pe `V_OPT_FACTURARE` si, pe unele
-ramuri, **re-deriva pretul, cota TVA si valuta din documentul sursa** (ex. `V_OPT_FACTURARE = 3`,
-preturile de pe contract, `:5129-5168`), in timp ce pe ramura implicita valoarea venita din VFP
-castiga (`V_PRET := V_PRET_TEMP`, `:5183-5186`). Planul #6 semnalase deja acelasi lucru.
-
-**Consecinta pentru #13:** pe facturile din contract (si posibil pe alte ramuri), pretul editat de
-utilizator poate fi suprascris tacut la reemitere. De inventariat ramura cu ramura, si de decis daca
-regenerarea trece un flag "preturile vin din formular, nu se re-deriva". **Nu se porneste
-implementarea inainte de acest inventar** — e singurul punct din care poate iesi o factura reemisa
-cu alte sume decat cele confirmate pe ecran.
-
-### I. Asezarea antetului (deciziile 8 si 9)
-
-**Doua grupuri vizibile, restul pliat.** Grupurile si etichetele reale, din inventar:
-
-| Grup | Controale | Note |
-|---|---|---|
-| Identitatea documentului | `Ct_clb_fdoc` („Tip document”: FACTURA / PROFORMA / BON FISCAL), `Clb_serie_act`, `Clb_nract`, `Clb_dataact`, `Clb_data_scadenta`, `Clb_zi_curs`, `Ct_clb_valuta` | scadenta e **dezactivata**, nu eliminata, cand `gnScadentaAutomata = 1` (`ofacturare.vc2:9713-9715`); ziua de curs se elimina pe retur (`:9717-9722`, tipurile 8 si 9 — nu si 24); valuta se elimina cand `in_valuta = 0` (`:9725-9728`) |
-| Partener si sursa | `Ct_clb_nume_client`, `txtCodFiscal` + `But_verifica1` (ANAF), `txtSoldLei`, `Ct_clb_altele` (sursa), `Ct_clb_gestiune_init`, pe aviz `Ct_clb_politici_preturi` | codul fiscal si soldul sunt read-only si derivate |
-| **Pliat** — analitice | `Ct_clb_venchelt`, `Ct_clb_sectie`, `Ct_clb_responsabil`, `Ct_clb_lucrare` | responsabilul si gestiunea sursa se elimina azi cand `gnScadereStoc = 0` sau tipul e 4/7/8/9/48/49 (`ofacturare.vc2:9646-9707`) |
-| **Pliat** — alte date | cele patru grupuri din `frm_alte_date`, vezi B | |
-
-**Butonul de modificare a antetului (decizia 9).** Mecanismul **exista deja**, si e mai fin decat
-credeam: `frm_modifica_factura` (`ofacturare_comun.vc2:5262-5774`) are **patru bife individuale** —
-`chkSerieAct`, `chkNrAct`, `chkDataAct`, `chkDataScad` — fiecare deblocand exact textbox-ul ei
-(`thisform.txtDataAct.Enabled = this.Value`, `:5758-5772`), si toate patru sunt ele insele inactive
-daca documentul nu are numar (`this.chkSerieAct.Enabled = !EMPTY(NVL(poRec.numar_act,0))`,
-`:5736-5750`). **Restul campurilor de antet nu sunt blocate deloc** — delegat, agent, masina, ruta,
-adresa, dataora expediere, text aditional sunt mereu editabile.
-
-In formularul unificat (**decizia 9, forma finala — un singur buton comutator, fara nicio bifa**):
-
-- in bara panoului de antet sta **un singur `but_modifica`**; apasat, deblocheaza **tot antetul** —
- si campurile „moi”, si cele patru de identitate — si **isi schimba imaginea in discheta lui
- `but_salvare`**; documentul deschis pentru consultare ramane inert;
-- **cele patru bife individuale dispar.** Nu se transpun in formularul unificat sub nicio forma:
- butonul e singurul control de protectie a antetului;
-- **si conditia lor se abandoneaza.** Azi bifele de serie si numar sunt ele insele inactive dupa
- `!EMPTY(NVL(poRec.numar_act,0))` (`:5736-5750`); regula asta nu se mai transpune pe campuri.
- Cu antetul deschis, **toate campurile de antet sunt editabile, fara exceptie si fara conditie de
- stare**. E o pierdere deliberata de protectie, in schimbul unei singure reguli inteligibile:
- antet blocat sau antet deschis, atat;
-- a doua apasare **salveaza doar antetul**. E posibil pentru ca
- `do_modifica` cheama azi **exclusiv** `pack_facturare.modifica_date_factura`, cu 15 parametri toti
- de antet, si niciun apel spre articole, note sau `oscrie_in_fisiere` (`ofacturare_comun.vc2:4587-4630`).
- Acopera cazul „vreau sa corectez doar delegatul”.
- **Precizare, ca sa nu se citeasca gresit:** „nu atinge notele si rulajele” e adevarat **la nivel de
- apel VFP**, nu si in Oracle. Corpul procedurii propaga seria, numarul si datele in `JV2007` si `RUL`
- (`PACK_FACTURARE.pck:14428-14459`) — coloane de **identitate**, nu sume: nicio valoare nu se
- recalculeaza. Pentru celelalte zece campuri, scrierea e strict in `VANZARI`. Vezi I-bis.
-- **`Termina` ramane salvarea intregului document**, cu rutarea din G-bis.
-
-**Ce nu exista si trebuie scris:** containerele efectiv folosite in antet nu au un mecanism gata
-facut de blocare. `ct_clb_cautare` are `do_activeaza` / `do_dezactiveaza` (`caut_ora.vc2:780-806`),
-dar acestea doar ascund iconita de cautare, iar in `ofacturare_comun.vc2` nu sunt apelate nicaieri;
-`clb_tx_simplu` (`lb_tx.vc2:551-585`) si `clb_serie_act` (`serii_numere.vc2:7`) **nu au deloc**
-metode de activare. Singura reteta completa din biblioteca e `clb_tx_data.dezactiveaza()` /
-`reactiveaza()` (`lb_tx.vc2:521-538`: `ReadOnly` + `TabStop` + butonul de calendar) — se
-generalizeaza de la ea, nu se inventeaza alta.
-
-Decizia 5 ramane in picioare: **asezarea e identica** la introducere si la modificare; difera doar
-starea antetului.
-
-### I-bis. Contractul lui `modifica_date_factura` (decizia 19)
-
-Raport complet: `docs\cercetare\modifica_date_factura_parametri.md`. Spec `PACK_FACTURARE.pck:921-935`,
-corp `:14392-14462`, singurul apel VFP la `ofacturare_comun.vc2:4599-4614`.
-
-Procedura are **doua regimuri de scriere**, si diferenta dintre ele decide cum se cheama din
-formularul unificat:
-
-| Parametri | Regim | Unde ajung |
-|---|---|---|
-| `V_ID_VANZARE` | doar `WHERE` | identitatea randului; sursa lui `lnIdFact` (`:14424-14426`) |
-| `V_ID_RUTA`, `V_ID_DELEGAT`, `V_ID_AGENT`, `V_ID_MASINA`, `V_DATAORA_EXP`, `V_ID_FACTURARE`, `V_LISTARE_DETALIATA`, `V_TEXT_ADITIONAL`, `V_TIP_SAFT`, `V_EFACTURA` | **scrise neconditionat**, inclusiv cu `NULL` | `VANZARI`, randul curent (`:14414-14423`) |
-| `V_DATA_ACT`, `V_DATA_SCAD`, `V_NUMAR_ACT`, `V_SERIE_ACT` | scrise **doar daca** sunt `NOT NULL` **si** difera de valoarea curenta | `VANZARI` + propagare in `DOCUMENTE`, `ACT`, `IREG_PARTENERI`, `JV2007`, `RUL` (si `RUL.DATAOUT`), toate **dupa `ID_FACT`**, nu dupa `ID_VANZARE` (`:14428-14459`) |
-
-**Consecinta 1 — apelul trimite intotdeauna antetul intreg.** Cele zece campuri din regimul
-neconditionat se scriu cu ce primesc, deci un apel cu `poRec` completat partial **goleste** in baza
-campurile netrimise. Butonul de antet nu poate trimite „doar ce s-a schimbat”: incarca antetul
-curent, aplica modificarile peste el, trimite tot.
-
-**Consecinta 2 — cele patru campuri de identitate ating cinci tabele.** Propagarea dupa `ID_FACT`
-inseamna ca schimbarea seriei sau a numarului dintr-un document atinge toate randurile legate de
-acelasi `ID_FACT`. E acelasi mecanism pe care se sprijina S9 (reemiterea cu `ID_FACT` pastrat) si
-acelasi motiv pentru care ordinea operatiilor conteaza acolo.
-
-**Consecinta 3 — un camp nou.** `V_EFACTURA` se scrie neconditionat dar nu are niciun control in
-niciun formular; azi valoarea vine din `Scatter` sau e fortata `0` (`ofacturare_comun.vc2:4576`).
-In antetul unificat primeste control, langa `V_TIP_SAFT` (ambele tin de raportare, nu de document).
-
-**Unde stau cele 14 in formularul unificat** (raportat la gruparea din I): cele patru de identitate
-in antetul vizibil; ruta, delegatul, agentul, masina, `dataora_exp` si adresa de facturare in
-sectiunea pliata, la „delegat si transport” / „adresa de facturare”; `text_aditional` si
-`listare_detaliata` tot in pliat; `tip_saft` si `efactura` formeaza acolo un **grup nou, de
-raportare**. Niciunul dintre cei 14 nu vine azi din `frm_alte_date` — clasa aceea nu e implicata
-deloc in fluxul `do_modifica`, deci sectiunea B si I-bis nu se suprapun.
-
-### J. Butoanele de linie si adaugarea din sursa (decizia 13)
-
-**Cum sunt azi.** In `frm_facturare_articole` butoanele sunt imprastiate lateral, intre cele doua
-griduri, si sunt iconite de 30x27 fara text: `But_modifica1` / `But_sterge1` la 773/61 si 811/61,
-`But_reset1` la 303/295, `But_urmator1` la 343/348, `But_urmator_tot1` la 343/378, `But_retur` la
-343/407 (`ofacturare.vc2:11192-11257`). **`But_urmator_tot1` — „adauga tot” — nu are nici caption
-nici `ToolTipText`** (`:11257`); metoda lui, `do_adauga_tot` (`:13169-13198`), face SCAN peste
-`crsarticole` si cheama `do_adauga_articol(.T.)` pe fiecare linie.
-
-**In prototip sunt deja unde trebuie**: `But_nou1` si `But_sterge1` la `Top = 175`, gridul la
-`Top = 204` (`:15936`, `:15955`) — adica **deasupra tabelului**, exact cum cere decizia 13.
-`But_nou1.Click -> do_adauga` (`:17118-17122`) e `APPEND BLANK` + focus in grid.
-
-**Ce lipseste: contractele.** `But_urmator_tot1` e vizibil pe `eProforma = 1`, `lCopiere`, tip 3
-(comanda), tip 4 (din avize), 21/28/42/47, 25, 8/9, 24 (`:15113-15245`). **Tipurile de contract
-(2, 6, 26, 52) nu sunt in lista.** Deci „adauga tot” acopera deja avizele, dar nu contractele.
-
-**Alegerea selectiva — tiparul importului RORIS.** In ROAACNPRO, `cmdImport` („Import Roris &
-Contracte”, `oacnpro.vc2:6894-6905`) face exact ce s-a cerut aici, si merita copiat ca structura:
-
-1. **buton activ conditionat** de document editabil **si** tip care are sursa
- (`llFacturaEditabila and llRorisSauContracte`, `oacnpro.vc2:8117-8145`);
-2. **o metoda unica de intrare** care ramifica pe tip (`do_executa` -> `factura_import`,
- `proceduri_acnpro.prg:3151-3212`);
-3. **dialog modal de selectie** cu coloana de bifat si criterii de cautare (`frm_tranzit`, coloana
- `cAles` legata de `crsConvoaie.ales`, `oacnpro.vc2:14500-14515`, `:14801`), urmat de un al doilea
- nivel de calcul / confirmare;
-4. **populare aditiva** prin `INSERT INTO` in cursorul local de articole, fara nicio procedura Oracle
- — pachetele intra abia la salvare (`proceduri_acnpro.prg:3331-3467`);
-5. **protectie minimala la dublu-import**: butonul se dezactiveaza dupa un import reusit
- (`oacnpro.vc2:7827-7834`), plus avertisment neblocant daca sursa a mai fost folosita
- (`:14915-14930`).
-
-Ce **nu** se copiaza: sursele de date si calculele ACN (`ips_*`, tarife, ecluzari), formularele lor,
-si valorile `poDate.cTip`. Ce trebuie facut mai bine: la zero rezultate, dialogul RORIS nu spune
-nimic — butonul pare ca nu face nimic (`oacnpro.vc2:14898-14943`).
-
-**Bara propusa, deasupra gridului (decizia 13):** linie noua · sterge linia · detalii linie ‖
-**un singur buton „Adauga articole”**, care deschide un `xmenu()` cu optiunile potrivite sursei —
-nu doua butoane separate. Tiparul e deja folosit in produs: `frm_facturi.but_modifica1` ->
-`inainte_de_do_modifica` -> `xmenu("Modificare date factura;Editare factura (articole, cantitati,
-preturi)")` (`ofacturare_comun.vc2:4925-4934`).
-
-| Sursa documentului | Optiunile din meniu |
-|---|---|
-| comanda | Adauga tot din comanda · Alege din comanda… · Cauta in lista de preturi… |
-| contract | Adauga tot din contract · **Alege ratele de facturat…** · Cauta in lista de preturi… |
-| avize | Adauga tot din avize · Alege avizele… · Alege liniile din avize… · Cauta in lista de preturi… |
-| lista de preturi | Cauta in lista de preturi… · Retur de articole… |
-| retur (tip 8, 9, 24) | Alege facturile de returnat… · Alege liniile de returnat… · Cauta in lista de preturi… |
-
-**Constanta meniului (deciziile 16 si 18): ultimele doua optiuni sunt aceleasi peste tot** —
-**„Cauta in lista de preturi…”** (cu pret din politici) si **„Alege din nomenclator…”** (cu pret
-tastat, ca „Alte servicii” din ROAAUTO, O-bis). Apar inclusiv pe documentele cu sursa, pe cele de
-retur si pe cele deja emise care se modifica. Sursa umple documentul, nu il inchide.
-
-**Decizia 20 (Marius, 09.08.2026): din nomenclator se pot alege si articole gestionabile, si
-negestionabile.** Nu se preia filtrul `in_stoc = 0` al lui ROAAUTO — acolo e o ocolire a subiectului
-gestiunii, nu o regula de produs. Consecinta directa: pe documentele auto vor putea aparea linii care
-descarca stoc langa linii care nu descarca, caz care azi nu exista nicaieri (O-bis, intrebarea 2).
-
-#### J-bis. Contul de venit al liniei — intrebarea lui Marius era corect pusa
-
-Doua cercetari, a doua o corecteaza pe prima. **Valabil e al doilea raport:**
-`docs\cercetare\cont_venit_corespondente.md`. Primul (`cont_venit_articol_fara_politica.md`) ramane
-util pentru contul de **gestiune**, dar concluzia lui pe venit e gresita si nu se citeaza.
-
-**Ce a gresit primul raport.** A cautat literalii `707` / `704` / `706` / `708` in `pack_facturare`,
-nu i-a gasit (corect — nu sunt hardcodati nicaieri) si a conchis ca **nu exista cont de venit pe
-linie**. Exista. E doar **indirect**, si sta chiar in `pack_facturare`, nu intr-un pachet de
-contabilitate separat.
-
-**Sunt doua conturi pe aceeasi linie de vanzare, cu surse complet diferite:**
-
-| | Contul de **gestiune** | Contul de **venit** |
-|---|---|---|
-| Unde ajunge | `VANZARI_DETALII.CONT` (`varchar(4)`) | `SCC` in randul de nota contabila |
-| De unde vine | `NOM_ARTICOLE.CONT` / `STOC.CONT` / `NOM_GESTIUNI.CONT` | `NOTE_CONTABILE.SCC` |
-| Prin ce | alegerea lotului (`do_alege_stoc`) | **politica de pret** a articolului |
-| Cine il consuma | `descarca_gestiune` (`ff_...:7485-7507`) | `scrie_nota` (`ff_...:7452-7476`) |
-
-Lantul care aduce venitul, in `pack_facturare.contabilizeaza_articol` (`ff_...:7182-7556`, cursorul
-`cursor_articol` la `:7227-7280`):
-
-**`CRM_POLITICI_PRET_ART` -> `CRM_POLITICI_PRETURI.ID_NOTA` -> `CRM_NOTE_VANZARI.ID_SET` ->
-`NOTE_CONTABILE.SCD` / `SCC`**
-
-Pentru o factura normala (`ntip <= 20`), `SCD` e contul debitor (creanta) si **`SCC` e contul de
-venit efectiv** al liniei (`ff_...:7407-7437`). Nu e derivat din nimic: perechea SCD/SCC e **scrisa
-manual de un contabil**, per sablon de nota, din ecranul „Configurare note contabile"
-(`COMUN\ferestre\frm_config_note_contabile[2007].sc2`, clasa `onote_contabile.vc2:2401-2435`,
-salvare la `:315-322`, `:486-493`).
-
-**Nu exista tabel de corespondenta 3xx -> 7xx.** Cautat in `SCRIPTURI_CLAR` sub toate numele
-plauzibile — negativ. Ipoteza lui Marius era corecta ca **intentie** (exista un mecanism care leaga
-articolul de contul de venit), dar mecanismul e **configurare manuala pe politica de pret**, nu
-derivare automata din contul de stoc.
-
-**Consecinta care conteaza pentru #13 — si care valideaza intrebarea initiala a lui Marius.** Daca
-contul de venit vine **prin politica de pret**, atunci un articol adaugat **direct din nomenclator,
-fara politica** (exact ce cere decizia 16 / 20) nu are `ID_POL`, deci cursorul de mai sus — filtrat
-`WHERE A.ID_POL = detalii_articol.id_pol` — nu intoarce niciun rand, si `SCD` / `SCC` raman `NULL`
-(sunt `LEFT JOIN`-uri). **Intrebarea „cu ce cont de venit intra un articol fara politica de pret" era
-deci exact intrebarea corecta.**
-
-#### J-ter. Raspunsul: nu „cu niciunul”, ci **eroare** — si nu exista precedent
-
-Verificat: `docs\cercetare\nota_contabila_fara_politica.md`. Doua rezultate, amandoua mai dure decat
-se anticipase.
-
-**1. Codul nu scrie tacut un cont gol — refuza documentul.** `contabilizeaza_articol` cauta politica
-articolului **inainte** de cursorul care aduce `SCC` (`ff_...:7286-7311`), si pe `NO_DATA_FOUND`
-ridica `RAISE_APPLICATION_ERROR` cu **`FACT-024`** („Articolul … nu este definit in politica de
-preturi …”). Cu `id_pol` `NULL`, `ID_POL = detalii_articol.id_pol` nu poate potrivi nimic, deci
-**mereu** se intra pe exceptie. Cursorul cu `SCC` nu se mai deschide. Nu exista ramura de default,
-nu exista fallback, si `scrie_nota` (`ff_...:12338-12570`) **nu are nicio validare pe cont** — dar
-nici nu ajunge sa fie chemat.
-Concluzie: o linie fara politica trecuta prin codul de azi **opreste tranzactia cu eroare**, nu produce
-o nota incompleta. Din perspectiva datelor e vestea buna; din perspectiva lui #13, e blocantul dur.
-
-**2. „Alte servicii" din ROAAUTO NU e precedent** — premisa pe care se sprijinea decizia 18 cade.
-Liniile acelea chiar ajung cu `id_pol` gol (confirmat: nici `crsalteserv`, nici `crsvanztemp`, nici
-semnatura lui `adauga_articol_factura_deviz` nu au `id_pol`, iar `INSERT`-ul in
-`VANZARI_DETALII_TEMP` nu include coloana). **Dar ele nu trec niciodata prin
-`contabilizeaza_articol`**: fluxul ROAAUTO cheama `initializeaza_date_factura` ->
-`adauga_articol_factura_deviz` -> `scrie_in_vanzari` -> `pack_auto.actualizeaza_deviz`
-(`oproceduri_devize.prg:1211-1310`), iar `scrie_in_vanzari` (`ff_...:13497-13962`, citit cap-coada)
-**nu genereaza nicio nota contabila de venit** — copiaza `ID_POL` (deci `NULL`) direct in
-`VANZARI_DETALII` si actualizeaza totalurile.
-Deci ROAAUTO nu demonstreaza ca articolele fara politica sunt tolerate; demonstreaza ca **exista o cale
-paralela de facturare care ocoleste contabilizarea de venit prin `pack_facturare`**. Unde capata acele
-documente contul de venit — daca il capata — **nu se vede in codul cercetat**; `actualizeaza_deviz`
-presupune deja existenta unui rand in `ACT`, a carui sursa nu a fost gasita.
-
-**3. Apelantii sunt trei, si acopera fluxul principal** (lasat neverificat de raportul 2):
-`scrie_factura2` (`ff_...:6150`) — factura normala si majoritatea tipurilor —, `scrie_factura_avize_retur`
-(`:6867`) si `scrie_aviz_retur` (`:7149`). Nu exista al patrulea.
-
-**4. `NOM_ARTICOLE.CONT` ca sursa de venit: NU.** Grep pe `NOM_ARTICOLE.CONT` in tot pachetul — zero
-potriviri. `V_SCC` vine exclusiv din `D.SCC` al lantului de politica. Varianta propusa de Marius nu
-exista nici macar ca ramura moarta.
-
-**Ce inseamna asta pentru perimetru.** „Alege din nomenclator…" nu mai e o adaugare de UI peste un
-mecanism existent: **cere modificare in `pack_facturare`**, adica in COMUN, cu impact peste toata
-suita — sau evitarea completa a lui `contabilizeaza_articol`, ca la ROAAUTO, ceea ce inseamna document
-fara nota de venit. **Aceasta e o schimbare de cost, nu un detaliu**, si se decide de Marius (vezi
-intrebarea deschisa de mai jos).
-
-**`NOM_ARTICOLE.CONT` nu e restrans la clasa 3** — confirmat: `verific_cont`
-(`COMUN\programe\oproceduri_comune.prg:2389-2415`) verifica doar ca acel cont exista in planul de
-conturi al anului (`vplcont_sintetic`), fara filtru de clasa; nu exista `CHECK CONSTRAINT` pe coloana
-si nici vreo ramificare pe `Left(cont,1)` aplicata articolelor. Deci un articol negestionabil **poate**
-purta legitim un cont 6xx / 7xx, cum a spus Marius. **Dar codul de azi nu-l foloseste asa**: acel camp
-merge in `VANZARI_DETALII.CONT` si de acolo la `descarca_gestiune`, niciodata la `SCC`. Ca sugestia lui
-Marius sa devina comportament, ar trebui **cod nou in `pack_facturare`** — adica in COMUN, cu impact
-peste toata suita. *Vezi intrebarea deschisa de mai jos.*
-
-**`ID_VENCHELT` / `NOM_VENIT_CHELTUIELI` nu e sursa contului.** Tabelul nu are coloana de cont;
-`ID_VENCHELT` se rezolva separat (`NVL(nid_venchelt, NVL(A.ID_VENCHELT, C.ID_VENCHELT))`,
-`ff_...:7205`) si pleaca la `scrie_nota` ca **parametru propriu**, alaturi de `SCD`/`SCC` — e o a
-treia dimensiune analitica (centru de venituri/cheltuieli, pentru raportare), nu contul insusi.
-Presupunerea din runda 7 ca „venitul vine din `Ct_clb_venchelt`" **se retrage**.
-
-De unde vine `CONT`, pe cele doua cai:
-
-| Cale | Sursa contului | Fallback |
-|---|---|---|
-| **gestionabil, cu stoc** — trece prin `do_alege_stoc` (`ofacturare.vc2:13239-13345`) | `STOC.CONT`, de pe lotul ales (`cursor_gestiuni_articol`) | **niciunul** — lot cu `CONT` gol ramane `NULL` |
-| **gestionabil, fara stoc** (`RF_FACTURARE_FARA_STOC = 1`) | `NOM_GESTIUNI.CONT` -> ultimul `STOC.CONT` -> `'371'` hardcodat (`cursor_gestiuni_articol_stoc0`) | singurul loc din pachet cu cascada si default |
-| **negestionabil** — `frm_articol_factura` direct (`:12871-12880`) | `NOM_ARTICOLE.CONT`, citit la cautarea articolului | **niciunul**; gol -> sentinela `'XXXX'` -> `NULL` la INSERT |
-
-`adauga_articol_factura` **nu recalculeaza** contul: il primeste ca parametru `V_CONT` si il scrie ca
-atare. **Nu exista nicio exceptie pe `CONT`** in tot pachetul — spre deosebire de cota de TVA, unde
-lipsa produce explicit `FACT-012` / `FACT-013` / `FACT-018`. O linie fara cont se scrie tacut.
-
-**Precedentul ROAAUTO nu ofera o regula, ci absenta ei.** „Alte servicii” (O-bis) trimite literal `''`
-catre `adauga_articol_factura_deviz` (`oproceduri_devize.prg:1256`), care ajunge `NULL` in Oracle,
-fara `NVL` si fara fallback. Liniile de articole reale din ROAAUTO **ajung deci cu `CONT = NULL`**.
-
-**Decizia 21 (Marius, 09.08.2026)** acopera **contul de gestiune**: cand `NOM_ARTICOLE.CONT` e gol pe
-un articol negestionabil ales din nomenclator, se aplica un **fallback la un cont implicit** — nu se
-accepta `NULL` ca la ROAAUTO, nu se refuza adaugarea. Precedentul de forma exista in pachet:
-`cursor_gestiuni_articol_stoc0` cade in cascada pana la `'371'` hardcodat. Contul anume ramane de ales
-la implementare. **Decizia 21 nu rezolva insa contul de venit** — sunt doua campuri diferite, cum arata
-tabelul de mai sus; la momentul cand a fost luata, distinctia nu era inca stabilita.
-
-~~**Decizia 24: articolul ales din nomenclator primeste `id_pol`-ul unei politici de pret
-implicite.**~~ **RETRASA in runda 8.** Argumentul ei — zero cod Oracle nou, COMUN neatins — ramane
-valabil ca argument, dar pretul lui era o intrebare de configurare cu contabilul (care politica, cu ce
-`SCC`, una sau mai multe) si un cont de venit uniform pentru orice articol adaugat asa. Marius a ales
-in loc derivarea contului. **Nu se reintroduce.** *Vezi J-quater.*
-
-Ramane valabil de aici, si e important: **alegerea politicii de catre operator** a fost si ea respinsa
-— muta costul pe fiecare adaugare si cere operatorului sa stie ce inseamna o nota contabila.
-
-**Ce se stie sigur pana atunci:** decizia 16 si decizia 20 **nu sunt anulate** de subiectul asta — pe
-articolele **cu** politica de pret (lista de preturi, comanda, contract, retur) contul de venit vine
-ca azi si nimic nu se schimba. Blocajul e strict pe ramura **„Alege din nomenclator…"**, adica pe
-partea din S4g care adauga articole fara politica.
-
-**Unde e efectiv de lucru pentru asta:** doar pe **comanda**. Verificat
-(`docs\cercetare\retur_si_lista_preturi.md`, B): pe contract, `crsarticole` contine deja lista de
-preturi intreaga, deci adaugarea libera **merge azi**; pe comanda, `cursor_comanda` umple `crsarticole`
-strict cu articolele comenzii (`ofacturare.prg:266-308`), deci nu merge. Restrictia **nu** e pe buton
-si nu e la validare — e in continutul cursorului. Se rezolva ca la copiere: `APPEND FROM` peste
-`crsarticole` cu rezultatul lui `cursor_preturi` (`ofacturare.prg:454-473`).
-
-#### J-quater. Deciziile 27 / 27-bis — contul de venit derivat, aplicat din VFP
-
-> **DEPASITA IN PARTE — de citit cu avertismentul asta in fata.** **Decizia 34** relaxeaza 27-bis
-> (`contabilizeaza_articol` primeste parametru de cont) si **decizia 35** cere ca `pack_facturare` sa fie
-> singurul cod de contare, si la emitere si la editare. Prin urmare:
-> - **punctul 1** (de ce ROAACNPRO si contractul nu sunt contraexemple) si **punctul 2** (derivarea
-> contului din `CORESP_CONT_VENCHELT` — regula deciziei 27) **raman valabile integral**;
-> - **punctul 3, „reteta in 4 pasi"** — politica tehnica per `SCC`, interogarea inversa,
-> `pack_preturi.adauga_politica_pret_art`, inserarea articolului in politica — e **ABANDONAT**. Se
-> pastreaza doar ca trasabilitate a rationamentului. **Nu se implementeaza si nu se reargumenteaza.**
-> - **cele trei variante** de la finalul sectiunii (reteta / nota pe antet / nota pe antet ca fallback)
-> sunt **caduce**: alegerea a fost facuta prin decizia 34.
->
-> Proiectarea in vigoare e parametrul deciziei 34 — `docs\cercetare\parametru_cont_contabilizeaza_articol.md`.
-
-Raport: `docs\cercetare\coresp_cont_venchelt.md`. Trei lucruri s-au stabilit, in ordinea in care conteaza.
-
-**1. Intrebarea lui Marius („in ROAACNPRO si pe factura din comanda / contract se adauga articole fara
-politica — de ce nu si aici?") a primit raspuns: observatia e reala, dar niciunul din cele doua exemple
-nu e un contraexemplu.** `FACT-024` ramane blocantul.
-
-- **ROAACNPRO nu foloseste deloc `contabilizeaza_articol`.** Salvarea facturii ACN
- (`proceduri_acnpro.prg:3331-3467`) merge pe `initializeaza_date_factura` ->
- **`adauga_articol_factura_deviz`** -> **`scrie_in_vanzari`** -> **`pack_acn.salveaza_regdoc`**.
- Cautare directa dupa `contabilizeaza_articol` in acel fisier: **zero rezultate**. Nota contabila o
- scrie o procedura proprie ACN, care nici nu primeste `id_pol` printre parametri. Acelasi tipar ca
- ROAAUTO „Alte servicii" (J-ter, punctul 2): **o cale de facturare paralela**, nu o dovada ca articolele
- fara politica sunt tolerate.
-- **Pe contract, articolul „liber" nu e fara politica.** `crsarticole` e populat de
- `pack_facturare.cursor_contract` / `cursor_preturi`, care **selecteaza explicit `A.ID_POL`**
- (`ff_...:2162-2167`) si care ruleaza la fiecare apel `completare_politica_stoc` (`ff_...:2151`).
- Deci fiecare rand din grila vine deja **cu o politica reala atasata**. „Adaugare libera pe contract"
- inseamna „orice articol din lista de preturi, nu doar cele din contract" — nu „articol fara politica".
-
- **Diferenta reala e cursorul-sursa al grilei, nu tipul de document:** `caut_articol`
- (`COMUN\programe\ocautare.prg:1636-1735`, cautarea in nomenclator) **nu are coloana `id_pol` in nicio
- ramura**; `cursor_preturi` / `cursor_contract` o au, pentru ca pleaca de la politica, nu de la
- nomenclator. Povestea #13 cere exact ce nu exista azi nicaieri.
-- **Ce verifica de fapt `FACT-024`:** `SELECT COMPUS, ID_POL_ART FROM VCRM_POLITICI_PRET_ART WHERE
- ID_ARTICOL = ... AND ID_POL = ...` (`ff_...:7278-7302`) — deci **apartenenta articolului la politica
- de pe linie**. Ipoteza din runda 8 e **partial** confirmata: verificarea e de apartenenta, dar `id_pol`
- **nu** vine din antet ca valoare unica — e parametru per linie, trimis de VFP. Doua cauze diferite
- (`id_pol` gol; articol nemembru) produc aceeasi eroare, iar codul nu le distinge.
-
-**2. `CORESP_CONT_VENCHELT` exista, e populat si e folosit in productie — dar niciodata pentru
-`CONT_VENIT`.** Toti consumatorii gasiti (`pack_vin`, `pack_devize`, `gestiune_pack_gest_import`,
-rapoarte de gestiune) citesc `CONT_CHELT` sau `CONT_APROVIZIONARE`. Coloana `CONT_VENIT` **are date
-reale** dar **zero consumatori**, nici Oracle nici VFP. Cheia de join e stabila si testata: pe `CONT`, cu
-`STERS = 0`, prin `LEFT JOIN` — tiparul se copiaza identic. Deci regula lui Marius e implementabila; e
-insa **un consumator nou**, nu o reteta deja rulata.
-
-**Masurat pe baza vie (10.08.2026, `MARIUSM_AUTO`) — `docs\cercetare\verif_baza_vie_cont_venit.md`:**
-tabelul are **41 de randuri active**, din care exact **20 au `CONT_VENIT`** populat; restul 21 sunt
-conturile de ajustari (`391`…`398`, toate cu `CONT_CHELT = 681`), care nu poarta marfa. **Niciun `CONT`
-nu e duplicat**, deci pasul 1 al retetei e determinist — desi schema nu are unique pe `CONT`, doar `PK`
-pe `ID_CCV`. Si, decisiv: **zero articole active cad pe un rand cu `CONT_VENIT` gol**, deci ramura
-„cont derivat gol" se trateaza defensiv dar nu are cazuri reale. DDL-ul complet e in raport.
-
-**3. Calea VFP (decizia 27-bis) exista si e construita din piese functionale.** Patru pasi.
-
-> **Clarificare ceruta de Marius (10.08.2026) — de citit inainte de cei patru pasi.** Politica **nu e
-> necesara ca sa se afle contul.** Regula deciziei 27 il determina complet, in VFP: corespondentele pe
-> clasa 3, contul de pe articol daca e 6xx / 7xx, `704` altfel. Aia e **pasul 1**, si e verificata pe date.
-> Politica e necesara **doar ca canal de transport** catre Oracle: `contabilizeaza_articol` **nu are
-> parametru de cont de venit** — primeste `V_ID_POL` si deduce singura contul prin lantul politica → nota →
-> `NOTE_CONTABILE.SCC`. Deci **pasii 2-4 nu decid nimic**, doar convertesc un cont pe care VFP il stie deja
-> intr-o forma pe care pachetul o accepta. Indirectarea e consecinta deciziei **27-bis**, nu a regulii lui
-> Marius: daca pachetul ar putea fi modificat, un parametru de cont ar face pasii 2-4 sa dispara.
-> **INCHIS (runda 9 + decizia 35).** Cautarea canalului direct s-a terminat —
-> `docs\cercetare\canal_cont_venit_fara_politica.md`. Verdict: canalul **exista** (`actactan` / `tact` →
-> `oscrie_in_fisiere` → `pack_contafin.SCRIE_IN_ACT`), dar e cablat pe **editarea unei note deja scrise**,
-> nu pe emitere; emiterea trece exclusiv prin `scrie_factura2` → `contabilizeaza_articol`. Pistele
-> `V_CONT` (e contul de gestiune), setterele de sesiune, `ID_VENCHELT` si `GetAnaliticByGrupUtilizatori`
-> sunt **toate NU**.
-> **Si nu se foloseste oricum:** decizia 35 il respinge explicit in #13, ca sa nu existe doua coduri de
-> contare. Reteta in 4 pasi cade prin **decizia 34** (parametru de cont in pachet), nu prin canal.
-
-1. **VFP calculeaza `SCC`-ul** dupa regula deciziei 27: `CORESP_CONT_VENCHELT.CONT_VENIT` pe contul de
- gestiune al liniei (articol gestionabil), `NOM_ARTICOLE.CONT` daca e 6xx / 7xx, altfel `'704'`.
-2. **VFP cauta o politica a carei nota are deja acel `SCC`** — interogarea inversa pe acelasi lant:
- `CRM_POLITICI_PRETURI -> CRM_NOTE_VANZARI -> NOTE_CONTABILE`, `WHERE NC.SCC = :cont_calculat`.
- Interogare **noua**, dar pe coloane si relatii deja confirmate.
- **Corectat pe baza vie:** legatura nu e politica -> nota, ci politica -> **set de note** —
- `CRM_POLITICI_PRETURI.ID_NOTA` -> `CRM_NOTE_VANZARI.ID_SET` -> `NOTE_CONTABILE.ID_SET`. Pe cele 7 note
- de vanzari active fiecare set are **un** rand, dar in tabel exista seturi cu pana la **30** de randuri,
- deci „nota politicii" e bine definita doar cat timp seturile de vanzari rămân cu un rand.
- **Si mai important: filtrarea pe `SCC` singur nu e suficienta** — vezi „Ce nu e gratuit" mai jos.
-3. **VFP se asigura ca articolul e membru al acelei politici** — RPC **existent**
- `pack_preturi.adauga_politica_pret_art`, deja folosit exact asa (verifica intai, insereaza daca
- lipseste) in `ofacturare.vc2:15551-15587`, la modificarea listei de preturi de la NIR. **`pack_preturi`
- nu e `pack_facturare`** — nu se atinge nimic din pachetul comun de facturare.
-4. **VFP trimite acel `id_pol`** in `adauga_articol_factura` (`V_ID_POL` e parametru de intrare explicit,
- `ff_...:4989-5015`). `contabilizeaza_articol` ruleaza **neschimbata**.
-
-**Modelul „politica tehnica, configurata o data, populata automat" exista deja in pachet:**
-`completare_politica_stoc` (`ff_...:2093-2120`) face `MERGE` in `CRM_POLITICI_PRET_ART` pentru toate
-articolele `IN_STOC = 1` sub politica `pack_facturare.nid_politica_stoc`, alimentata din optiunea globala
-`gnId_pol_pret_stoc` (`ofacturare.vc2:21733-21753`). Nu e direct reutilizabila — are o singura nota
-pentru toate articolele, iar decizia 27 cere pana la sase conturi diferite — dar arata ca tiparul e
-acceptat in produs.
-
-**Calea VFP e mai completa decat modificarea pachetului**, nu doar mai ieftina: politica reala aduce si
-`CU_TVA`, `IN_VALUTA`, `EXPLICATIE`, `ASCD`, `ASCC` din nota configurata. Un fallback in
-`contabilizeaza_articol` ar da doar `SCC`; `CU_TVA` si `IN_VALUTA` **nu au nicio sursa alternativa** in
-afara lui `NOTE_CONTABILE`, deci ar trebui hardcodate — cu risc de calcul gresit al bazei si al TVA.
-
-**Ce nu e gratuit, si trebuie stiut inainte de S4g:**
-
-- **Pasul 2 depinde de configurarea fiecarui client — deci nu se poate proiecta pe acoperire.**
- Decizia lui Marius, 10.08.2026: **datele din Dev nu sunt baza de proiectare.** Fiecare client isi
- defineste propriile politici de pret, fiecare cu nota ei de vanzare salvata pe un `ID_SET`. Pe schema
- de dezvoltare masurarea a dat `704` cu 19 politici valabile, `707` cu 4, `7015` cu 1, si zero pentru
- `711` / `702` / `703` / `7018` — **dar aceste numere nu se folosesc ca argument**, pe o baza de client
- distributia poate fi complet alta. Ce se pastreaza din masurare e strict **structural** (forma lantului,
- absenta unique-ului pe `CONT`, bug-ul de set multi-rand) plus un fapt negativ: **afirmatia rundei 8 ca
- „pentru `704` nu exista nicio nota configurata" nu se susține ca regula** — pe Dev exista patru, deci
- pasul „se creeaza nota pentru 704" nu poate fi pus in plan ca obligatoriu.
- **Consecinta de proiectare:** reteta nu are voie sa presupuna ca gaseste o politica pentru `SCC`-ul
- calculat. Ori garanteaza singura existenta a ceea ce foloseste (politica tehnica creata de produs), ori
- are o cale care **nu trece prin politica deloc** — vezi mai jos.
-- **`PTVA` de pe nota e inofensiv — verificat pe cod, nu presupus.** `cursor_articol`
- (`PACK_FACTURARE:7218-7271`) **nu selecteaza `D.PTVA`**; cota folosita efectiv vine din
- `detalii_articol.proc_tvav * 100 - 100` (`:7464`), adica din articol / document. Deci o nota cu
- `PTVA = 5` pe un articol cu 21% **nu produce nimic** — coloana e moarta pentru aceasta procedura.
- Ingrijorarea initiala („criteriul trebuie sa fie `(SCC, PTVA)`") **se retrage**.
- `IN_VALUTA = 1` de pe nota pe un document in lei nu da nici eroare, nici suma greșita — doar populeaza
- redundant `ACT_TEMP.SUMA_VAL` la curs 1 (`scrie_nota:12391-12404`, `:12492-12507`): inconsistenta
- cosmetica, nu contabila. `ASCD` / `ASCC` nule au fallback automat prin
- `GetAnaliticByGrupUtilizatori` (`:7409-7428`), iar `ID_PARTD` / `ID_PARTC` **nu se citesc de pe nota**
- deloc — vin din contul si din contextul documentului (`:12510-12530`).
-- **In schimb, `ID_SET` cu mai multe randuri dubleaza venitul SI descarcarea de gestiune.** Asta e
- riscul real, si e mai grav decat cel presupus. `cursor_articol` face `LEFT JOIN NOTE_CONTABILE D ON
- C.ID_SET = D.ID_SET` **fara `ROWNUM`, fara agregare, fara filtru**, iar bucla care il consuma
- (`:7393-7542`) executa `scrie_nota` **si** `descarca_gestiune` **o data pentru fiecare rand al
- setului, cu aceeasi cantitate si acelasi pret intreg de fiecare data** — nu impartite. Nu exista
- nicio logica de distributie: `ORDINE` nu apare in tot pachetul. Deci pasul 2 nu trebuie doar sa
- gaseasca un rand cu `SCC`-ul potrivit, ci **sa garanteze ca setul ales are exact un rand**. Cele 7
- note de vanzari active au, azi, exact un rand fiecare — dar 30 din cele 40 de seturi din baza au mai
- multe, cu maxim 30. **Conditia care face reteta sigura e o coincidenta a datelor curente, nu o
- garanție a codului.** Sursa: `docs\cercetare\s10_pret_rederivat.md`, „Completare: nota contabila a
- politicii", punctul 1.
-- **Pasul 3 poluează o lista de preturi de producție.** Politica **este** lista de preturi: candidatele
- reale contin `STOC PRODUSE` cu **6310** articole si `LISTA PRETURI LEI` cu **909**, plus liste cu nume de
- client si de sezon (`CHIOSC`, `SERVICE AUTO`, `S7 CRACIUN`…). Un articol adaugat ad-hoc pe factura ar
- aparea de acum in acea lista, cu pretul cu care a fost facturat o data. **Deci pasul 2 nu trebuie sa
- caute orice politica potrivita, ci o politica tehnica dedicata, una per `SCC`** — modelul
- `gnId_pol_pret_stoc` extins de la una la sapte. Cele **sase** politici cu 0 articole din baza vie arata
- ca o politica goala e o stare acceptata de produs.
-- **Ambiguitatea celor 19 politici pe `704` e de lista de preturi, nu de rezultat contabil** — majoritatea
- trimit la aceeasi `id_nota = 1`, deci toate dau `704` / `PTVA = 21` / lei. Cu atat mai mult, criteriul de
- departajare corect e „care lista de preturi accept sa murdaresc", iar raspunsul e „niciuna dintre cele
- existente".
-- **Politica tehnica devine vizibila utilizatorului** in `caut_politici_curente_util()` — aceeasi functie
- ca la cautarea normala. Ori se filtreaza explicit (flag / prefix dedicat), ori se accepta riscul ca
- cineva sa o aleaga din greseala pe o factura normala. **De decis in S4g.**
-- **`id_pol` devine populat** acolo unde azi ar fi gol. Nu s-a gasit cod care sa presupuna „`id_pol` gol =
- articol fara politica", dar nici nu s-a cautat exhaustiv.
-- **Doua politici active nu au `ID_NOTA`** (`32 HOTEL TAXE`, `33 HOTEL CAZARE`) — `id_pol` valid, nota
- absenta. Ce face `contabilizeaza_articol` in acest caz e intrebare deschisa, trimisa pe cod. E o gaura
- care **exista deja azi**, independenta de #13.
-
-**RASPUNS LA DECIZIA 32 — reteta RAMANE. `docs\cercetare\idpol_comanda_contract.md`.**
-
-Intrebarea era: cum alege programul nota contabila la factura din comanda, care „nu are politica de pret"?
-**Raspuns: are. Structural nu poate sa nu aiba.** `COMENZI_ELEMENTE.ID_POL` e **`NOT NULL`** la nivel de
-schema (constrangerea `SYS_C0015376`, plus `FK_COMENZI_ELEMENTE_002`) — verificat direct: **0 din 7108
-randuri** au `ID_POL` nul sau zero, 9 politici distincte in uz, toate cu nota atasata. Deci nu exista nicio
-ruta alternativa catre nota, si **nu exista contradictie cu concluzia rundei 8**: pe comanda cazul „`id_pol`
-gol" e imposibil, nu doar neintalnit. Ce percepe operatorul ca „n-am ales nicio politica" e faptul ca
-politica se alege **o data pe comanda** — manual sau moștenita dintr-o optiune legata de tipul comenzii —
-si de atunci fiecare articol adaugat o primeste automat, din `com_vpreturi_utilizator`, view care filtreaza
-`id_pol IS NOT NULL` la sursa. Pe **contract** tiparul e acelasi, dar cheia stocata e
-`CTR_ARTICOLE.ID_POL_ART` — FK direct la randul din `CRM_POLITICI_PRET_ART`, **nullable**, cu cazuri reale.
-
-**De ce `FACT-024` nu se declanseaza pe comanda / contract:** nu pentru ca ar exista un fallback, ci pentru
-ca **articolul nu e ales niciodata din nomenclator** — e ales dintr-o lista deja filtrata pe politica, deci
-apartenenta e garantata **prin construcția listei**, nu prin validare. Exact aici e diferenta cu #13, unde
-`caut_articol` ofera nomenclatorul intreg.
-
-**Deci refolosirea nu simplifica nimic:** mecanismul de jos — RPC de inserare + apartenenta garantata — e
-**exact** ce propune reteta in 4 pasi. Ce ar simplifica cu adevarat („ia politica curenta fixa si pune
-articolul in ea") e **decizia 24, retrasa**, si motivul retragerii sta: o politica unica da **un singur**
-cont de venit oricarui articol, indiferent de natura lui — opusul deciziei 27. Comanda si contractul nu
-raspund niciodata la intrebarea „**care** politica pentru **acest** articol", pentru ca la ele politica vine
-gata aleasa, o data, de operator.
-
-**CORECTIE, a doua tura a aceluiasi agent — premisa lui Marius ERA corecta, dar pe contract, nu pe comanda.**
-Exista o ruta reala catre nota contabila **complet in afara lui `id_pol`**: la **contractele cu rate /
-scadentar** (`OPT_FACTURARE IN (1, 2)`), o functie separata — **`contabilizeaza_rata`** — scrie nota direct
-din **`CONTRACTE.ID_NOTA`**, fara sa treaca prin `CRM_POLITICI_PRETURI`. Confirmat pe cod de agent si pe o
-factura reala (`id_vanzare 360`: `SCD = 4111` / `SCC = 704` in `ACT`, pe o linie fara articol si fara
-politica). **Structura confirmata independent de sesiunea principala:** `CONTRACTE.ID_NOTA` exista, e
-nullable, si e **populat pe 19 din 242 de contracte**, rezolvand la note reale — `1 NOTA 1` → `SCC 704`
-(5 contracte), `2 DISCOUNT` → `SCC 4111` (5), `5 VANZARE MARFA` → `SCC 707` (1). Deci nota **pe antetul
-documentului** nu e o ipoteza, e un mecanism in uz.
-
-**Ce inseamna asta pentru #13, si de ce e o decizie de produs, nu una tehnica.** Tiparul „nota pe antet"
-ar fi **mai simplu decat reteta in 4 pasi**: n-ar mai fi nevoie nici de gasirea politicii, nici de
-inserarea articolului in ea, nici de politica tehnica — antetul ar purta nota, iar liniile ad-hoc ar
-moșteni-o. **Dar cere cod nou in `pack_facturare`**, pentru ca `contabilizeaza_rata` trateaza rate, nu
-articole de factura. Adica **incalca exact decizia 27-bis** („`pack_facturare` nu se atinge").
-**Deci alegerea e a lui Marius, intre trei variante:**
-
-1. **reteta in 4 pasi** (decizia 27-bis respectata, `pack_facturare` neatins, dar cere politica tehnica per
- `SCC` si o interogare inversa noua);
-2. **nota pe antet ca la `contabilizeaza_rata`** (mult mai simplu si mai curat conceptual, dar **relaxeaza
- decizia 27-bis** — cod nou in pachetul comun intregii suite);
-3. **nota pe antet doar ca fallback** pentru articolele fara politica, lasand restul neschimbat.
-
-**Nu se implementeaza nimic pana la aceasta alegere.** Detalii: `idpol_comanda_contract.md`, sectiunea E-bis.
-
-**Doua observatii din date, gasite la confirmarea verdictului:**
-
-- **Precedentul cerut de decizia 27 exista deja in producție, si e mai bun decat `gnId_pol_pret_stoc`.**
- Politica `7 DISCOUNT` apare pe **870 de linii de comanda** si trimite la nota `2 DISCOUNT`
- (`SCD = 667`, `SCC = 4111`). E o politica de pret folosita **exclusiv ca mecanism de rutare contabila**,
- nu ca lista comerciala de preturi. Deci „politica tehnica, dedicata unui cont, populata automat" nu e o
- invenție a lui #13 — **produsul o face deja**, pentru discount. Argument direct pentru politica tehnica
- per `SCC`.
-- **Garantia prin construcția listei nu e etanșă in date: 37 de linii de comanda au un articol care NU e
- membru al politicii de pe linie.** **VERIFICAT (runda 10)** —
- `docs\cercetare\linii_comanda_articol_nemembru.md`. **Decizia 32 NU se redeschide in sensul periculos:
- nu exista cale de cod care sa ocoleasca `FACT-024`.** Patru rezultate:
- - **Cifra 37 se reconfirma, dar numitorul din plan era gresit** — `6868` era alt numitor; cel corect
- pentru linii cu `ID_POL NOT NULL` e **7108**.
- - **Premisa „37 de linii ar cadea la facturare" era partial gresita.** Un rand cu `CANTITATE < 0` **nu
- dovedeste ca linia a fost facturata**: singurul loc care il insereaza e `inchide_comanda`
- (`PACK_FACTURARE:5769-5820`), care scrie *diferenta ramasa* la **inchiderea** comenzii, chiar si cand
- nimic nu s-a facturat pe acea linie. **34 din 35 de linii negative n-au nicio factura in spate, nici
- macar stearsa** — comenzile au fost inchise, nu facturate.
- - **Una singura chiar a ajuns intr-o factura emisa** — comanda `497`, articolul `4294507522`
- („VOUCHER DISCOUNT") pe politica `7` („DISCOUNT"), in factura `ID_VANZARE = 1028`, `20.03.2026`. Si
- codul **chiar a rulat** `contabilizeaza_articol` pentru ea: apelul e in ramura `ELSE` a lui
- `CASE pack_facturare.ntip` din `scrie_factura2`, care exclude doar transferurile, avizele de custodie
- si facturile cu rate — tipul 3 cade in `ELSE`. Deci **fie articolul era membru al politicii la
- 20.03.2026 si a fost scos ulterior, fie verificarea a fost ocolita altfel; dovada pentru a doua
- varianta nu exista.**
- - **Cauza e NEDETERMINABILA DIN DATE, structural.** `CRM_POLITICI_PRET_ART` **n-are coloana `STERS`** si
- n-are tabel de istoric — stergerile sunt **fizice, fara urma**, deci nu se poate reconstitui starea de
- la 20.03.2026. Coloanele de audit ale facturii (`VANZARI.ID_UTILS` / `DATAORAS` si cele de pe cele
- doua linii) sunt **toate NULL**, deci nici o editare ulterioara nu s-a inregistrat. Indiciu de tipar,
- nu dovada: aceeasi pereche articol-politica apare pe **35 de comenzi diferite**, ceea ce sustine o
- **curatare de catalog** mai degraba decat 35 de greseli independente de introducere.
-
- **Ce ramane, si cum se formuleaza:** pentru celelalte 36 de linii, „zero facturi in date" **nu
- demonstreaza ca nu se pot factura** — demonstreaza doar ca nu s-a intamplat. Iar cu starea de azi a lui
- `CRM_POLITICI_PRET_ART`, toate cele 37 **ar** cadea cu `FACT-024` daca ar trece acum prin
- `contabilizeaza_articol` (verificat pe view-ul `VCRM_POLITICI_PRET_ART`, care n-are filtru propriu, deci
- vede exact aceleasi perechi ca tabelul). **Concluzia pentru #13 e neschimbata:** garantia prin
- constructia listei e reala cat timp catalogul nu se editeaza sub documente deja emise.
-
-**Verificarile pe baza vie sunt facute** (10.08.2026) — `docs\cercetare\verif_baza_vie_cont_venit.md`:
-interogarea inversa pe fiecare `SCC` candidat, DDL-ul lui `CORESP_CONT_VENCHELT`, distributia articolelor
-pe ramurile deciziei 27 (6125 din 6430 pe ramura gestionabila), efectele colaterale ale pasului 3 si trei
-fragilitati de structura. **Rămâne deschisa doar partea de cod**, listata mai sus.
-
-### K. Discountul pe linie (decizia 14)
-
-Verificat de doua ori, pe formularul real si pe DDL. Raspunsul la intrebarea „e doar procentual?” e
-**nu, si nici doar valoric — sunt amandoua, dar in alta fereastra**.
-
-**Intrarea pentru operator exista deja, in dialogul de articol.** `frm_articol_factura`
-(`ofacturare.vc2:1108-2659`), deschis la fiecare adaugare de articol, are trei campuri legate:
-`Clb_procent_discount` (procent), `Clb_discount_unitar` (suma, in lei sau valuta) si
-`Clb_discountctva` (varianta cu TVA). Toate cheama
-`frm_articol_factura.do_calculeaza_discount(valoare, tip)` (`:1874-1976`) cu `tip = 1` procent,
-`tip = 2` lei, `tip = 3` valuta (`:2602-2649`) — tastezi in oricare, se recalculeaza celelalte.
-Rezultatul intra in `poArticol.discount_unitar` si variantele lui, apoi in `crsfactura` prin
-`Replace` (`:12956-12957`).
-
-**Se stocheaza o singura coloana, si e valoare.** `VANZARI_DETALII.DISCOUNT_UNITAR NUMBER(22,6)`
-(`ff_2024_06_13_02_COMUN_FACTURARE.sql:3`; simetric pe `VANZARI_DETALII_TEMP` la `:9` si pe
-`CRM_POLITICI_PRET_ART` la `:16` — **trei tabele diferite, nu aceeasi coloana de trei ori**).
-**Nu exista coloana de procent** pe `VANZARI_DETALII` — procentul e doar mod de introducere.
-Parametru Oracle: `V_DISCOUNT_UNITAR` in `adauga_articol_factura`
-(`ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql:4986`), scazut din pretul fara TVA inainte de TVA
-(`:15794-15847`).
-
-**In grid, azi, comportamentul e inconsecvent.** Pe factura in lei ramane `cDiscountCTva`, care e
-`ReadOnly = .T.` (`ofacturare.vc2:12311-12317`); pe factura in valuta ramane `cVdiscountftva`, care
-**e editabila** — dar nu are niciun `Valid` / `InteractiveChange`, deci o editare directa in celula
-schimba valoarea bruta fara sa refaca totalurile. Excluderea reciproca e la `:15269-15278`.
-
-**Corectie fata de runda 3:** afirmasem ca prototipul are deja procent pe linie, ca argument pentru
-pornirea de la el. **Fals.** `procdisc` apare o singura data in tot fisierul, ca `ControlSource` de
-coloana (`:16721`), fara niciun `Replace` care sa-l populeze si fara corespondent Oracle — e schela
-moarta. (Restul aparitiilor de „procdisc” sunt variabila de optiune `gnMemProcDisc`, altceva.)
-Argumentele pentru prototip raman celelalte doua: controalele de antet si butoanele deasupra gridului.
-
-**Ce ramane de facut:**
-
-- cele doua campuri din dialogul de articol devin **coloane in grid** — procent si valoare unitara —
- cu **acelasi calcul reciproc** din `do_calculeaza_discount`, mutat pe evenimentele coloanelor;
-- se repara astfel si inconsecventa de mai sus: aceleasi validari in ambele monede;
-- se pastreaza excluderea pe `in_valuta`;
-- modelul de date **nu se atinge**;
-- **de verificat separat, blocant**: daca `discount_unitar` apare pe rapoartele `.frx` si daca e
- transmis in eFactura (UBL) si SAF-T. Daca nu apare pe hartie, documentul tiparit nu explica totalul.
-
-#### K-bis. Discountul de DOCUMENT — cota, explicatia si atribuirea pe cote
-
-Cercetare terminata, verificata la sursa (doua runde, a doua a corectat concluzii ale primei —
-vezi rezervele de mai jos). Detaliu complet: `docs\cercetare\discount_document_cota_tva.md`.
-
-**Cota discountului de document = cota MAXIMA de pe factura, ca regula implicita.** Nimeni n-o
-alege: nu exista control in formular si nicio coloana pe `VANZARI` pentru ea.
-`Calculate Max(proc_tvav)` — `COMUN\programe\oproceduri_facturare.prg:1387`,
-`COMUN\clase\ofacturare_comun.vc2:4495` si `:7294`, `COMUN\programe\ofacturare_stoc.prg:582`.
-Discountul intra ca **pseudo-linie negativa** printr-un rand-sentinela `Replicate('Z',20)`
-(`COMUN\programe\ofacturare_comun.prg:1886-1897`), care devine linia „Discount NN.NN % Factura"
-(`:1273-1392`).
-
-**Explicatia nu exista ca notiune — e o constanta.** In XML, `AllowanceChargeReason="Discount"`
-si `ReasonCode="95"` sunt hardcodate (`COMUN\programe\xmlefactura.prg:774-776`), la fel
-`currencyID="RON"` (`:778`). Textul construit in VFP („Discount 10.00 % Factura") nu ajunge in
-XML.
-
-**Regula e implementata de doua ori, independent — nu intr-un singur loc.** In VFP (mai sus) si
-in PL/SQL: `PACK_FACTURARE.recalculeaza_totaluri_vanzari`,
-`MAX(ROUND(discount*(a1.proc_tvav-1),...)) as DISC_TVA_RON` —
-`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16081-16092`,
-scris in `VANZARI.DISCOUNT_TVA` si de acolo in `TOTAL_TVA` / `TOTAL_CU_TVA` (`:16214-16227`).
-**Pentru #13: doua locuri de schimbat, nu unul** — daca se schimba doar unul, `VANZARI.TOTAL_TVA`
-si TVA-ul din XML diverg pe facturile cu cote mixte.
-
-**Defectul dovedit e de atribuire fiscala, nu de validare.** Pe cote mixte, tot TVA-ul
-discountului se scade din cota maxima. Exemplu: 1000 lei la 21% + 1000 lei la 11%, discount de
-document 10% (200 lei) → se declara 10 lei TVA in minus, mereu in acelasi sens (TVA colectat
-subdeclarat). Aceeasi valoare gresita ajunge si in nota contabila si in jurnalul de TVA. Caz-limita
-real, masurat: daca liniile de la cota maxima sunt o mica parte din total, `TaxSubtotal` iese cu
-baza negativa (`TaxableAmount = -410.00`).
-
-**Ipoteza bazei negative — verdict nuantat, asa cum a iesit din verificare, nu simplificat.**
-Temerea: pseudo-linia, avand `id_jtva_coloana = 0`, iese din `LEFT JOIN` cu `coloana_jv` NULL si
-formeaza grup propriu in `C_TVA_FACTURA`. **Infirmata pe factura obisnuita** — masurat headless,
-`IIF()` din VFP intoarce ramura falsa, nu `.NULL.`, cand conditia e nula, deci pseudo-linia se
-contopeste corect. **Confirmata insa pe facturile scutite / taxare inversa / intracomunitare**,
-unde liniile reale au `scutit = 1` si `expltva` completat iar pseudo-linia are `0` si gol: apar
-doua grupuri, deci un `TaxSubtotal` in plus cu baza negativa si categoria `Z`, iar
-`agettipcota(1)` (`xmlefactura.prg:782-786`) devine ambiguu intre `E` si `Z`.
-
-**Nu blocheaza factura — validat, nu presupus.** Validat offline cu DUKIntegrator, 6 scenarii,
-inclusiv un control negativ care chiar iese cu erori (`BR-CO-13` + `BR-CO-15`) — deci cele „ok"
-inseamna ceva. Trece inclusiv un caz cu `TaxableAmount = -400.00`. Regulile pe categorii
-(`BR-S-08` / `BR-E-08` / `BR-Z-08`) se satisfac trivial: aritmetica inchide, modelarea fiscala e
-cea gresita, si asta niciun schematron nu prinde. **Rezerva de scris explicit:** validatorul local
-e din 2022; validatorul ANAF online n-a fost apelat (interdictie).
-
-**`currencyID="RON"` hardcodat e neconformitate reala si activa, dar fara dovada ca ar cauza
-respingere.** Dovedit pe fisier: XML-ul in EUR de la VENDING_MASTER e identic pe SHA256 cu cel din
-`TRIMISE` (deci exact ce a plecat la ANAF) si a fost acceptat. Respingerea din `ERORI` e a unei
-incarcari anterioare, pentru alte reguli.
-
-**Nu s-a putut proba pe date reale, si asta ramane netransat.** In baza accesibila sunt 3 facturi
-cu discount de document (toate cu o singura cota, anterioare eFacturii) si 34 cu cote mixte fara
-discount — intersectia e goala. Cele 4 XML-uri de productie cu alocare de document sunt, dupa trei
-indicii independente, discounturi pe linie, nu de document. Absenta din date nu e dovada (regula
-casei). Ramane nedovedit prin rulare: reproducerea end-to-end prin program a scenariului „factura
-scutita + discount de document".
-
-**Recomandarea cercetarii pentru #13:** repartizare proportionala automata pe cote, **nu se cere
-utilizatorului cota**. Discountul de document nu are o cota proprie de ales — natura lui de TVA e
-determinata de liniile pe care le reduce; a pune operatorul sa aleaga inseamna a-i cere o decizie
-fiscala pe care datele o dau deja. Pentru explicatie: un singur camp text optional pe document,
-folosit ca `AllowanceChargeReason` in locul constantei (`ReasonCode` ramane `95`).
-
-**Doua completari obligatorii daca se implementeaza, altfel reparatia e degeaba:**
-- bucatile de discount trebuie sa primeasca **`id_jtva_coloana` al grupului pe care il reduc**, nu
- doar cota — cheia de grupare are cinci campuri si `expltva` se completeaza tot prin
- `id_jtva_coloana`. O implementare care seteaza doar `proc_tva` lasa grupul orfan exact unde e azi;
-- **eFactura nu are nevoie de nicio modificare** — `xmlefactura.prg:758-792` grupeaza deja
- `GROUP BY proc_tva` si emite cate un `AllowanceCharge` per cota.
-
-Doua consecinte vizibile daca se implementeaza: factura tiparita va arata N randuri „Discount X %
-Factura" in loc de unul, si nota contabila primeste TVA-ul discountului spart pe cote.
-
-**Decizia a fost luata — decizia 59 (runda 16): repartizare proportionala pe cote.** Vezi sectiunea
-„Decizia 59" de la deciziile rundei 16, cu toate consecintele de implementare.
-
-**Cele doua puncte ramase s-au inchis si ele, tot in runda 16.** Campul text optional de motiv —
-**decizia 61**: da, se adauga (`AllowanceChargeReason`, `ReasonCode` ramane `95`), cu stocare noua
-pe `VANZARI` si un control nou in formular. Asezarea lui s-a inchis in runda 17 — **decizia 66**: sta in banda de totaluri, langa discount. Retroactivi-
-tatea la relistare/retrimitere — **decizia 62**: restrictia de modificare e strict `EsteInEFactura`,
-fara legatura cu nicio data; ramane insa deschis, separat, cazul relistarii (nu editarii) unei
-facturi vechi deja trimise, vezi decizia 62.
-
-### M. Valuta si data cursului (decizia 15)
-
-**Cele doua concepte exista in cod, distinct** — decizia 15 nu introduce o distinctie noua, o face
-vizibila:
-
-- **(a) factura in valuta**: `poDate.in_valuta` / `Curs` / `multiplicator` / `id_valuta`, un singur
- curs pentru tot documentul;
-- **(b) articol cu pret in valuta pe document in lei**: `poArticol.tip_valuta = 1`, proprietate a
- politicii de pret, independenta de `in_valuta`. Conversia se face **in VFP**, cu cursul zilei:
- `poArticol.pretftva = Round(poArticol.pretftva_val * poArticol.Curs / poArticol.multiplicator, gnPPretV)`
- (`ofacturare.vc2:1989`, `:2017`, `:2953`). Cursurile zilei se incarca exact pe ramura „document in
- lei”: `If poDate.in_valuta = 1 ... Else citeste_cursuri_zi(poDate.zi_curs)` (`ofacturare.prg:407-418`).
-
-**In baza, exact cum ai descris:** `VANZARI_DETALII` **nu are coloana `CURS`**; pastreaza `PRET` (in
-lei, valoarea de facturare) plus `PRETD` si `ID_VALUTAD` ca urma a pretului original in valuta.
-Cursurile ajung in `VANZARI_CURSURI`, scrise neconditionat la emitere pentru **orice** valuta straina
-aparuta pe linii — deci si pe o factura in lei
-(`PACK_FACTURARE.sql:14491-14501`, `scrie_cursuri`).
-
-**`in_valuta` nu e o alegere, e o proprietate a tipului de document.** Se seteaza o singura data, in
-`Init`: `If Inlist(tnIdSet,223,225,226,227,271) OR INLIST(m.tnTip, 5,6,7,9,10,52) -> .in_valuta = 1`
-(`ofacturare_comun.prg:248-250`), si nu se mai schimba. Selectorul de valuta e chiar eliminat din
-formular cand `in_valuta = 0` (`ofacturare.vc2:9725-9728`), deci operatorul nici nu-l poate alege.
-
-**Problema semnalata, confirmata:** `Clb_zi_curs` e eliminat **doar** pe retur (tip 8, 9), la
-`ofacturare.vc2:9717-9722` — si niciodata in functie de valuta, desi blocul imediat urmator,
-`:9725-9728`, face exact asta pentru selectorul de valuta. Deci **azi campul apare si pe facturi in
-lei**, unde de multe ori nu are ce cauta. Validarea e la randul ei asimetrica: `frm_date_factura`
-cere ziua cursului doar cand `in_valuta = 1` (`:9484`), dar `frm_date_aviz_lucrare` o cere
-**neconditionat** (`:8076`).
-
-**Regula propusa:** campul apare cand tipul nu e retur **si** (documentul e in valuta **sau** exista
-pe document macar un articol cu pret in valuta).
-
-**Unificarea face regula posibila.** Azi cazul (b) nu se poate sti la deschiderea antetului — se
-afla abia dupa incarcarea articolelor, cand antetul e deja inchis si eliberat (`Release
-ofrmceredate`, `ofacturare.prg:248`). In formularul unificat antetul si gridul sunt in aceeasi
-fereastra, deci campul poate aparea in clipa in care intra pe grid primul articol cu pret in valuta.
-**Din acelasi motiv dispare si mecanismul lui #16**: bug-ul de focus si de renumerotare apare la
-revenirea din `frm_curs` intr-un antet care tocmai s-a inchis — in formularul unificat nu mai exista
-un antet inchis la care sa te intorci. `frm_curs` e in `COMUN\clase\onom_curs.vc2:537`, deschis din
-`vizualizeaza_curs` (`oproceduri_curs.prg:8-42`) ca recuperare la eroarea Oracle 20005
-(`ofacturare.prg:313-317`).
-
-**Capcana:** `poDate.zi_curs` se trimite **neconditionat** ca prim parametru catre `cursor_preturi` /
-`cursor_articole_k` / `cursor_gestiune` / `cursor_lucrare` (`ofacturare.prg:272-303`), inclusiv pe
-tip 1. Ascunderea campului nu inseamna golirea valorii — valoarea implicita (data documentului)
-trebuie sa ramana. Iar pe avizul de lucrare, ascunderea fara repararea validarii de la `:8076` ar
-bloca finalizarea antetului cerand un camp care nu mai e pe ecran.
-
-### N. Returul din facturi anterioare (decizia 17)
-
-Rapoarte: `docs\cercetare\factura_retur_document.md` (mecanismul principal) si
-`retur_si_lista_preturi.md`, A (al doilea mecanism).
-
-**Sunt doua fluxuri de cod independente**, care ating aceeasi clasa de formular prin metode si
-proceduri Oracle diferite. Nu au niciun punct comun in afara conventiei de semn a cantitatii.
-
-#### N.1 Factura de retur ca document (tipurile 8, 9 — si avizul de retur, 24)
-
-**Asta e mecanismul pe care il descrie Marius, si functioneaza deja cap-coada.**
-
-- **Intrare:** tile-ul de pe ecranul de facturare (`ofundal_facturare.vc2:882-884`) -> `politica.mpr`
- -> `factureaza(8)` / `factureaza(9)` (`Meniuri\politica.mn2:14-15, 45-46`).
-- **Alegerea facturilor, la nivel de document:** `frm_date_factura.do_cauta_facturi`
- (`ofacturare.vc2:9173-9212`) cheama `caut_facturi_multiple_client`
- (`oproceduri_facturare.prg:2091-2121`) — browse cu **selectie multipla**, titlu „Alegeti facturile
- (mouse-click pe numar sau apasati SPACE)”. Filtrare pe **client** (obligatoriu ales inainte) si
- **valuta**; sursele exclud tipurile de retur, deci nu se face retur dintr-un retur. Id-urile alese
- se aduna intr-un CSV in `poDate.listaid`, numerele in `poDate.descriere`, iar antetul primeste
- automat textul „RETUR FACTURA …”. Fara alegere nu se poate continua (`:9523-9526`).
-- **Popularea liniilor:** `pack_facturare.cursor_retur` -> `cursor_retur_document`
- (`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:3943-3956`, `:3958-4071`) selecteaza direct din
- `VANZARI_DETALII` liniile facturilor alese si le pune in acelasi `crsarticole` pe care celelalte
- tipuri il umplu cu lista de preturi (`ofacturare.prg:306-311`). **Confirmat exact ce spunea Marius:**
- `ID_GESTIUNE` vine din linia originala (`:4034`, `:4055`), `PRET_ACHIZITIE` la fel, **neschimbat**
- (`:4035`, `:4056`), iar pretul de vanzare se recalculeaza pe curs doar daca moneda nu e nationala
- (`:4016-4030`). `GESTIONABIL` e `NVL2(A1.ID_GESTIUNE,1,0)` — gestionabil doar daca originalul avea
- gestiune.
-- **Ce se poate face manual:** **stergerea liniilor aduse merge** si cantitatea redevine disponibila
- in cursorul sursa (`do_sterge`, `ofacturare.vc2:14608-14693`, ramura de retur la `:14658-14659`);
- **returul partial merge** (`do_verifica_articol`, `:14743-14754`, fata de maximul calculat pe
- server).
-- **Avizul de retur (24)** foloseste acelasi `cursor_retur` si aceleasi ramuri; difera doar antetul —
- `nIdTipDoc = 6` si `frm_date_aviz` in loc de `frm_date_factura` (`ofacturare.prg:194-195`, `:225`).
-
-**Singurul gol real, si e acelasi ca la comanda:** pe un document de retur **nu se poate adauga o
-linie din afara facturilor sursa**, pentru ca `crsarticole` **este** rezultatul lui `cursor_retur`
-(`do_adauga_articol` ia articolul mereu din el, `ofacturare.vc2:12843-12851`). Nu e o interdictie
-explicita, e continutul cursorului — exact cauza de la comanda (J). Se rezolva la fel, prin
-`APPEND FROM`, si abia asta face reala decizia 16 pe documentele de retur.
-
-#### N.2 Retur de articole intr-o factura de vanzare normala (`But_retur`)
-
-Butonul (`cmd_butoane.vc2:324-338`, `caction = do_retur`) e vizibil **doar** pe tipurile 1, 5, 7, 10
-(`ofacturare.vc2:15122-15127`) — pe un document de retur nu exista deloc. Aici factura sursa se alege
-**per articol**, la fiecare linie: `caut_facturi_multiple_client_articol`
-(`oproceduri_facturare.prg:2124-2159`), filtrat suplimentar pe articolul curent. Perechile
-`ID_ARTICOL:ID_VANZARE` se acumuleaza in `thisform.cListaIdArticoleRetur` (`:12888`) si pleaca ca
-`poDate.listaid` (`:13977-13979`). Gestiunea se alege prin
-`pack_facturare.cursor_gestiuni_articol_retur`, nu vine din factura sursa — **diferenta de fond fata
-de N.1**.
-
-**Legatura linie-de-retur -> linie originala: neverificat** pe schema. In VFP nu exista coloana de
-linie sursa; la nivel de antet exista `poDate.nid_vanzare_retur` (`ofacturare.vc2:14448`, `:14509`).
-Conteaza doar pentru **afisare** — daca formularul poate arata din ce factura vine fiecare linie.
-
-#### N.3 Ce se schimba in formularul unificat
-
-- **N.1 se muta ca atare.** Alegerea facturilor devine o optiune in meniul butonului de adaugare
- („Alege facturile de returnat…”), cu acelasi dialog, aceleasi filtre si aceeasi populare din
- `cursor_retur`. **Nu se reproiecteaza nimic din ce merge**, si in special nu se atinge preluarea
- gestiunii si a pretului de achizitie din facturile originale.
-- **N.2 capata si alegerea la nivel de document**, dupa modelul lui N.1, pastrand calea per-articol
- pentru cazul cu un singur articol.
-- **Lista de preturi devine disponibila si pe documentele de retur** (decizia 16), prin acelasi
- `APPEND FROM` ca la comanda. Consecinta de proiectat: pe acelasi document vor coexista linii
- aduse din facturi sursa (cu gestiune si pret de achizitie mostenite) si linii libere, care nu au
- factura sursa.
- **Decizia 22 (Marius, 09.08.2026): linia de retur fara factura originala e permisa, ca pe orice alt
- document.** Returul nu face exceptie de la regula deciziei 16 — sursa umple documentul, nu il
- inchide, si nici nu apare doar „pentru corectii”. Consecintele de proiectat, acum ferme:
- - **gestiunea si pretul de achizitie nu se pot mosteni** pe o linie libera, pentru ca nu exista linie
- originala. Se aleg, ca la N.2 (`cursor_gestiuni_articol_retur`), nu se preiau ca la N.1;
- - **maximul returnabil calculat pe server nu se aplica** unei linii fara factura sursa — nu exista
- cantitate originala fata de care sa se limiteze;
- - afisarea „din ce factura vine linia” trebuie sa suporte si valoarea goala (vezi mai sus, legatura
- linie-de-retur -> linie originala, inca neverificata pe schema).
-
-*De pastrat cum e:* excluderea returului dintr-un retur, filtrarea pe client si valuta, maximul
-returnabil calculat pe server, si mostenirea gestiunii si a pretului de achizitie. Nu se ating.
-
-### O. Facturile din ROAAUTO (decizia 18)
-
-Raport: `docs\cercetare\roaauto_facturi.md`.
-
-> **Precizare la descrierea liniilor de mai jos.** „Liniile unei facturi ROAAUTO nu sunt articole” e
-> adevarat doar pentru liniile **generate din deviz**. Langa ele pot sta articole reale, adaugate
-> prin mecanismul **„Alte servicii”** — vezi O-bis, verificat pe cod
-> (`docs\cercetare\roaauto_articole_lista_preturi.md`). Restul sectiunii ramane valabil: tipul `-12`,
-> drumul comun prin `PACK_FACTURARE`, faptul ca editorul lui #6 le vede, si blocarea modificarii
-> dupa facturare — ultima **reconfirmata**.
-
-**Ce se confirma.** ROAAUTO nu are cale proprie spre baza: `factureaza_deviz`
-(`ROAAUTO\Programe\oproceduri_devize.prg:846`) cheama acelasi `PACK_FACTURARE` partajat —
-`initializeaza_date_factura` (`:1211`), `adauga_articol_factura_deviz` (`:1240`), `oscrie_in_fisiere`
-(`:1269`), `scrie_in_vanzari` (`:1302`) — deci liniile trec prin acelasi `VANZARI_DETALII_TEMP` si
-ajung in acelasi `VANZARI_DETALII` ca orice factura ROA. Tipul documentului e **`-12`**
-(`:922`). Editorul lui #6 le vede deja, fara cod de recunoastere a sursei, verificat pe date reale
-(`id_vanzare = 1047`). **Deci partea de „le vede” e gratuita.**
-
-**Ce nu se confirma — si asta schimba dimensiunea deciziei.** „Se pot modifica ulterior” **nu e
-adevarat azi, in niciun produs**:
-
-- in ROAAUTO, formularul de devize isi dezactiveaza butonul de modificare de indata ce comanda are
- numar de factura (`oviz_devize.vc2:4536`); singura actiune post-facturare gasita e re-listarea
- (`oproceduri_devize.prg:1516`), care nu scrie nimic. Niciun apel din ROAAUTO catre
- `modifica_date_factura`;
-- in ROAFACTURARE, gridul de articole din editorul nou (`frm_modific2024`, `COMUN\clase\omodificari.vc2`)
- e **read-only prin design**, la nivel de grid si pe fiecare `Text1`.
-
-Deci decizia 18 nu extinde o cale existenta, **creeaza o capacitate care nu exista nicaieri**.
-
-**Cum arata liniile.** `factureaza_deviz` agrega sumele devizului si insereaza cate o linie sintetica
-per categorie, cu `id_articol` **negativ**: `-100000` MANOPERA (`:965-967`), `-100003` MATERIALE
-(`:947-949`), `-100001` discount manopera, `-100005` / `-100006` avans si stornare avans,
-`-100007` / `-100008` inspectie tehnica si spalare (`:936-1027`). Optional, cu
-`gnAUTOIdArticolReparatii` setat, toate se cumuleaza intr-o singura linie cu un articol real
-(`:989-1004`). Langa ele pot sta **articole reale**, prin „Alte servicii” — vezi O-bis.
-
-### O-bis. „Alte servicii” — cum se adauga azi articole reale in ROAAUTO
-
-Raport: `docs\cercetare\roaauto_articole_lista_preturi.md`. **Asta e mecanismul de refolosit.**
-
-- **Unde:** formularul `frm_incasare_finala` (`ROAAUTO\Clase\oviz_devize.vc2:5435-7143`), aratat **la
- emiterea facturii finale** (`do_factureaza_final`, `:2569`) — nu pe devizul propriu-zis.
-- **Sursa articolelor:** `cauta_nom_articole` pe `vnom_articole_toate`
- (`COMUN\programe\ocautare.prg:1781-1823`), filtrat `in_stoc = 0 and in_crm = 1` si cu id-urile
- sintetice excluse (`oviz_devize.vc2:6539-6580`). **Nomenclatorul brut, si numai articole fara
- stoc** — nu lista de preturi, nu politici.
-- **Pretul se tasteaza manual.** `do_adauga` nu completeaza pretul si cantitatea; operatorul le pune
- in grid, iar `do_modifica_alteserv` recalculeaza valoarea (`:6692-6698`, `:7064-7070`). Nu exista
- preluare automata de pret pe calea asta.
-- **Liniile raman separate.** Cumularea in „REPARATII AUTO” include doar id-urile sintetice
- (`oproceduri_devize.prg:999-1012`); randurile din `crsalteserv` se insereaza dupa, cu `id_articol`
- real, si ajung ca atare in `VANZARI_DETALII_TEMP` (`:1036-1041`, `:1240-1257`).
-- **Gestiune: tot zero.** `id_gestiune` nu e completat de niciun `INSERT` si pleaca `0` spre Oracle
- (`:1201-1206`, `:1255`) — consistent cu filtrul `in_stoc = 0`. Deci **nici articolele reale din
- ROAAUTO nu descarca gestiune**. Diferenta fata de liniile sintetice e doar `id_articol`.
-- **Stergere si modificare:** exista, dar **doar cat timp formularul e deschis, inainte de emitere**
- (`do_sterge`, `:6730-6741`).
-- **Contul pleaca gol.** `crsvanztemp` are coloana `Cont c(4)`, dar `INSERT`-ul care il umple nu o
- include (`oproceduri_devize.prg:1190-1206`); apelul trimite literal `''` (`:1256`), care ajunge
- `NULL` in `VANZARI_DETALII_TEMP.CONT`, fara `NVL` si fara fallback. Deci **liniile de articole reale
- din ROAAUTO se scriu azi fara cont** de gestiune, tacut. Vezi J-bis.
-- **Si fara politica de pret — dar pe alta cale decat credeam.** `id_pol` lipseste peste tot pe firul
- asta (nu e nici in `crsalteserv`, nici in `crsvanztemp`, nici in semnatura lui
- `adauga_articol_factura_deviz`). **Motivul pentru care asta nu produce `FACT-024`** e ca fluxul
- ROAAUTO **nu trece prin `contabilizeaza_articol`**: merge pe `scrie_in_vanzari`, care nu genereaza
- nicio nota de venit. Vezi **J-ter**.
-
-> **Corectie importanta la temeiul deciziei 18.** Ideea ca „«Alte servicii» face deja jumatate din ce
-> cerem, deci se generalizeaza” **nu se sustine**. Mecanismul acela functioneaza tocmai pentru ca
-> ocoleste contabilizarea de venit; generalizat pe fluxul ROAFACTURARE, unde `contabilizeaza_articol`
-> **este** apelata (`scrie_factura2`, `ff_...:6150`), s-ar lovi de `FACT-024`. Ce ramane valabil din
-> O-bis e descrierea UI (articole reale langa linii sintetice, pret tastat, fara gestiune) — nu si
-> concluzia ca partea grea e deja rezolvata.
-
-**Ce inseamna asta pentru decizia 18.** Doua lucruri, in directii opuse:
-
-- **usureaza** partea de model: un articol real langa linii sintetice **nu e o noutate**, e deja
- cazul normal al facturilor auto. Intrebarea „cum coexista” are deja un raspuns in produs;
-- **nu rezolva** cerinta: mecanismul traieste in formularul de emitere al ROAAUTO si moare odata cu
- el. Ce cere Marius e aceeasi capacitate **la modificare**, care nu exista nici acolo, nici aici.
-
-**Intrebarile ramase, in ordinea in care blocheaza:**
-
-1. ~~**Ce se intampla cu totalul devizului**~~ — **RASPUNS (runda 7)**, raport
- `docs\cercetare\pack_auto_actualizeaza_deviz.md`. Premisa intrebarii era gresita: **nu exista niciun
- `SUM` peste `VANZARI_DETALII`, pentru ca `PACK_AUTO` nu citeste deloc `VANZARI` /
- `VANZARI_DETALII`** — zero potriviri pe `VANZARI` in tot pachetul (1804 linii).
- `actualizeaza_deviz` (`ff_2026_03_31_02_AUTO_PACK_AUTO.sql:692-733`) face trei lucruri, toate pe
- structura proprie ROAAUTO: scrie cota TVA pe `DEV_ORDL`, stampileaza `ID_FACT` pe `RUL`, si — doar
- pe anumite `id_set` — pe `NOM_LUCRARI`. E o legatura **deviz -> document**, nu un recalcul
- **document -> total deviz**. Nu e nici macar specifica facturarii: aceleasi trei apeluri o
- folosesc si la inchiderea de productie si de regie, care scriu note contabile, nu facturi.
- **Deci o linie noua pe `tip = -12` nu poate dezechilibra nimic pe partea Oracle**, si nu e nevoie
- de niciun apel suplimentar catre ROAAUTO. Precedentul „Alte servicii” confirma pe date live:
- liniile reale coexista de mult cu cele sintetice, fara ca `actualizeaza_deviz` sa faca distinctie.
- **Ce ramane, si e de alt fel:** o **desincronizare de afisare**. Totalul devizului aratat in
- ROAAUTO se calculeaza din `RUL` si din cursoarele de facturare (`oviz_devize.vc2:7816-7823`),
- **niciodata** din `VANZARI_DETALII` — deci nu va arata linia adaugata, nici azi, nici dupa #13.
- In schimb **relistarea o va arata**: `relisteaza_factura_deviz` citeste `fact_vfacturi_detalii`
- (`oproceduri_devize.prg:1564`), un view neconditionat peste `VANZARI_DETALII`
- (`ff_2024_06_04_01_COMUN_FACTURARE.sql:8-94`). Factura retiparita si ecranul de deviz vor spune
- lucruri diferite — **DECIS (decizia 28): e acceptabil.** Cerinta lui Marius e ca **MANOPERA si
- MATERIALE sa fie conform devizului**; restul articolelor pot exista pe factura fara sa apara in
- ecranul de deviz. Nu se cere cod nou in ROAAUTO si nu se mai pune intrebarea.
-2. **Gestiunea, pentru articole cu stoc. DECIS (decizia 20):** se admit si articolele gestionabile.
- ROAAUTO ocoleste subiectul filtrand `in_stoc = 0`; filtrul acela **nu se preia**. Deci pe
- documentele auto vor coexista linii care descarca stoc cu linii care nu descarca — caz nou, de
- proiectat, nu de evitat.
-3. **Cine ramane proprietarul documentului** dupa ce ROAFACTURARE ii adauga o linie — mai poate
- ROAAUTO sa-l relisteze corect (`relisteaza_factura_deviz` citeste din `fact_vfacturi`)?
-
-**Reconfirmat:** dupa emitere nu exista cale de intoarcere in ROAAUTO. `verifica_stornare`
-(`oviz_devize.vc2:4513-4514`) e o metoda **goala**; `do_storneaza_avans` priveste doar avansul.
-Singurul instrument gasit asupra unei facturi emise e stergerea totala (soft-delete) prin ecranul
-generic din COMUN — nu o editare.
-
-**Secventierea — reevaluata dupa raport (runda 7).** Marius a cerut ca `pack_auto` sa fie cercetat
-inainte de orice estimare (decizia 23), si a avut dreptate: raspunsul **rastoarna recomandarea
-initiala**. Motivul pentru care decizia 18 urma sa se livreze ultima era riscul tehnic de a scrie pe
-un produs pe care #13 nu-l controleaza. **Acel risc nu exista** — `PACK_AUTO` nu citeste `VANZARI` /
-`VANZARI_DETALII` deloc, deci nu are ce sa se dezechilibreze (vezi intrebarea 1 de mai sus).
-
-Ce ramane nu mai e risc tehnic, ci **o singura intrebare de produs**:
-1. ~~e acceptabil ca ecranul de deviz sa nu arate linia adaugata din #13~~ — **RASPUNS, decizia 28:
- da, e acceptabil.** Conditia e alta: MANOPERA si MATERIALE conform devizului.
-2. cine ramane proprietarul documentului (intrebarea 3 de mai jos) — nu s-a schimbat.
-
-**Decizia 18 nu mai trebuie sa fie ultima din motive tehnice.** Ordinea de lucru din S4g ramane insa
-valabila din alt motiv, mai bun: se face intai pe documentele ROAFACTURARE, unde scrierea e a
-noastra, pentru ca acolo se aseaza mecanismul; `tip = -12` vine dupa, ca **aplicare**, nu ca risc.
-
-**Perimetru:** gridul read-only din `frm_modific2024` si `ofacturare_editare.prg` sunt ale lui **#6**.
-Deschiderea lui la scriere nu se face din #13 fara intelegere explicita — un singur scriitor pe fisier.
-
-### L. Observatii colaterale, gasite in timpul verificarii
-
-Nu fac parte din #13 si nu se repara aici — se semnaleaza ca sa nu se piarda.
-
-0-ter. **(runda 9) O nota de vanzari cu set multi-rand inregistreaza venitul si descarca gestiunea de N
- ori.** In `pack_facturare.contabilizeaza_articol`, `cursor_articol` face `LEFT JOIN NOTE_CONTABILE D ON
- C.ID_SET = D.ID_SET` **fara `ROWNUM`, fara agregare, fara filtru**
- (`ff_2026_08_09_01_...:7218-7271`), iar bucla care il consuma (`:7393-7542`) executa `scrie_nota`
- **si** `descarca_gestiune` **o data pentru fiecare rand al setului, cu aceeasi cantitate si acelasi
- pret intreg** — nu impartite. Nu exista nicio logica de distributie: `ORDINE` nu apare in tot pachetul.
- Azi nu se manifesta pentru ca toate cele 7 note de vanzari active au exact un rand pe set — dar **30
- din cele 40 de seturi din baza au mai multe, cu maxim 30 de randuri**. Deci e o bomba armata de
- configurare: cine ataseaza unei politici de pret o nota cu set multi-rand obtine **dublare de venit si
- dublare de descarcare de gestiune**, silentios. **E in `PACK_FACTURARE`, adica in COMUN** — se
- semnaleaza, nu se repara din #13. Conteaza direct pentru reteta din J-quater: vezi acolo.
- Sursa: `docs\cercetare\s10_pret_rederivat.md`, „Completare", p. 1 + `verif_baza_vie_cont_venit.md` p. 6.
-0-quater. **(runda 9) Politica de pret fara `ID_NOTA` nu are nicio plasa de siguranta.** Spre deosebire de
- articolul lipsa din politica (`FACT-024`), aici nu exista cod de eroare: lantul de `LEFT JOIN` din
- `cursor_articol` supravietuieste inelului lipsa, cursorul intoarce **un rand cu totul `NULL`**, iar
- `scrie_nota` insereaza in `ACT_TEMP` un rand cu conturile de debit si credit **nule**. Daca `ACT_TEMP`
- are `NOT NULL` pe ele, iese un `ORA-01400` generic in loc de un mesaj `FACT-0xx` — **neverificat**,
- DDL-ul lui `ACT_TEMP` nu e in export. Starea exista in baza vie **azi**: politicile active `32 HOTEL
- TAXE` si `33 HOTEL CAZARE` n-au `ID_NOTA`. Independent de #13.
-0-bis. **(runda 7) `do_modifica` pare sa scrie `id_valuta` in loc de `id_sectie`.** In
- `frm_modific2024.do_modifica` (`COMUN\clase\omodificari.vc2:13941`), ramura
- `CASE m.lcControl = 'sectie'` face `replace sectie with loCauta.sectie, id_valuta with
- loCauta.id_sectie`. Daca e ce pare, textul afisat al sectiei se schimba dar coloana `id_sectie`
- nu — si, in plus, se strica `id_valuta`. **Necitit pe date, doar pe cod.** Fisierul e in
- **perimetrul lui #6** (`omodificari.vcx` a intrat in proiect prin `97d1613`) — se semnaleaza acolo,
- nu se repara de aici. Conteaza pentru #13 pentru ca sustine partial verdictul „`ID_SECTIE` e
- editabil": teoretic da, practic poate nu.
-0. **(runda 7) Handler-ul lui `FACT-024` se auto-saboteaza cand `id_pol` e `NULL`.** In
- `pack_facturare.contabilizeaza_articol` (`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:7286-7311`),
- ramura `WHEN NO_DATA_FOUND` construieste mesajul cu inca doua `SELECT ... INTO`, dintre care al
- doilea e `FROM CRM_POLITICI_PRETURI WHERE id_pol = detalii_articol.id_pol`. Cu `id_pol` `NULL`,
- **si acel `SELECT` da `NO_DATA_FOUND`**, iar in handler nu exista al doilea nivel de tratare — deci
- utilizatorul primeste un `ORA-01403` generic in loc de mesajul `FACT-024` formatat. Articolul
- apucase sa fie rezolvat, deci informatia nu se pierde de tot, dar diagnosticul e mult mai prost.
- **E in `PACK_FACTURARE`, adica in COMUN** — se semnaleaza, nu se repara din #13. Devine relevant
- direct daca se alege varianta 3 din J-bis.
-1. **`do_copiaza`, ramura de avize: variabila gresita.** La `ofacturare_comun.vc2:3702-3703`, ramura
- `CASE INLIST(loFactura.tip, T21, T24, T26, T30, ...)` scrie `lnTip = T22` in loc de
- `loFactura.tip = T22`, deci degradarea de tip **nu se aplica** pe acea ramura. **Fisierul e in
- perimetrul lui #6** — nu se atinge de aici; efectul nu a fost verificat pe date.
-2. **„Proforma -> factura” merge prin omisiune.** Copierea nu propaga `nIdTipDoc` pentru ca linia e
- comentata (`ofacturare_comun.prg:370`), deci copia unei proforme porneste implicit pe FACTURA.
- Functioneaza, dar ca efect secundar, nu ca ramura dedicata. Daca #13 atinge copierea, merita
- transformat in intentie explicita.
-3. **Asimetria de resetare a globalelor** — vezi „Canalul de precompletare”, mai sus.
-4. **Modificarea in bloc pare sa goleasca campuri pe care nu le-ai atins.** Pe selectie multipla
- (`lnNrInreg > 1`), `do_modifica` face `Scatter Name poRec Memo Blank` si reseteaza explicit ruta,
- delegatul, agentul, masina, `dataora_exp`, `id_facturare`, `listare_detaliata`, `tip_saft`,
- `text_aditional` si `efactura` (`ofacturare_comun.vc2:4565-4580`). Cum acesti zece parametri se
- scriu **neconditionat** in `VANZARI` (I-bis), un `SCAN` peste facturile alese pare sa scrie valorile
- goale pe **fiecare** dintre ele — deci schimbarea rutei pe trei facturi ar sterge delegatul si
- textul aditional de pe toate trei. **De confirmat pe date inainte de a fi numit bug**: e posibil ca
- fluxul sa presupuna ca operatorul completeaza tot ce vrea propagat. **Fisierul e in perimetrul lui
- #6** — se semnaleaza, nu se repara de aici. Conteaza si pentru #13: formularul unificat lucreaza
- pe un singur document si trebuie sa trimita antetul intreg (I-bis, consecinta 1), deci nu
- mosteneste problema.
-
-**L.4 (runda 11). Numarul de POS nu se dezaloca la Renunt.** In `frm_alte_date`, la anulare se
-dezaloca numarul de chitanta (16) si cel de bon fiscal (3), dar **nu si cel de POS (26)** —
-`docs\cercetare\s3b_alte_date_analitice.md`, sectiunea 9. Bug preexistent, in productie, **nu introdus
-de #13**. Conteaza pentru S3b pentru ca „`actualizeaza_tipincasare` se muta ca atare" **l-ar propaga
-in formularul unificat**. Se repara in trecere sau se lasa ca azi si se preia separat — punct de decis,
-vezi lista de la finalul rundei 11.
-
----
-
-## Stories
-
-Ordinea e strict pe risc: unificarea intai (livrabil de sine statator, util si fara regenerare),
-regenerarea peste ea.
-
-## Metoda de executie (Marius, runda 14) — obligatorie, nu recomandare
-
-**Planul asta e un document de proiectare, nu un plan de executie. La implementare se SPARGE PE
-STORIES, si fiecare story se executa ca livrare de sine statatoare.** Nu se porneste implementarea pe
-tot #13 deodata, nu se acumuleaza modificari nelivrate peste mai multe povesti, si nu se trece la
-povestea urmatoare cu cea precedenta netestata si nerevizuita.
-
-### Ce inseamna „spart pe stories"
-
-- **O story = o unitate de livrare.** Are perimetru propriu de fisiere, criteriu „gata cand" propriu
- (fiecare story de mai jos il are deja scris) si se incheie cu diff + review + commit propriu.
-- **Inainte de prima linie de cod dintr-o story**, se scrie o **nota de executie** in `docs\` care
- transpune proiectarea in pasi concreti: fisierele atinse, metodele atinse, ordinea editarilor, si ce
- se testeaza dupa fiecare. Proiectarea spune *ce* si *de ce*; nota de executie spune *unde* si *in ce
- ordine*. Rapoartele din `docs\cercetare\` sunt materia prima — nu se reface cercetarea.
-- **Povestile cu dependente declarate** (`*Depinde de:*`, la fiecare story) **nu se pornesc in paralel
- cu cele de care depind.** Unde nu e dependenta, se pot rula in paralel de agenti diferiti — dar
- **un singur scriitor pe fisier**, niciodata doi agenti pe aceeasi metoda.
-- **O story care se dovedeste prea mare la executie se sparge mai departe**, cu acordul lui Marius, si
- se noteaza in plan. Mai bine cinci livrari mici decat una care nu se poate revizui.
-
-### Teste la fiecare pas — nu doar la S6 si S12
-
-`S6` si `S12` raman testele **pe flux real**, la capatul fiecarei etape. **Ele nu inlocuiesc testarea
-per story.** Fiecare story se incheie cu teste proprii, rulate si trecute, **inainte** de review:
-
-- **Harness headless** (`COMUN\docs\depanare_testare_vfp.md`) pentru logica — cazurile minime ale
- povestii, plus **cel putin o proba de neregresie** pe calea veche, care trebuie sa ramana neatinsa.
-- **Harness UI vizibil** (`COMUN\docs\testare-ui-vfp.md`) unde povestea atinge formulare sau griduri —
- coloanele de grid **nu se materializeaza headless**, deci acolo verificarea headless nu e concludenta.
-- **Rezultatul asteptat se declara INAINTE de rulare**, inclusiv pentru cazurile care trebuie sa dea
- eroare. Un test scris dupa ce s-a vazut rezultatul nu dovedeste nimic.
-- **Un esec documentat e livrabil valid** — se raporteaza, nu se ascunde si nu se reia la nesfarsit.
-- Testele fiecarei povesti **se pastreaza**, si intra in suita rulata de S6 / S12. Nu se scriu de
- unica folosinta.
-
-### Code review dupa implementare, inainte de commit — pentru fiecare story
-
-**Nicio story nu se comite fara review, si review-ul vine dupa implementare si dupa teste, nu in loc
-de ele.** Ordinea, fixa:
-
-1. **Implementare** (delegata unui subagent, conform modului de lucru din `CLAUDE.md`).
-2. **Teste** — rulate, trecute, cu rezultatele raportate.
-3. **Diff ca fisier in `docs\`** (`diff_s_.patch`), inclusiv partea din `COMUN`.
-4. **Code review pe diff**, de catre **un agent care nu a scris codul** — altfel isi revizuieste
- propriile presupuneri. Review-ul verifica cel putin: regresia pe calea veche, conventiile per zona
- atinsa (`COMUN\docs\reguli_lucru.md`, punctul 7 — encoding `cp1250` la `.vc2`/`.sc2`, `GO` pe
- `Recno()`, `goExecutor` + `ALTER TABLE`, UX formulare/griduri), comentariile (istoric **numai** in
- antetul fisierului, max o linie in cod), si ca write-back-ul text→binar e facut pentru fiecare
- fisier atins.
-5. **Aprobarea lui Marius.**
-6. **Commit** — in **ambele** repo-uri unde e cazul (ROAFACTURARE si COMUN), cu changelog.
-
-**Afirmatiile review-ului se verifica, nu se cred.** Un review poate citi structura corect si presupune
-semantica gresit; cand semnaleaza un defect, se deschide codul citat inainte sa fie acceptat — la fel
-cum se procedeaza cu rapoartele de cercetare.
-
-**Ce NU face review-ul:** nu reargumenteaza deciziile luate (lista lor e in acest plan), nu extinde
-perimetrul povestii, si nu propune refactorizari colaterale. Ce gaseste in afara perimetrului se
-**raporteaza separat**, nu se repara in trecere — exact cum s-a procedat cu defectul `lnTip` din
-`do_copiaza`.
-
-### Etapa I — formularul unificat
-
-#### S1 — Inventarul de campuri si alegerea bazei
-Deciziile de perimetru sunt luate (vezi listele de la inceput). Ramane: **se porneste de la prototipul
-`frm_facturare_articole2` sau de la `frm_facturare_articole` extins?**
-Recomandare: **de la prototip**, si acum cu trei argumente in plus fata de runda 2 — are deja
-controalele de antet, are butoanele **deasupra** gridului (decizia 13), si are coloanele de discount
-editabile plus procentul pe linie (decizia 14). Partea grea de layout e deja acolo; logica lipsa se
-porteaza in el.
-Livrabil: tabel camp-cu-camp `frm_date_factura` / `frm_date_aviz` / `frm_modifica_factura` /
-`frm_alte_date` -> formular unificat, cu ce se pastreaza, **in ce grup din cele patru intra** (I),
-ce se pliaza, ce dispare, si **cu ruta de scriere a fiecarui camp** (pe loc sau prin regenerare —
-vezi G-bis). Baza de pornire: `docs\cercetare\inventar_controale_formulare.md`, care are deja
-etichetele reale si conditiile de vizibilitate.
-**Livrat (runda 7): `docs\S1_inventar_campuri_formular_unificat.md`** — 30 de campuri de antet, cu
-grupul din I, conditiile de vizibilitate si ruta de scriere pentru fiecare, plus randul dedicat lui
-`V_EFACTURA` (singurul camp fara control azi, nicaieri) si cele patru bife marcate ca disparute.
-Tabelul a scos la iveala **golul de rute de scriere** din G-bis — vezi acolo. Are si o sectiune
-„Neclarificate" cu opt puncte, dintre care doua ambiguitati de nume (`chkDetaliat`, `cboTipFactura`
-apar in doua formulare si nu s-a confirmat pe cod ca scriu acelasi camp).
-**Coloana „ruta de scriere" e completa acum** — `rute_scriere_antet.md` a inchis cele trei grupuri
-lasate neclarificate, iar deciziile 25 si 26 le-au dat ruta. Tabelul se citeste **impreuna cu tabelul
-de rutare din G-bis**, care e sursa de adevar pentru ruta fiecarui camp; sectiunea „Neclarificate" din
-S1 ramane valabila doar pentru punctele **4, 5, 7 si 8** (ambiguitatile `chkDetaliat` / `cboTipFactura`,
-liniile exacte de definire a controalelor, si dependenta de drepturi).
-*Gata cand:* tabelul e aprobat. **APROBAT de Marius, 09.08.2026 — S1 e incheiata.** Tabelul devine
-referinta pentru S3 si S3b; modificarile ulterioare se fac in el, nu se rescrie de la zero.
-
-**ASEZAREA ZONEI DE JOS — INCHISA prin decizia 57 (Marius, runda 15): VARIANTA D.**
-Cerinta initiala (runda 14), formulata de el: *„totalurile de jos sa fie mai compacte, si sa includa
-si discount-ul; formularul trebuie sa fie compact si aerisit; incasarea si alte date jos de tot,
-eventual 2 butoane pe acelasi rand — vezi modelul Saga; in centrul atentiei sa fie datele facturii"*.
-Referinta vizuala: `{06D747B8-0824-488C-8832-DEB9AE661974}.png`.
-Rundele 14-15 au dat patru variante (A / B / C, apoi D). **Aleasa: D.** Vezi „Decizia 57" la
-deciziile rundei 15, care are enuntul complet, cele patru consecinte de implementare si punctul lasat
-deschis. Ce e de retinut aici, pentru executia lui S1:
-
-- **Antetul se strange la doua randuri**, fara titluri de grup — campurile se recunosc dupa eticheta.
-- **Panoul separat „Discount pe document" dispare**; discountul devine rand editabil in banda de
- totaluri, cu procentul pe loc.
-- **Banda de totaluri** e pe toata latimea, lipita de grid: baza, discount articole, discount document
- cu procentul, TVA — desfacute pe un rand — si totalul mare singur la dreapta.
-- **Incasare si Alte date NU sunt dialoguri** — sunt doua sectiuni colapsabile in formular, **una
- langa alta pe acelasi rand**, sub totaluri, fiecare cu rezumatul continutului pe randul inchis.
-- **Bara de comenzi de jos nu exista**: `but_renunt` / `but_termin` raman in banda de titlu.
-
-**Cota de TVA a discountului de document s-a decis — decizia 59, runda 16** (vezi sectiunea K-bis):
-repartizare proportionala automata pe cote, discountul **NU cere cota de la utilizator**, deci **nu
-e nevoie de o a treia sectiune pentru cota**. Ce mai cere UI e **un camp text optional de motiv**
-(pentru `AllowanceChargeReason`), mult mai mic decat o sectiune. **Decizia 61 (runda 16) l-a
-materializat: Marius vrea campul. Asezarea lui s-a inchis definitiv abia in runda 17 — decizia 64
-(a treia sectiune jos) a fost **rasturnata de decizia 66: motivul sta in banda de totaluri, langa
-suma pe care o explica**, iar randul de jos ramane cu **doua** sectiuni, ca la decizia 57. Varianta
-grea (cota + explicatie proprii) ramane exclusa, ca mai sus.
-
-**Cele doua pagini online ale lui #13 — nu se confunda:**
-- **mockup-ul formularului** (fisier pe disc, `docs\mockup_13_formular_unificat.html`, **v9** din runda
- 17, cu asezarea D si motivul discountului in banda de totaluri):
- **https://claude.ai/code/artifact/e9d73e86-7518-4f50-a998-43c49e083142**.
- Are copie pe disc, si ea e sursa de adevar; artifactul se republica din ea (`WebFetch` pe URL intai,
- apoi `Artifact` cu `url`). Decizia 33 e consumata — URL-ul e la zi.
-- **pagina cu variantele de asezare** (A/B/C/D), **fara copie pe disc**, deci artifactul **e** sursa de
- adevar:
-
-Pagina cu variantele: **https://claude.ai/code/artifact/dfc70d38-856f-48fd-b6af-3da78e9da4f7**
-— **nu mai are copie pe disc** (cerinta lui Marius, runda 15: „doar online, ca sa nu mai intretii 2
-variante"). Procedura de modificare: `WebFetch` pe URL → fisier de lucru **in scratchpad, nu in
-`docs\`** → `Artifact` cu `url` = link-ul de mai sus.
-
-#### S2 — O singura procedura `factureaza`
-Se elimina `factureaza2` ca procedura paralela; `factureaza` primeste un mod
-(`gnFacturareNou` ramane comutatorul de rulare, dar nu mai duce la alt cod duplicat). Se pastreaza
-integral ramurile care lipsesc azi din `factureaza2` (lista din A).
-
-**PROIECTAT (runda 9) — `docs\cercetare\s2_factureaza_unificare.md`.**
-**S2 e mult mai ieftina decat arata planul.** `factureaza2` nu e a doua implementare functionala care
-cere fuziune atenta — e un fork din 08.06.2017 la care **executia interogarii de articole e dezactivata**
-(`lnSucces = 1` hardcodat, `goExecutor.oExecute` niciodata apelat) si mai multe blocuri intregi sunt
-inchise cu `If .F.`. Are **exact un apelant** in tot codul — `ofacturare.prg:90`, din interiorul lui
-`factureaza`, in spatele unui `AMESSAGEBOX` de confirmare — deci **zero utilizatori reali**. Ambele sunt
-proceduri globale in `COMUN\programe\ofacturare.prg` (`:81-577` si `:583-1081`, ~500 de linii fiecare),
-fara omonime. Singura diferenta functionala care justifica existenta lui `factureaza2` e formularul de
-articole (`frm_facturare_articole2` vs `frm_facturare_articole`).
-**Obstacolul nu e tehnic:** formularul spre care duce e tot un prototip neterminat, deci unificarea
-procedurilor **nu** face formularul nou utilizabil — doar elimina duplicarea. Aia rămâne treaba lui S3.
-**Trei corectii la lista din sectiunea A:** `verifica_numar(16, ...)` pentru chitanta **nu lipseste** din
-`factureaza2` (e identic, `:502-504` vs `:1018-1020`) — planul greseste; „`cursor_avize` cu tip 23" e
-imprecis — tipul 23 nu lipseste, e **rutat diferit** (`cursor_preturi` in `factureaza` vs
-`cursor_gestiune` in `factureaza2`), ceea ce e mai grav decat o omisiune; si lipsesc din plan **tipul 52**
-pe ramura de contract si **tipul 24** pe ramura de retur. Semnatura propusa, ramificarea interna, ordinea
-in care se face fara sa strice suita si criteriul de „gata" verificabil sunt in raport, sectiunile 5-7.
-**`ofacturare.prg` e cod comun al intregii suite** (copie in fiecare produs ROA, sincronizata manual) —
-la fel ca S3c, nu se face impreuna cu alta modificare.
-*Gata cand:* `factureaza2` nu mai exista, iar comutatorul alege formularul, nu procedura.
-*Depinde de:* S1.
-
-#### S3 — Portarea logicii de antet in formularul unificat
-Cele 17 + 13 metode `do_cauta_*`, `do_schimba_tipdoc`, validarile din `inainte_de_do_termin`
-(`ofacturare.vc2:9455-9561` si `:7277-7352`) si `Init`-urile. Se porteaza **o singura data**, cu
-ramificare pe factura / aviz in interior, nu doua copii.
-Punct de atentie cunoscut: **#16 din `todos.txt`** — la revenirea din formularul de curs valutar,
-focusul sare pe tip document si iesirea din serie regenereaza numarul actului.
-
-**PROIECTAT (runda 9) — `docs\cercetare\s3_portare_antet.md`.** Doua rezultate schimba povestea:
-
-- **Portarea „o singura data cu ramificare" nu e posibila ca atare.** `Init`, `inainte_de_do_termin` si
- partial `do_cauta_fdoc` sunt **omonime cu semantica total diferita pe toate cele patru formulare-sursa**
- (antet vs. articole vs. alte-date). Deci nu e o metoda cu ramificare interna, sunt **patru fuziuni de
- metoda**. Obstacolul principal al lui S3 nu e codul de validare — majoritatea e `Do Case` / `amessagebox`
- mecanic — ci **reconcilierea a patru cicluri de viata `Init` / `inainte_de_do_termin` independente
- intr-unul singur**, cu ordinea de dependente din sectiunea 5 a raportului. Numarul real de `do_cauta_*`
- e **29, nu 30**. Lista completa a omonimelor e la sectiunea 2 — **se citeste inainte de orice editare**,
- altfel portarea le confunda (capcana deja platita o data cu `do_calculeaza_discount`).
-- **#16 nu e un bug de focus, si nu e in perimetrul in care il caută planul.** Reprodus pe cod pana la
- linia exacta: bucla de reincercare din `factureaza` / `factureaza2` (`ofacturare.prg:174-571`) trateaza
- **orice esec SQL** — nu doar cursul valutar lipsa — ca pe un „DA, continui cu alt document", si
- redeschide formularul de antet de la zero. Deci **unificarea nu-l reproduce automat**; poate chiar sa-l
- elimine ca efect secundar, daca antetul nu se mai reconstruieste din `Init` dupa un esec Oracle in pasul
- urmator. **Cade premisa „ori se rezolva #16 aici, ori se reproduce bug-ul".** Si leaga #16 de **S2**, nu
- de S3 — bucla e in procedura, nu in formular.
-
-*Gata cand:* un document se emite integral din formularul unificat, pe tip 1 (lista de preturi), cu
-acelasi rezultat in `vanzari` / `act` / `rul` ca pe calea veche — criteriul rescris verificabil e la
-sectiunea 7 a raportului, iar ce **nu** se poate testa headless la sectiunea 8.
-*Depinde de:* S2.
-
-#### S3b — Sectiunea pliata: alte date + analitice
-Deciziile 7 si 8. Se muta in formular cele patru grupuri din `frm_alte_date` (B) si coboara acolo
-analiticele din antet. `actualizeaza_tipincasare` se muta ca atare; **alocarea si dezalocarea
-numerelor** de chitanta / bon fiscal / POS raman legate de aceleasi evenimente ca azi, nu de
-deschiderea formularului. `frm_alte_date` nu se sterge cat timp calea veche mai e in uz.
-**Doua precizari din runda 7, amandoua restrang povestea:**
-- **analiticele coboara ca AFISARE, nu ca editare** (decizia 26) — venit/cheltuiala, sectie,
- responsabil, lucrare sunt read-only in formularul unificat; se editeaza din editorul de nota al lui
- **#6**, care le trateaza pe linie. Eticheta / tooltip trebuie sa spuna asta, altfel campul pare stricat;
-- **pe un document deja emis, grupul de incasare e blocat in etapa I** (decizia 25) — nu are ruta de
- scriere pe loc, iar regenerarea nu exista inca. La emitere se comporta ca azi.
-**PROIECTAT (runda 11) — `docs\cercetare\s3b_alte_date_analitice.md`.** S3b nu e o mutare de controale.
-Trei rezultate schimba povestea:
-
-- **Riscul din criteriul de „gata" e real, si are mecanism.** Alocarea numarului de chitanta nu porneste
- din clicul utilizatorului, ci din **orice atribuire programatica** a lui `.Value`:
- `opt_incasat.ProgrammaticChange` (`ferestre_cere_date.vc2:3351-3352`) cheama acelasi
- `actualizeaza_tipincasare()` ca `.Click` (`:3250-3251`). Consecinta neasteptata: **azi, deja**,
- `Init` (`:3150`) seteaza singur `opt_incasat.Value = 2` cand documentul soseste cu `poDate.incasat<>0`
- (cazul copierii), deci deschiderea dialogului aloca un numar fara ca cineva sa atinga ceva. Intr-un
- formular unde zona se plieaza si se deplieaza repetat pe acelasi `poDate` persistent, o repopulare
- naiva a starii ar aloca si dezaloca **la fiecare toggle**. Solutia proiectata: populare **o singura
- data**, iar plierea strict pe `Visible`/`Height` — niciodata pe reasignare de `.Value`. Criteriul de
- non-alocare e formulat ca **assert headless pe `poGeneratorNumere`**, pe doua scenarii de start
- (document nou **si** document copiat cu incasare presetata — al doilea e cel care azi chiar aloca).
-- **Nu exista mecanism de pliere de refolosit.** Cautare exhaustiva in `ofacturare.vc2`: zero potriviri
- in prototipul `frm_facturare_articole2`. Cel mai apropiat tipar din suita e
- `frm_modific2024.afiseaza_rulaje` (`omodificari.vc2:13169-13199`, perimetrul #6 — **citit, neatins**),
- acelasi idiom sus/jos validat deja pentru `but_modifica`/`but_salveaza` la decizia 9. Deci **cod nou**,
- dupa un tipar existent, nu o clasa reutilizabila.
-- **Decizia 26 cere mai mult decat mecanismul existent.** `ct_clb_cautare.do_dezactiveaza()`
- (`caut_ora.vc2:800-806`) ascunde **doar lupa de cautare**; textbox-ul ramane tastabil. Read-only real
- cere `ReadOnly` explicit pe langa el — nesemnalat pana acum.
-
-**Bug preexistent, gasit in trecere:** la Renunt se dezaloca chitanta (16) si bonul fiscal (3), dar
-**nu si POS (26)**. Nu e introdus de S3b, dar „`actualizeaza_tipincasare` se muta ca atare" **l-ar
-propaga**. **Decizia 40: se repara aici, in trecere** — deci diff-ul lui S3b nu mai e o mutare pur
-mecanica, si testarea acopera si dezalocarea POS pe calea veche.
-
-**Decizia 41 fixeaza granularitatea plierii: doua comutatoare.** Grupul de **incasare** are comutator
-propriu — e singurul cu efecte laterale (alocare/dezalocare) si singurul blocat pe document emis prin
-decizia 25 — iar delegat/transport, adresa, text aditional si analiticele stau impreuna sub al doilea.
-Garda de non-alocare la toggle se scrie si se testeaza astfel **intr-un singur loc**.
-
-*Gata cand:* criteriul rescris verificabil e la sectiunea 10 a raportului, in cinci puncte — mai strans
-decat formularea de mai jos pe trei dintre ele: paritatea de emitere se cere pe **toate patru** tipurile
-de incasare (nu doar bon fiscal), non-alocarea la toggle se cere pe **ambele** scenarii de start, iar
-blocarea grupului de incasare si read-only-ul analiticelor se cer pe **ambele stari ale antetului**
-(inainte si dupa `but_modifica`), nu doar la deschidere. Formularea initiala, pastrata ca rezumat: 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.
-*Depinde de:* S3.
-
-#### S3c — Sursa ca parametru, nu ca global
-Decizia 12. Punctele de intrare exista deja (comanda: `ocomenzi.vc2:1580-1596`; contract: din
-ROACONTRACTE), dar transmit prin globalele `goComanda` / `goContract`. Se adauga parametru explicit
-pe `factureaza` si pe `oDateFactura`, cu globalele pastrate ca sursa de rezerva pana se convertesc
-toti apelantii (inclusiv cei din ROACONTRACTE si ROAGEST — e cod comun). Se verifica intai asimetria
-de resetare semnalata la L.3.
-**PROIECTAT (runda 11) — `docs\cercetare\s3c_sursa_ca_parametru.md`.** Se poate face, e o interventie
-mica — dar **planul supraestimeaza cat de „globala" e problema azi**, si in doua sensuri opuse:
-
-- **`goContract` nu e scris nicaieri in ROAFACTURARE** — nici in codul produsului, nici in `COMUN`-ul
- lui. Deci ramura de precompletare din contract (`ofacturare_comun.prg:261-297`) e **cod mort in acest
- produs**, iar **asimetria de resetare de la L.3** (`ofundal_facturare.vc2:886-902`) exista textual dar
- e **inerta**: n-are ce sa lase nereseta, pentru ca n-are scriitor. Devine risc real abia daca cineva
- adauga in viitor un scriitor in ROAFACTURARE — moment in care lipsa resetarii s-ar activa **tacut**.
-- **`goComanda` chiar e viu, si are DOI scriitori**, nu unul: clicul pe „Factureaza"
- (`ocomenzi.vc2:1583`) **si** navigarea in grid (`:2199`, doar ca sa decida vizibilitatea unui buton).
- Al doilea n-are nicio legatura cu facturarea si **ramane si dupa conversie** — deci globala nu dispare.
-- **Criteriul „pana se convertesc toti apelantii" nu se poate citi ca „pana dispare globala".** In
- ROACONTRACTE, `goContract` e **bufferul de editare al intregului ecran de contracte** (peste 100 de
- `ControlSource` legate de el), populat de navigarea in grid, independent de facturare. Nu dispare la
- aceasta poveste si nici la vreuna rezonabila urmatoare; S3c schimba **doar canalul** prin care valoarea
- ajunge la `oDateFactura.Init`.
-
-**Suprafata de regresie, masurata:** doi scriitori de convertit (`ocomenzi.vc2:1580-1596`;
-`ferestre_contracte.vc2:1538-1549` + `:1598-1606` in ROACONTRACTE), **trei** fisiere comune atinse o
-singura data fiecare (`ofacturare.prg`, `oproceduri_facturare.prg`, `ofacturare_comun.prg`), si **zero
-schimbari** la celelalte ~31 de puncte de intrare din inventarul S2 — toate cheama `factureaza(N)` cu un
-singur argument. Cele cinci fisiere sunt **identice pe MD5** in cele sapte produse, cu o singura exceptie:
-**ROAIMOB**, o linie lipsa in `ofacturare_comun.prg` — acolo diff-ul se aplica **manual**, nu prin copiere
-mecanica.
-
-**Semnatura propusa:** `factureaza(tnTip, toFactura, toSursa)` si `oDateFactura::Init(tnIdSet, tnTip,
-toSursa)` — parametru nou la coada, cu implicit, fallback pe global cand lipseste.
-**Capcana de limbaj, semnalata explicit:** garda se scrie `Type('toSursa') = 'O'`, **nu**
-`Type('toSursa') <> 'U'`. Un parametru VFP nepasat **nu** e `'U'` (aia e pentru variabile nedeclarate),
-ci `'L'` cu `.F.` — o garda `<> 'U'` ar trece mereu adevarat si ar incerca sa citeasca `.id_part` de pe
-`.F.`, eroare la primul apel neconvertit. Raportul cere verificarea comportamentului `Type()` pe un
-`.prg` de proba **inainte** de a atinge fisierele reale.
-
-*Gata cand:* criteriul rescris e la sectiunea 10 punctul 4 al raportului, pe patru probe — una
-structurala (parametrul prezent cu semnatura identica in toate cele trei fisiere comune, in toate cele
-sapte produse) si trei comportamentale: **calea convertita** cu globala deliberat „murdara" dintr-o
-navigare anterioara produce documentul dat prin parametru, nu pe cel din globala; **calea neconvertita**
-(oricare din cele ~31 de apeluri cu un singur argument) produce acelasi document ca inainte; iar
-**ROACONTRACTE** da aceeasi precompletare ca azi, verificat manual pe build separat.
-*Depinde de:* S2. **Atinge cod comun intregii suite** — nu se face impreuna cu alta modificare.
-
-#### S4 — Cautarea articolelor pe server, in linie
-Partea Oracle: variante filtrate pe articol ale cursoarelor de facturare, cu aceleasi ramuri pe tip
-ca `cursor_preturi` / `cursor_contract` / `cursor_comanda` / `cursor_avize` / `cursor_gestiune`.
-Partea VFP: `combosql` pe cod si pe denumire completeaza linia cu pret, cota TVA, valuta, `id_pol`,
-`gestionabil`, `pret_cu_tva`; `crsarticole` nu se mai incarca in masa.
-Se pastreaza "adauga tot" pentru tipurile care au document sursa (comanda, aviz, contract) — acolo
-setul e marginit si incarcarea lui e legitima.
-**PROIECTAT (runda 11) — `docs\cercetare\s4_cautare_articole_server.md`. Criteriul de mai jos nu e
-atingibil ca atare, si motivul nu e UX.**
-
-- **`crsarticole` nu e doar sursa de populare a gridului — e un registru al cantitatii ramase de
- facturat.** E citit **si scris** de `do_adauga_tot`, `do_sterge` si `do_scrie_factura` pentru toate
- tipurile cu document sursa: stergerea unei linii **reface** cantitatea in `crsarticole`
- (`ofacturare.vc2:14640-14669`), iar la scriere se face `Calculate Sum(cantitate) To lnCantitateRamasa`
- peste el ca sa se decida daca se inchide automat comanda / avizul (`:14303-14311`, `:14334-14338`).
- Deci pe **comanda, aviz si contract** incarcarea in masa **nu poate disparea**, indiferent de decizia
- de UX privind „adauga tot" — bookkeeping-ul e cablat pe cursorul incarcat. **S4 se aplica curat doar
- pe ramurile de lista de preturi** (`cursor_preturi`, plus jumatate din `cursor_contract` si
- `cursor_gestiune`).
- **DEPASIT de proiectarea punctului 2 (runda 12)** — se citeste doar ca istoric al deciziei 39.
- Concluzia „incarcarea in masa nu poate disparea" cadea pentru ca `crsarticole` era tratat ca un
- registru omogen; sunt de fapt **doua mecanisme distincte** (Rol A / Rol B), si niciunul nu cere
- cursorul incarcat. Vezi mai jos.
-- **`combosql` e un prototip la jumatate, si e singura lui utilizare din suita.**
- `grd_factura.cCodMat.cboCodmat` / `cCboDenumire` (`ofacturare.vc2:16751-16797`, wiring la
- `:19288-19334`) chiar cauta pe server, dar scrie **doar** `codmat` / `denumire` / `id_articol`, pentru
- ca sursa lui (`vnom_articole`) n-are pret, TVA, valuta, `id_pol`, `gestionabil`. Cautare in
- `COMUNROA` si `ROAGEST`: **zero alte utilizari** — nu exista de unde copia un exemplu complet.
- Confirma insa exact punctul C: de facut e **varianta filtrata pe articol a celor cinci cursoare**, nu
- o cautare noua.
-- **`cursor_contract` produce deja doua cursoare** — `V_CURSOR` (`crsarticole`, prin delegare la
- `cursor_preturi`) si `V_CURSOR2` (`crsarticole1`, articole **sau** rate). Filtrarea se aplica curat
- doar pe jumatatea `crsarticole`; **randurile de rata n-au `id_articol`** si raman needitate.
-- **Vizibilitatea de azi a butonului „adauga tot" coincide aproape exact cu impartirea utila pentru S4**
- (`ofacturare.vc2:15108-15248`: ascuns pe lista de preturi, vizibil pe comanda / aviz / retur) —
- confirmare pe cod, nu presupunere.
-- **Legatura cu S10, confirmata:** pretul se cauta **o singura data**, la alegerea liniei, si se
- transmite mai departe neschimbat — exact ce face azi `adauga_articol_factura`, care il primeste ca
- parametru in loc sa-l re-derive.
-- **Efect secundar al filtrarii, rezolvat prin decizia 42:** `verifica_cursuri_valute` e azi
- neconditionata in procedura, deci pe varianta filtrata s-ar declansa la **fiecare** cautare de articol
- in loc de o data la deschidere — cu `-20005` posibil pe o valuta pe care operatorul n-o foloseste,
- inainte sa vada vreun rand. Se **restrange la valuta articolului cautat**.
-- **Cele doua puncte „de inchis inainte de implementare" sunt INCHISE (runda 12)** —
- `docs\cercetare\s4_puncte_deschise.md`. Raspunsul de baza e la amandoua „filtrarea nu schimba nimic",
- dar **fiecare lasa in urma o cerinta de implementare, nu doar o bifa**:
- - **`id_jtva_coloana` chiar lipseste** din `cursor_preturi`, din `cursor_gestiune` si din `V_CURSOR2`
- al lui `cursor_contract`, pe toate ramurile — confirmat pe SQL. **Nu e bug:** `do_initializeaza_articol`
- pune `0`, iar `frm_articol_factura.Init` (mostenit si de `frm_articol_gest_factura`) **il rederiva
- mereu** din `proc_tvav` via `jtva_coloane`, pe orice linie adaugata prin `do_adauga_articol`.
- **Cerinta care rezulta pentru S4:** derivarea tine **numai** daca linia trece prin
- `do_adauga_articol`. `combosql`-ul prototip de azi (`ofacturare.vc2:19288-19306`) face `REPLACE`
- direct in `crsfactura` si **ocoleste toata derivarea**; daca S4 extinde acel `REPLACE` fara sa treaca
- prin `do_adauga_articol`, `id_jtva_coloana` ramane nederivat si Oracle
- (`adauga_articol_factura`, ramura `ELSE`) arunca **`-20000 FACT-013`** sau scrie cota gresita.
- **Bug nou posibil, introdus de S4** — intra ca cerinta explicita in proiectare, nu ca observatie.
- - **`but_urmator_tot1` are `Visible = .F.` la design** (`ofacturare.vc2:11265`); tipurile 23 si 41 au
- `Case` propriu, dar **niciunul nu-l face vizibil** — confirmat, nu presupus. Nu exista alt mecanism
- de „adauga tot"; exista insa `but_urmator1` (adaugare rand-cu-rand), **neconditionat de tip**, care
- merge prin acelasi `do_adauga_articol` — deci dupa S4 **nu se pierde nimic** pe aceste tipuri.
- - **Corectie de rutare fata de ce presupunea planul:** pe formularul **standard** (`factureaza`,
- `ofacturare.prg:266-308`) doar **tipul 41** cheama `cursor_gestiune`; **tipul 23 cheama de fapt
- `cursor_preturi`** (grupat cu lista de preturi). Tipurile **45, 48, 49 nu ating deloc**
- `cursor_gestiune` (45 → `cursor_preturi`, 48/49 → `cursor_articole_k`, alta procedura). Doar pe
- **prototip** (`factureaza2`, opt-in `gnFacturareNou`) 23 si 41 merg impreuna pe `cursor_gestiune` —
- **divergenta reala intre cele doua formulare**, semnalata, neatinsa, in afara perimetrului S4.
-
-**Decizia 39 largeste povestea peste ce propunea raportul.** Raportul recomanda restrangerea la lista de
-preturi, tocmai pentru ca registrul de cantitate ramasa blocheaza restul; Marius a ales sa se desfaca si
-registrul. Deci S4 are de acum **doua bucati, nu una**:
-1. **varianta filtrata a cursoarelor** + completarea liniei din `combosql` (partea proiectata in raport);
-2. **decuplarea bookkeeping-ului de cantitate ramasa** de cursorul incarcat in masa — sursa unica, nu o a
- doua copie tinuta in pas cu prima. Atinge `do_adauga_tot`, `do_sterge`, `do_scrie_factura` si
- **inchiderea automata** a comenzii / avizului.
-
-**Punctul 2 — PROIECTAT (runda 12): `docs\cercetare\s4_punct2_registru_cantitate_ramasa.md`.** Iese mult
-mai ieftin decat parea, pentru un motiv care nu se vedea din raportul punctului 1.
-
-- **`crsarticole.cantitate` are DOUA roluri, nu unul** — si numai unul e „registrul" temut.
- **Rol A — cantitate ramasa de facturat dintr-un document sursa** (comanda `3,21,25,28,42,47`; avize
- `4`). **Rol B — plafon de cantitate in sesiune** (lista de preturi gestionabila `1,22,29` si jumatatea
- de contract, transfer `23,41`, retur `8,9,24`): impiedica operatorul sa adauge mai mult decat vede pe
- ecran. **Rol B nu alimenteaza nicio decizie Oracle** — e plafon de UI, nu registru de business.
-- **Pe Rolul A, cursorul VFP e o copie redundanta a unui calcul pe care Oracle il repeta oricum.**
- `do_scrie_factura` sumeaza `crsarticole` doar ca sa decida ce trimite in `pnParametruAditional`, iar
- Oracle **recalculeaza independent, din tabele reale**, in `inchide_comanda()` / `marcheaza_facturat()`,
- chiar in procedura care scrie factura.
-- **Nu exista coloana `INCHISA`.** Cautare in tot pachetul: **zero potriviri** (verificat separat de
- sesiunea principala). „Comanda inchisa" e o stare **derivata** din `COMENZI_ELEMENTE` vs
- `VANZARI_DETALII`; `inchide_comanda()` insereaza un **rand compensator**, nu seteaza un flag. Pe
- comanda, `pnParametruAditional` e strict **binar** — „s-a cerut fortarea inchiderii?" —, iar cantitatea
- trimisa de VFP **nu participa** la calculul Oracle.
-- **Pe avize e altfel, si aici sta subtilitatea:** `VANZARI.FACTURAT` **e** un flag persistat, iar
- `V_VERIFICARE` (= `pnParametruAditional`) alege intre „**increde-te in VFP** si marcheaza toate avizele
- referite" (`0`) si „**recalculeaza per-aviz** din tabele reale si marcheaza doar cele cu `ramas = 0`"
- (`1`). Deci pe aviz suma din VFP schimba semantica, nu doar declanseaza o actiune.
-- **Un bug preexistent, de REPRODUS identic, nu de reparat in trecere:** cand un `crsarticole` agrega mai
- multe avize, suma globala poate da `0` desi un aviz are ramas si altul are exces care-l compenseaza —
- caz in care toate se marcheaza facturate, inclusiv cel cu ramas real. Varianta noua pastreaza aceeasi
- conditie de declansare (suma globala pe tranzactie, nu per document).
-- **`23` si `41` nu apar deloc in `CASE`-ul de finalizare** — cad pe `ELSE`, fara nicio inchidere:
- transferul n-are document sursa de inchis, doar plafon (Rol B). Contractul (`2,6,52`) intra pe
- `scrie_rate_factura`, care **nu e o inchidere**, e alta operatie.
-- **Recomandarea: (b) pentru Rolul A, (c) pentru Rolul B.**
- **(b)** cele doua `Calculate Sum` din `do_scrie_factura` se inlocuiesc cu un apel Oracle facut **dupa**
- `do_scrie_articole()` (cand `VANZARI_DETALII_TEMP` contine exact liniile pe cale sa fie scrise) si
- **inainte** de `Do Case`-ul care alege procedura de scriere. Cele doua functii Oracle noi sunt o
- **extragere** a interogarii pe care `inchide_comanda` / `marcheaza_facturat` o ruleaza oricum, nu logica
- noua. Efect secundar gratuit: dispare si un bug latent de concurenta — cursorul local nu vede azi ce a
- facturat intre timp alt operator din aceeasi comanda.
- **(c)** plafonul Rol B se cere pe server **la fiecare adaugare/editare**, minus ce e deja in
- `crsfactura` — deci nu mai exista a doua copie de tinut in sincron.
- Varianta cu un cursor propriu, minimal, a fost **respinsa motivat**: ramane tot o a doua copie manuala,
- doar mai ingusta. Nu e „sursa unica".
-- **Cazul limita cerut in plan** (adauga si sterge inainte de salvare) devine **trivial**, nu doar
- acoperit: liniile adaugate-si-sterse nu ajung niciodata in `VANZARI_DETALII_TEMP`, deci nu influenteaza
- calculul, fara nicio actiune de refacere.
-- **CORECTIE asupra punctului 1:** pasul lui 5 (`s4_cautare_articole_server.md:417-424`) opreste
- incarcarea in masa si pe `23,41`, presupunand ca n-au bookkeeping — **au Rol B**, confirmat pe cod.
- Punctul 1 **nu se poate aplica pe `23,41`** inainte ca punctul 2 sa acopere Rolul B pe ele.
-
-**Toate trei sunt INCHISE (runda 13). Nu se mai reiau.**
-1. ~~**Asimetria din `do_modifica`**~~ — azi, pe grupul `1,22,29` + contract-lista, plafonul **nu** se
- ajusteaza la editarea cantitatii unei linii deja adaugate. E preexistenta. **INCHIS — decizia 45
- (runda 13, pe recomandare):** se lasa sa se **corecteze de la sine** prin recalculul la cerere, cost
- zero, dar corectia se **declara explicit in changelog** — S4 schimba atunci un comportament punctual,
- nu doar „decupleaza".
-2. ~~**Corectia pe `23,41`**~~ — **INCHIS — decizia 46 (Marius, runda 13): asteapta punctul 2.**
- Punctul 1 **nu se redeschide** acum; aplicarea lui pe `23,41` vine odata cu recalculul pe server, care
- acopera Rolul B. Nu se pierde nimic: ordinea de implementare oricum le pune dupa.
-3. ~~**Contract `26,52`**: nu s-a gasit dovada nici de prezenta, nici de absenta a Rolului B.~~
- **INCHIS de proiectarea S5** (`docs\cercetare\s5_acoperire_tipuri.md`): `26` si `52` **n-au niciun
- bookkeeping**, nici Rol A, nici Rol B — excluderea e totala, pe `Do Case` exhaustiv fara ramura
- implicita. Deci „dovedit absent", nu „nepresupus". Nu mai e o decizie de luat.
-
-**Cerinta de revizuire**: cele doua functii Oracle noi sunt o extragere din proceduri existente, dar
-raman **PL/SQL nou in `PACK_FACTURARE`**, cu `JOIN`-urile reproduse **din citire, nu din executie**. Se
-verifica pe Oracle inainte de a continua — e primul pas al implementarii, nu o formalitate.
-
-**Nota de executie (decizia 60):** pe documentele de tip **48/49** (custodie), cautarea pe server in
-linie ramane restransa la articole `IN_STOC = 0` — nu se ofera articole gestionabile pe aceste tipuri.
-Siguranta regenerarii la editarea custodiei (decizia 60,
-`docs\cercetare\custodie_48_49_stergere_reemitere.md`) atarna de acest invariant.
-
-*Gata cand:* patru probe, nu una. **(a)** Deschiderea formularului nu mai executa niciun cursor de
-articole, **pe niciun tip** — nu doar pe lista de preturi. **(b)** Alegerea unei linii produce aceleasi
-valori ca randul corespunzator din `crsarticole` de azi, pe fiecare tip; maparea camp-cu-camp e la
-sectiunea 6 a raportului, cu coloanele semnalate explicit acolo unde varianta filtrata **nu** poate
-produce aceeasi valoare. **(c)** **Paritate pe inchiderea automata** (decizia 39): acelasi document
-sursa, aceleasi linii facturate partial, **aceeasi stare finala** — pe comanda, acelasi rand compensator
-in `COMENZI_ELEMENTE` (nu exista flag `INCHISA` de comparat); pe aviz, exact aceleasi `VANZARI.FACTURAT`
-marcate, inclusiv in cazul in care avizele agregate se compenseaza intre ele — pe fiecare tip cu document
-sursa —
-inclusiv cazul in care operatorul adauga si apoi sterge linii inainte de a salva, care azi trece prin
-refacerea cantitatii in `crsarticole`. **(d)** O linie adaugata prin cautarea in grid ajunge in
-`crsfactura` cu **`id_jtva_coloana` derivat** — adica trece prin `do_adauga_articol`, nu prin `REPLACE`
-direct ca prototipul de azi; proba e ca documentul se scrie fara `FACT-013` si cu aceeasi cota ca pe
-calea veche. **(e)** Pe un document de tip 48/49, cautarea pe server nu ofera si nu permite adaugarea
-unui articol cu `IN_STOC <> 0` (decizia 60).
-*Depinde de:* S3. **Punctul 2 nu e proiectat** — se proiecteaza separat inainte de implementare.
-
-#### S4b — Bara de butoane si meniul de adaugare
-Decizia 13, proiectata in J. Trei bucati:
-1. **Butoanele de linie deasupra gridului**, cu eticheta, nu iconite mute: linie noua (`but_nou`),
- sterge linia (`but_sterge`), detalii linie.
-2. **Un singur buton „Adauga articole” cu `xmenu()`**, cu optiunile din tabelul din J. Inlocuieste
- `But_urmator_tot1` (azi fara caption si fara `ToolTipText`) si butonul separat de alegere.
- **Acopera si contractele** — tipurile 2, 6, 26, 52 lipsesc azi din conditiile de vizibilitate
- (`ofacturare.vc2:15113-15245`), desi avizele sunt acolo.
-3. **Alegerea selectiva**, dupa tiparul RORIS: dialog modal cu coloana de bifat si criterii de
- cautare, populare aditiva in cursorul local, nicio scriere in baza pana la salvare. Pe contract,
- unitatea de selectie e **rata** — cazul explicit cerut. Spre deosebire de modelul RORIS, la zero
- rezultate se spune de ce, nu se inchide in tacere.
-**PROIECTAT (runda 11) — `docs\cercetare\s4b_bara_butoane_meniu.md`.** Implementabila fara cod nou major,
-cu **patru corectii** fata de textul de mai sus:
-
-- **Golul de contract e mai mare decat „lipseste `but_urmator_tot1.Visible`".** Pe **tipul 52**
- formularul nu intra in **niciun** `Case` al `Do Case`-ului (`ofacturare.vc2:15109-15248`) — deci pierde
- si titlul, si eliminarea coloanei `cSerie`, nu doar butonul „tot".
-- **Nu se porneste de la tiparul RORIS.** `frm_tranzit` e specific ROAACNPRO si ar insemna formular nou;
- ROAFACTURARE are deja `cauta_alfa(..., tnTipReturn=1)` — mecanism **generic** de selectie multipla cu
- bifare, criterii de cautare si populare aditiva, folosit **chiar in acest formular** pentru returul
- multi-factura (`do_cauta_facturi`). Mai ieftin, si deja dovedit in productie.
-- **„Unitatea de selectie e rata" e adevarat doar pe jumatate.** `crsarticole1` are **doua ramuri
- disjuncte** in SQL — `OPT_FACTURARE = 3` (articole reale) si `OPT_FACTURARE IN (1,2)` (rate de
- scadentar) — iar un contract e mereu pe una singura, niciodata pe amandoua. Eticheta „Alege ratele de
- facturat…" e corecta doar pe a doua ramura; **contractul are deci doua meniuri, nu unul**.
-- **Un gol de cod, nu doar de vizibilitate:** `do_adauga_tot` parcurge azi **exclusiv `crsarticole`,
- niciodata `crsarticole1`**. Fara extindere, „adauga tot" pe contract fie n-ar face nimic, fie ar aduce
- liniile gresite — deci pe contract butonul trebuie **scris**, nu doar facut vizibil.
-
-**Echivalenta „tot" = „alege total"** tine azi prin constructie, pe o singura rutina comuna de adaugare
-pe rand (`do_adauga_articol`) — se pastreaza asa, iar pe contract devine adevarata abia dupa extinderea
-de mai sus.
-
-*Gata cand:* pe fiecare sursa (comanda, contract, avize, document returnat) meniul ofera si „tot" si
-„alege", iar rezultatul in `crsfactura` e identic pe cele doua cai cand selectia e totala — **inclusiv
-pe contract**, unde azi „tot" nu parcurge cursorul potrivit, si **inclusiv pe tipul 52**, care azi nu
-intra in nicio ramura. Pasii cu criterii verificabile sunt la sectiunea 7 a raportului; ce nu se poate
-testa headless, la sectiunea 8.
-*Depinde de:* S4.
-
-#### S4c — Discountul pe linie, mutat din dialog in grid
-Decizia 14, proiectata in K. Dialogul de articol dispare odata cu unificarea, deci cele doua campuri
-de discount ale lui — **procent** si **valoare unitara** — devin coloane in grid, cu acelasi calcul
-reciproc din `frm_articol_factura.do_calculeaza_discount` mutat pe evenimentele coloanelor. Se repara
-in acelasi timp inconsecventa de azi (read-only in lei, editabil fara recalcul in valuta). Se
-pastreaza excluderea pe `in_valuta`. Modelul de date **nu se atinge** — se stocheaza tot valoarea.
-**VERIFICAT — S4c e deblocata, dar capcana e alta decat se credea.** Raport:
-`docs\cercetare\discount_in_rapoarte_si_efactura.md`.
-
-- **Niciun raport de factura nu tipareste discountul pe linie** — nici valoare, nici procent. Cautare
- in toate `.fr2` de factura / proforma / invoice din `COMUN\Rapoarte`: **zero potriviri** pe „disc".
- Singurele doua `.fr2` cu „DISCOUNT" sunt de NIR, nu de facturi emise. Se tipareste `pretftva` si
- `valftva`, **deja nete de discount** (`prelucreaza_factura`, `ofacturare_comun.prg:1055-1059`,
- `:1156-1248`, in cursorul `crsfacttemp`).
-- **eFactura foloseste exact acelasi cursor** (`xmlefactura.prg`) — `LineExtensionAmount` si
- `PriceAmount` sunt aceleasi valori nete, cu optiunea (dezactivata implicit) de a adauga si un
- `cac:AllowanceCharge` informativ pe linie.
-- **SAF-T (D406) nu exista in ROAFACTURARE** — doar tabele de nomenclator cu prefix `saft_` (coduri
- TVA / plata), pe partea de achizitii, fara legatura cu `DISCOUNT_UNITAR`.
-- **Deci ingrijorarea initiala („utilizatorul schimba totalul fara sa se vada pe hartie") era gresit
- tintita:** discountul nu se vede pe hartie **prin design**, iar totalul se vede corect pentru ca
- pretul tiparit e deja net.
-
-**PROIECTAT (runda 12) — `docs\cercetare\s4c_discount_in_grid.md`.** Implementabila, cu **capcana
-retintita**: formularea de mai jos, din rundele anterioare, era in acelasi timp prea alarmista si prea
-vaga.
-
-- **Baza de date nu e in pericol.** `do_scrie_articole` trimite spre Oracle **direct** din
- `discountftva` / `discountctva` / `vdiscountftva` / `vdiscountctva` (`ofacturare.vc2:14081-14083`,
- ales pe `cu_tva` si `tip_valuta`) — verificat pe cod, nu presupus. Deci
- `VANZARI_DETALII.DISCOUNT_UNITAR` iese **mereu corect**, indiferent de starea campurilor agregate.
-- **Riscul e strict local, si e o inconsistenta, nu o valoare veche.** `valdiminuatftva` /
- `valdiminuatctva` sunt agregate citite de `prelucreaza_factura` **din acelasi `crsfactura` din
- memorie**, nereincarcat din Oracle. Netratate, factura tiparita poate iesi cu `pretftva` corect si
- `valftva` inconsistent — **pret x cantitate diferit de valoare**, ceea ce se vede pe hartie.
-- **Exista deja azi calea care demonstreaza gaura:** editarea `vdiscountftva` in grid, pe factura in
- valuta, **nu declanseaza recalculul** agregatelor (`discount_verificare2.md`, punctul 3).
-- **Calculul e deja generic si refolosibil**, nu trebuie rescris: `do_calculeaza_discount`
- (`ofacturare.vc2:1874-1976`) plus `calculeaza_totaluri()` (`oproceduri_facturare.prg:2258-2381`),
- care ruleaza pe `Scatter Name`, **fara dialog**.
-- **Evenimentul recomandat pe coloanele noi e `Text1.LostFocus`**, nu `InteractiveChange` sau `Valid` —
- tiparul e deja folosit in acelasi fisier, pe `frm_avizare_lucrare.grd_articole.cCantitate` /
- `cPret` (`:6549-6562`).
-- **Punctul deschis din S1 e inchis in trecere:** `_checkbox1` si `chkDetaliat` sunt **doua controale
- distincte** in `frm_alte_date`, nu o duplicare — subiectul nu are legatura cu S4c.
-
-*Gata cand:* tastarea in oricare din cele doua coloane produce aceleasi valori in `crsfactura` ca
-dialogul de azi, pe ambele monede; totalurile se refac imediat; discountul venit din politica de pret
-se comporta ca azi; **si `valdiminuatftva` / `valdiminuatctva` se recalculeaza la fiecare editare**,
-astfel incat pe factura tiparita `pret x cantitate` sa dea exact valoarea — verificat prin retiparire
-si prin XML-ul de eFactura, nu doar pe ecran. Pasii cu criterii verificabile sunt la sectiunea 7 a
-raportului; ce nu se poate testa headless, la sectiunea 9.
-*Depinde de:* S4.
-
-#### S4d — Data cursului valutar, numai cand are sens
-Decizia 15, proiectata in M. Campul apare cand tipul nu e retur **si** (documentul e in valuta **sau**
-a intrat pe grid macar un articol cu pret in valuta) — evaluat reactiv, ceea ce devine posibil abia
-in formularul unificat.
-**VERIFICAT — S4d e deblocata.** Raport: `docs\cercetare\zi_curs_validare.md`. Ascunderea selectorului
-**nu** poate lasa documentul fara curs, cu o conditie deja indeplinita de cod:
-
-- **Implicitul exista si e neconditionat.** `poDate.zi_curs` primeste data documentului chiar in
- `oDateFactura.Init` / `Reset` (`COMUN\programe\ofacturare_comun.prg:247`, `:496`), **inainte** ca
- formularul sa decida ce ascunde. **Nicaieri codul nu goleste `zi_curs` cand controlul e ascuns.**
- Deci „valoarea implicita ramane" nu e ceva de construit — e comportamentul actual, de **nestricat**.
-- **Precedentul cerut exista deja**, in alt formular: `frm_date_factura`, tipurile 8 / 9 (retur), unde
- `clb_zi_curs` se elimina **neconditionat** si documentul se salveaza corect — in principal pentru ca
- `cursor_retur` nici nu foloseste `poDate.zi_curs`.
-- **Linia `:8076` nu e in formularul de factura.** Apartine lui `frm_date_aviz_lucrare`
- (`inainte_de_do_termin`, `ofacturare.vc2:8054-8119`), un formular restrans pentru **aviz pe lucrare /
- aviz pe NIR** (tipurile 27 si 30), care nici nu are control de valuta. Valideaza `zi_curs` pentru ca
- tipul 27 are nevoie de curs pentru articolele din comanda, **independent de `poDate.in_valuta`** —
- deci nu e o inconsecventa de reparat orbeste, are un motiv. Se aliniaza doar daca formularul unificat
- preia si tipurile 27 / 30.
-
-**Riscul real e in alta parte, si nu tine de vizibilitatea campului:**
-`pack_facturare.verifica_cursuri_valute` (chemata din `cursor_preturi`) ruleaza **neconditionat de
-`in_valuta`** si exclude doar moneda nationala. Deci un `zi_curs` implicit (azi) fara curs setat in
-`CURS` pentru o valuta prezenta in listele de preturi ale utilizatorului **poate pica oricum**
-(`-20005`, „Nu este setat cursul…"), indiferent daca selectorul e vizibil sau nu. **Ascunderea nu
-introduce riscul asta si nici nu-l rezolva** — dar il face mai greu de inteles pentru operator, care nu
-mai vede campul din cauza caruia primeste eroarea. De tratat in mesajul de eroare, nu in vizibilitate.
-
-**PROIECTAT (runda 12) — `docs\cercetare\s4d_zi_curs_reactiv.md`.** Nu se inventeaza nimic; se
-reevalueaza vizibilitatea unui control care exista deja.
-
-- **Cheia reactivitatii e un camp deja prezent in cursorul gridului: `crsfactura.tip_valuta`**,
- interogabil cu **exact tiparul deja folosit in cod** (`ofacturare.prg:1656`, `:1730`:
- `Select Distinct ... From crsfactura Where tip_valuta = 1`). Nu e nevoie de o structura noua.
-- **Prototipul are deja `Clb_zi_curs` propriu, editabil, legat la `poDate.zi_curs`**
- (`ofacturare.vc2:16285-16305`) — se schimba doar **cand** e vizibil.
-- **Mesajul `-20005` contine DEJA data si numele valutei lipsa** (`STRINGAGG` peste toate valutele fara
- curs) — deci partea de „sa spuna care valuta si ce zi" nu e de construit. **Decizia 42 nu schimba
- continutul mesajului, ii schimba domeniul**: il restrange la valuta articolului cautat, dar **numai pe
- varianta filtrata** (S4 punctul 1); pe caile cu document sursa incarcarea in masa ramane
- neconditionata, deci acolo eroarea poate inca numi o valuta straina de documentul curent.
-- **Ce lipseste cu adevarat, si intra ca pas de implementare, nu ca optiune:** sectiunea M cere ca la
- aceasta eroare campul sa **revina vizibil** — altfel operatorul primeste o eroare despre un camp pe
- care nu-l vede.
-- **#16 nu e in perimetrul S4d.** E legat de S2 (bucla de reincercare din `ofacturare.prg`), cu verdict
- separat in `s3_portare_antet.md`. S4d doar **confirma** ca antetul persistent ii inlatura mecanismul,
- cu conditia ca S2/S3 sa nu recreeze formularul la eroare.
-- ~~**De confirmat cu Marius (mic, de UX):** ce se intampla cand se sterge **ultimul** articol in
- valuta?~~ **INCHIS — decizia 47 (Marius, runda 13): simetrie.** Campul **se ascunde la loc** cand
- dispare ultimul articol in valuta, pe tiparul `lb_cursuri`. „Clipitul" la adaugari/stergeri repetate
- e acceptat ca pret al unei reguli unice: aparitia si disparitia urmeaza aceeasi conditie, nu doua.
-
-*Gata cand:* o factura in lei fara articole in valuta nu arata campul si se emite corect; aceeasi
-factura, dupa adaugarea unui articol cu pret in valuta, arata campul cu data implicita completata;
-factura in valuta se comporta ca azi; iar la `-20005` **campul redevine vizibil**, cu mesajul de azi
-(care deja numeste valuta si ziua). Pasii cu criterii verificabile sunt la sectiunea 7 a raportului; ce
-nu se poate testa headless, la sectiunea 9.
-*Depinde de:* S4. **#16 se urmareste in S2/S3, nu aici** — vezi M.
-
-#### S4e — Lista de preturi disponibila si pe factura din comanda
-Decizia 16, proiectata in J. Singurul gol real: pe contract merge deja, pe comanda nu, pentru ca
-`cursor_comanda` umple `crsarticole` doar cu articolele comenzii. Se adauga lista de preturi peste
-cursorul sursei, exact ca la copiere (`ofacturare.prg:454-473`), si optiunea „Cauta in lista de
-preturi…” intra in meniu pe toate sursele.
-**Si stergerea intra aici**, nu doar adaugarea: cazul cerut e „clientul mai vrea ceva sau vrea sa
-schimbe”, deci o linie adaugata trebuie sa poata fi si scoasa.
-**DECIS (decizia 29): stergerea unei linii venite din comanda ramane fara protectie.** Se sterge ca
-oricare alta; comanda ramane cu cantitatea nefacturata si va aparea **facturata partial**, ceea ce e
-si starea corecta. Nu se cere confirmare, nu se marcheaza „refuzat", nu se ajusteaza numararea
-acoperirii.
-Ramane un singur efect lateral de tratat, si e pe **adaugare**, nu pe stergere: capul de coloana
-„Cantitate comandata” si mesajul „A fost facturata intreaga cantitate comandata”
-(`ofacturare.vc2:15144-15150`) nu sunt adevarate pentru liniile libere adaugate langa cele din
-comanda.
-**PROIECTAT (runda 12) — `docs\cercetare\s4e_lista_preturi_pe_sursa.md`. Reteta din decizia 16 NU se
-generalizeaza literal** — si asta e rezultatul principal al proiectarii.
-
-- **`APPEND FROM` peste cursorul sursei ar strica doua lucruri pe comanda**, ambele tacut:
- **(1)** `id_c` e `ROWNUM` per executie Oracle, deci randurile din lista de preturi ar **coliziona** cu
- cele ale comenzii, iar `do_sterge` ajusteaza cantitatea `For id_c = poArticol.id_c` (`:14652-14655`) —
- ar atinge randul gresit; **(2)** `do_scrie_factura` face `Sum(cantitate)` peste `crsarticole` pe exact
- aceste tipuri (`:14332-14338`), iar in `cursor_preturi` **`cantitate` inseamna STOC**, nu „ramas de
- facturat" — suma care decide inchiderea comenzii ar fi poluata.
-- **De ce merge totusi pe contract azi**, verificat: lista de preturi si articolele contractului sunt
- **doua cursoare separate** de la bun inceput (`crsarticole` / `crsarticole1`), iar `cursor_contract`
- emite `id_c` ca **`rownum - 10000`** (`PACK_FACTURARE:2722` — confirmat direct pe export de sesiunea
- principala), adica autorii au tratat coliziunea de `id_c` ca risc real. In plus, tipurile de contract
- **nu au deloc** ramura cu `Sum(cantitate)` in `do_scrie_factura` — cad pe `Otherwise`. Nu e un tipar
- de copiat, e o coincidenta favorabila.
-- **Solutia curata, verificata fezabila pe cod: liniile libere NU intra deloc in `crsarticole`.** Se
- adauga direct in `crsfactura` prin `APPEND BLANK` + `combosql` — tipar **deja existent** in
- `frm_facturare_articole2.do_adauga` si pe linia de discount (`ofacturare.vc2:14531`). Atunci `id_c`
- ramane `0` implicit, si **`do_sterge` devine no-op prin constructie**, fara nicio modificare de cod.
-- **Se aplica identic pe AVIZE (tip 4), nu doar pe comanda** — `cursor_avize` are aceeasi semantica
- „ramas de facturat" si aceeasi ramura de `Sum`. Titlul povestii spune „din comanda", perimetrul real
- e „orice sursa cu registru".
-- **Avertisment care traverseaza in S4f:** pe returul ca document (`8,9,24`) riscul de coliziune `id_c`
- **ramane** (`do_sterge` ajusteaza cu semn opus, urmarind maximul returnabil), desi **fara** poluarea
- sumei de inchidere. Deci S4f foloseste acelasi mecanism, nu `APPEND FROM`.
-- **Validarea de cantitate pe liniile din comanda e satisfacuta prin constructie** — drumul
- `do_adauga_articol` → `do_verifica_articol` nu e atins, fiindca liniile libere nu modifica `crsarticole`.
-- **Gol real ramas, neacoperit de S4 si S4b:** nu exista mecanism de validare a cantitatii/stocului
- pentru un rand ales prin `combosql` — ambele rapoarte se opresc la maparea campurilor. `do_verifica_articol`
- nu se poate refolosi ca atare (cere un `poArticol` scatter-uit dintr-un cursor sursa incarcat).
- **DECIS — decizia 44 (Marius, runda 13): `poArticol` devine parametru explicit.** Se pastreaza un
- **singur loc de validare**: `do_verifica_articol` primeste `poArticol` ca **parametru**, in loc sa
- citeasca variabila `Private` populata de apelant. Schimbarea de contract a metodei e **aprobata ca
- atare**; consecinta obligatorie e actualizarea **tuturor apelantilor existenti**, inventariati inainte
- de prima editare. Aceeasi decizie acopera si `do_alege_stoc` / `frm_articol_gest_factura` din S4f (R7)
- — o singura solutie pentru amandoua, cum cerea raportul.
-
-*Gata cand:* pe o factura la comanda **si pe una din avize** se poate adauga un articol care nu e in
-sursa, cu pretul din lista de preturi, si se poate sterge o linie adaugata, fara ca liniile din sursa
-sa-si piarda validarea de cantitate **si fara ca suma care decide inchiderea automata sa se schimbe** —
-proba directa: aceeasi comanda, cu si fara linii libere adaugate, produce acelasi rezultat de inchidere.
-*Depinde de:* S2. **Interactioneaza cu S4 punctul 2** (registrul) si **avertizeaza S4f**.
-
-#### S4f — Returul in formularul unificat
-Decizia 17, proiectata in N. **Partea grea nu e ce credeam.** Factura de retur ca document (tipurile
-8, 9, 24) functioneaza deja cap-coada: alegere multipla a facturilor sursa, populare din
-`cursor_retur`, gestiune si pret de achizitie mostenite din liniile originale, stergere si retur
-partial. Munca e:
-
-1. **mutarea lui N.1 ca sursa in meniul de adaugare**, fara sa se atinga popularea — acelasi dialog,
- aceleasi filtre, acelasi `cursor_retur`;
-2. **ridicarea lui N.2 (`But_retur`) la nivel de document**, dupa modelul lui N.1, cu calea
- per-articol pastrata;
-3. **lista de preturi pe documentele de retur**, prin acelasi `APPEND FROM` ca la S4e.
-
-Nu se ating: excluderea returului dintr-un retur, filtrarea pe client si valuta, maximul returnabil
-calculat pe server, mostenirea gestiunii si a pretului de achizitie.
-**DECIS (decizia 22):** linia de retur care nu vine din nicio factura originala **e permisa**, ca pe
-orice alt document. Deci punctul 3 nu mai are conditie de intrare. Ce trebuie proiectat in schimb, pe
-liniile libere: gestiunea si pretul de achizitie **se aleg** (ca la N.2), nu se mostenesc, iar maximul
-returnabil calculat pe server **nu se aplica** — nu exista cantitate originala.
-**Afisarea provenientei — VERIFICAT, si raspunsul e „nu la nivel de linie".** Raport:
-`docs\cercetare\legatura_linie_retur.md`. Deci **S4f se livreaza fara coloana de provenienta pe linie**;
-nu se inventeaza. Ce s-a stabilit, ca sa nu se reia:
-
-- **Legatura se pierde chiar in cursorul care aduce datele.** `cursor_retur_document`
- (`ff_...:3949-4062`) foloseste `V_LISTAID` **doar ca filtru** (`WHERE A1.ID_VANZARE IN (...)`,
- `:4054-4055`); in lista de coloane a `SELECT`-ului extern (`:3965-4028`) **nu apar nici
- `ID_VANZARE`, nici `ID_VANZARE_DET`**. `crsarticole` nu are de unde sti din ce factura vine randul.
-- **`INSERT`-ul in `VANZARI_DETALII` nu are nicio coloana de sursa.**
-- **Exista insa o legatura la nivel de DOCUMENT, si nu era cunoscuta in plan: `VANZARI_CORESP`.**
- `scrie_corespondente_vanzari(3)` (`ff_...:14834-14836`, din `finalizeaza_factura`) scrie
- `(ID_VANZARE_FACT = documentul de retur, ID_VANZARE_AVIZ = fiecare factura sursa, TIP = 3)`
- (`:15481-15516`) — **cate un rand per factura sursa aleasa**, nu per linie. Numele coloanei e generic,
- reutilizat si pentru perechi aviz-factura (`TIP = 1/2`).
-- **Consecinta pentru UI:** cand s-a ales **o singura** factura sursa, se poate afisa corect „documentul
- asta de retur provine din factura Y" — la nivel de antet, nu de linie. Cand s-au ales **mai multe**
- (selectie multipla, suportata explicit de dialog), `VANZARI_CORESP` da **multimea** de facturi
- posibile, deci nici macar antetul nu poate arata o sursa unica. **De asezat in UI ca informatie de
- document, niciodata ca proprietate de linie.**
-- **N.2 (`But_retur`) nu scrie nicio legatura.** `listaid` (perechi `ID_ARTICOL:ID_VANZARE`) e folosit
- in `pack_facturare` (`ff_...:8142-8212`) exclusiv ca filtru pe `RUL`, ca sa calculeze cantitatea inca
- disponibila din acea vanzare. Sursa nu ramane atribut al liniei noi.
-**PROIECTAT (runda 12) — `docs\cercetare\s4f_retur_formular_unificat.md`**, cu **trei corectii** fata de
-textul de mai sus:
-
-- **Punctul 1 se restrange.** Alegerea facturilor sursa **nu se muta** in bara de butoane — ramane la
- antet / in sectiunea pliata (confirmat impotriva `s4b_bara_butoane_meniu.md` §9.3 si a tabelului de
- meniu de acolo). Ce se muta in meniul de adaugare e doar **„adauga tot din facturile alese"** si
- **„alege liniile"**.
-- **Un risc concret, netratat nicaieri pana acum (R1):** `frm_articol_gest_factura`
- (`ofacturare.vc2:4094-4103`) face, sub `If Thisform.lRetur`, `poArticol.pretftva = pretv` — adica
- **suprascrie pretul de vanzare cu pretul din stoc pe ORICE linie de retur** (verificat direct de
- sesiunea principala). Corect pentru liniile **mostenite** dintr-o factura sursa; **gresit pentru
- liniile libere** permise de decizia 22, care trebuie sa pastreze pretul din lista de preturi.
- Raportul propune fixul.
-- **Distinctia „linie libera" vs. „linie mostenita" nu cere camp nou: `crsfactura.id_c = 0`.** Oracle nu
- produce niciodata `id_c = 0` din `ROWNUM`, deci valoarea implicita e ea insasi semnalul. Vine din
- mecanismul impus de S4e: liniile libere intra direct in `crsfactura` (`APPEND BLANK` + `combosql`),
- **nu** in `crsarticole` — asa ca ajustarea din `do_sterge` (care pe retur urmareste maximul returnabil)
- devine **no-op prin constructie**. Acelasi semnal dezactiveaza si suprascrierea de pret de mai sus.
-- **Gol nou (R7), pe care S4e nu-l are** (comanda si avizele n-au dialog de gestiune): azi se intra in
- `do_alege_stoc` / `frm_articol_gest_factura` **doar** dintr-un `poArticol` scatter-uit din
- `crsarticole`. O linie libera din `crsfactura` nu are asa ceva, iar decizia 22 cere ca gestiunea **sa
- se aleaga**. Deci trebuie un **punct de intrare nou** in dialog. **Se unifica cu golul echivalent din
- S4e** (validarea cantitatii, `do_verifica_articol`): e aceeasi problema structurala — dialogurile sunt
- cuplate de `crsarticole` —, deci merita **o singura solutie**, nu doua.
- **INCHIS prin decizia 44** (runda 13): `poArticol` devine **parametru explicit** si aici, nu variabila
- `Private` populata de apelant — aceeasi solutie ca in S4e, cum cerea raportul.
-- **R4 e inchis** (verificare independenta): `scrie_corespondente_vanzari(3)` e gatata pe `ntip IN (8,9)`,
- nu pe `listaid`.
-- **`VANZARI_CORESP` nu e afectata de liniile libere** — se scrie din `poDate.listaid`, fixat la antet.
- **De confirmat (R4):** pentru `But_retur` ridicat la nivel de document, raspunsul pare a fi „fara
- corespondenta persistata", pentru ca scrierea e gatata pe `ntip IN (8,9)`, nu pe `listaid`.
-
-*Gata cand:* un document de retur deschis in formularul unificat aduce liniile facturilor alese cu
-aceleasi valori ca azi — inclusiv gestiunea si pretul de achizitie —, permite stergere si cantitate
-partiala, iar pe o factura normala se poate face retur alegand facturile o singura data. **In plus: o
-linie libera pe un document de retur isi pastreaza pretul din lista de preturi**, adica nu trece prin
-suprascrierea de la `:4094-4103`. Pasii cu criterii verificabile sunt la sectiunea 9 a raportului; ce nu
-se poate testa headless, la sectiunea 11; riscurile R1-R6, la sectiunea 12.
-*Depinde de:* S2, S4e.
-
-#### S4g — Adaugarea de articole la modificarea oricarui document, inclusiv auto
-Decizia 18, proiectata in O si O-bis. **Nu se porneste de la zero:** „Alte servicii” din ROAAUTO
-face deja jumatate — articole reale langa linii sintetice, cu pret tastat, fara gestiune — doar ca
-traieste in formularul de emitere si moare odata cu el. Se generalizeaza in formularul unificat, ca
-a doua sursa din meniu („Alege din nomenclator…”), disponibila **si la modificare**, pe orice tip de
-document, nu doar pe cele auto.
-**Ordinea in care se lucreaza**, ca sa nu se blocheze tot: intai pe documentele ROAFACTURARE, unde
-scrierea e a noastra; abia apoi pe `tip = -12`.
-**Decizia 20 se aplica aici:** din nomenclator se ofera **si articole gestionabile, si
-negestionabile** — nu se copiaza filtrul `in_stoc = 0` al lui ROAAUTO.
-**Blocantul real e contul de venit, si el priveste doar ramura „Alege din nomenclator…”** (J-bis,
-J-ter). Contul de venit vine din `NOTE_CONTABILE.SCC` **prin politica de pret**; un articol fara
-`ID_POL` nu ajunge la cont gol, ci **la eroare** — `contabilizeaza_articol` ridica `FACT-024` si
-opreste tranzactia. Pe ramura „Cauta in lista de preturi…” nu se schimba nimic: acolo politica exista.
-**Premisa de la care pornea povestea asta a cazut:** „Alte servicii” din ROAAUTO **nu face deja
-jumatate** din treaba — acele linii ocolesc complet `contabilizeaza_articol`, printr-o cale de
-facturare paralela care nu genereaza nota de venit. Nu e un mecanism de generalizat, e o exceptie.
-**DECIS (decizia 27, care inlocuieste 24):** contul de venit se **deriva**, nu se ia prin politica —
-din `CORESP_CONT_VENCHELT` pentru articolele gestionabile (pe contul de gestiune al liniei), din
-`NOM_ARTICOLE.CONT` daca e 6xx / 7xx pentru cele negestionabile, altfel **704**. **Derivarea se face
-in VFP**, dar **transportul s-a schimbat la decizia 34**: contul calculat se trimite **direct, ca
-parametru nou al lui `contabilizeaza_articol`**. Ocolul prin `id_pol` cu nota potrivita — politica
-tehnica, interogarea inversa pe `SCC`, `pack_preturi.adauga_politica_pret_art` — e **abandonat**;
-J-quater punctul 3 se citeste doar ca trasabilitate. **Decizia 35** adauga ca acelasi drum serveste si
-editarea prin regenerare, deci nu se proiecteaza aici o a doua ruta de contare.
-~~**De decis in aceasta poveste, nu inainte:** ce se intampla cand linia are **si** politica, **si**
-cont trimis din VFP — cine castiga.~~ **PROIECTAT (runda 13) —
-`docs\cercetare\s4g_adaugare_articole_modificare.md`.** Intrebarile despre politica tehnica in ecranul
-de cautare a politicilor **au disparut** odata cu reteta.
-
-**Raspunsul: niciuna dintre cele trei variante pure — parametrul castiga, dar combinatia ambigua e
-oprita explicit, nu rezolvata tacit.**
-- **Combinatia nu poate aparea in fluxul normal, si asta e dovedit, nu presupus.** `crsfactura.id_pol`
- e `N(20) Null` (`COMUN\programe\ofacturare_comun.prg`, `creeaza_facturacrs` — **verificat direct**),
- deci la `APPEND BLANK` ramane `.NULL.`, si ajunge la Oracle ca literalul `NULL`
- (`ofacturare.vc2:14072`). Cursorul de cautare din nomenclator **n-are deloc coloana `id_pol`**, deci
- nu exista punct in care o linie „din nomenclator" sa-l poata popula.
-- **Singurul scenariu real de ambiguitate e regenerarea** (decizia 35): daca derivarea contului ar rula
- **necondiționat** pe toate liniile documentului, si nu doar pe cele fara `id_pol`, o linie cu politica
- reala ar primi si cont derivat. **E un risc de implementare VFP, nu Oracle** — dar proiectarea Oracle
- nu trebuie sa-l faca invizibil.
-- **Deci: `cont_venit IS NOT NULL` intra pe ramura noua; daca in acel moment `id_pol` e si el populat,
- se ridica eroare** (cod nou, distinct de `FACT-024`, care ramane pentru cazul „nici politica, nici
- cont"). Variantele „politica castiga" si „fallback la `NO_DATA_FOUND`" au fost respinse motivat:
- prima defineste castigatorul pe **prezenta** campului, nu pe rezolvarea lui, si ar reintroduce
- `FACT-024` acolo unde VFP a oferit deja o solutie; a doua e semantic cea mai curata, dar cere
- **restructurarea interna** a functiei (un flag propagat din `EXCEPTION` pana la punctul de decizie),
- fata de un singur `IF` la intrarea in ramura deja proiectata. **Ambele ascund o eroare de date in loc
- s-o semnaleze.**
-- **Regresie zero pe apelantii de azi**, prin constructie: cand `cont_venit` e `NULL` — adica toti
- apelantii existenti, care nu cunosc parametrul —, executia intra direct pe `ELSE`, garda nu se
- evalueaza niciodata, comportamentul e identic cu cel de azi.
-- **De ales de Marius:** numarul concret al codului de eroare nou (`FACT-0xx`).
-Separat, contul de **gestiune** e rezolvat ca regula (decizia 21): fallback, nu `NULL`, nu refuz.
-**`pack_auto` nu mai e blocant** — `PACK_AUTO` nu citeste `VANZARI` / `VANZARI_DETALII` deloc (O,
-intrebarea 1). Desincronizarea de afisare e **acceptata** (decizia 28); conditia e MANOPERA si
-MATERIALE conform devizului.
-**Blocantul netehnic a cazut si el:** gridul read-only din `frm_modific2024` e al lui #6, dar #13
-incepe dupa ce #6 se termina (decizia 30).
-**Restul proiectarii S4g, pe scurt** (detaliile in raport):
-- **Suprafata pe Oracle**: `contabilizeaza_articol` primeste contul prin `VANZARI_DETALII_TEMP%ROWTYPE`
- (`cont_venit`), deci semnatura functiei ramane aceeasi — se extinde **tipul de rand**. Consecinta de
- livrare: **DB inainte de EXE**.
-- **Derivarea in VFP** urmeaza fix decizia 27: `CORESP_CONT_VENCHELT` pentru gestionabile (pe contul de
- gestiune al liniei), `NOM_ARTICOLE.CONT` daca e 6xx/7xx pentru negestionabile, altfel **704**. Ruleaza
- **doar pe liniile fara `id_pol`** — vezi garda de mai sus; aici se leaga cele doua.
-- **Fluxul in formular** refoloseste exact mecanismul lui S4e: linia „din nomenclator" intra prin
- `APPEND BLANK` + `combosql` **direct in `crsfactura`**, niciodata in `crsarticole`.
-- **Ramane deschis, mostenit din S4e:** validarea de cantitate/stoc pentru linia libera — se rezolva
- prin decizia 44 (`poArticol` ca parametru explicit), aceeasi solutie pe ambele surse.
-- **De re-rulat inainte de implementare, nu de presupus incheiat:** cautarea apelantilor lui
- `adauga_articol_factura` in restul suitei (ROAGEST, ROAAUTO, ROAACNPRO, ROAIMOB). Risc asteptat zero
- — folosesc proceduri separate sau alt pachet —, dar cautarea **nu s-a terminat in nicio runda**.
-- **Trei hardcodari raman de confirmat de Marius, nu de presupus inofensive:** `CU_TVA = 1` (are efect
- masurat prin `nproc_tva_max`, pe linie scutita + discount global), numele cheii de optiune de firma
- pentru `SCD` (decizia 36) si domeniul ei `PROGRAME`, si trasabilitatea `CONT_VENIT` pe
- `VANZARI_DETALII` (optionala pentru functionare, dar fara ea coloana nu se pastreaza dupa fapt).
-
-**Nota de executie (decizia 60):** pe documentele de tip **48/49** (custodie), „Alege din
-nomenclator…" ramane restrans la articole `IN_STOC = 0`, la fel ca ramura „Cauta in lista de
-preturi…" (S4) — decizia 20 (si articole gestionabile, si negestionabile) **nu se aplica** pe
-tipurile 48/49. Altfel se rupe invariantul pe care se sprijina siguranta regenerarii la editarea
-custodiei (decizia 60, `docs\cercetare\custodie_48_49_stergere_reemitere.md`).
-
-*Gata cand:* pe un document deja emis se poate adauga o linie noua, din lista de preturi sau din
-nomenclator, si documentul se salveaza consistent — pe fluxurile ROAFACTURARE, cu partea auto
-livrata separat, dupa (1). Pe un document 48/49, „Alege din nomenclator…" nu ofera si nu permite
-adaugarea unui articol cu `IN_STOC <> 0`.
-*Depinde de:* S4e, si de deciziile de mai sus. **Nu blocheaza etapa I.**
-
-#### S5 — Acoperirea tuturor tipurilor
-`frm_facturare_articole.Init` are 20 de ramuri pe `poDate.tip` (`:15107-15250`) care schimba titlul,
-capul coloanei de cantitate, mesajul de stoc, vizibilitatea discountului, prezenta seriei. Toate
-trebuie sa existe si in formularul unificat. Tipurile speciale raman pe calea lor:
-`tip = 27` (`frm_avizare_lucrare`), `tip = 30` (aviz din NIR, formular nevizibil).
-**PROIECTAT (runda 12) — `docs\cercetare\s5_acoperire_tipuri.md`. Povestea e mult mai mare decat
-„porteaza cele 20 de ramuri", si motivul e ca baza de pornire aleasa nu are aproape nimic de portat.**
-
-- **`Do Case`-ul de azi acopera 21 de valori de `tip`** (in 14 ramuri). **Patru tipuri reale,
- reachable prin `factureaza()`, nu intra in niciun `Case`: `45` (factura restaurant), `48` / `49`
- (custodie), `52` (contract, factura fiscala valuta)** — pierd titlu, cap de coloana, mesaj de stoc,
- vizibilitatea discountului si eliminarea coloanei `cSerie`. **Nu doar `52`**, cum semnalase S4b.
- Rutarea cursorului le recunoaste (`ofacturare.prg:271-282`); doar `Init` nu le-a „prins" niciodata.
- **Nota de executie (decizia 60):** randul de configurare pentru `48`/`49` trebuie sa pastreze
- restrictia la articole `IN_STOC = 0` mostenita de la sursa lor de azi (`cursor_articole_k`,
- `PACK:3595-3701`, `:3695`) — vezi notele echivalente la S4 si S4g; e conditia de siguranta pentru
- regenerarea la editarea custodiei (decizia 60,
- `docs\cercetare\custodie_48_49_stergere_reemitere.md`).
-- **Cinci tipuri (`43,44,46,50,51`) nu ajung deloc la acest formular** — zero potriviri in tot arborele
- `D:\ROA`. `50` e marcat „in lucru" in sursa. Se declara explicit ramase in afara.
-- **Descoperirea care schimba estimarea: prototipul nu e o versiune partiala a `Do Case`-ului — e
- aproape gol.** `frm_facturare_articole2.Init` (`:18988-19080`) alege pe tip **doar** cuvantul
- „factura"/„aviz", pe o lista mai scurta (lipseste `24`). Nu seteaza titlu (nu exista
- `lb_titlu_alb_b121` in tot prototipul), nu schimba capul coloanei, nu schimba mesajul de stoc, nu
- ascunde discountul, si **n-are deloc conceptul de coloana `cSerie`**. Daca formularul unificat porneste
- de la prototip — cum decide S1 —, **toata diferentierea pe tip se reconstruieste de la zero**, nu se
- completeaza. Asta e cel mai mare cost ascuns al etapei I descoperit pana acum.
-- **Rutarea cursorului diverge pe TREI tipuri, nu unul:** pe prototip, ramura de contract e
- `Inlist(tnTip, 2, 26, 6)` (`ofacturare.prg:762`) fata de `Inlist(tnTip, 2, 26, 6, 52)` pe standard
- (`:283`) — **verificat direct de sesiunea principala** —, iar ramura de retur omite `24`. Pe aceste
- tipuri, prin prototip, `lcSqlCursor` ar ramane **nedefinit**: eroare, nu doar comportament diferit.
-- **Punctul lasat deschis de S4 punctul 2 se inchide aici:** tipurile **`26` si `52` n-au niciun
- bookkeeping** `crsarticole` — nici Rol A, nici Rol B. Excluderea e totala, pe `Do Case` exhaustiv fara
- ramura implicita, deci e „dovedit absent", nu „neconfirmat".
-- **`30` nu e un formular separat**, cum spunea planul: e **acelasi `frm_facturare_articole`**, trecut
- prin acelasi `Init`, dar niciodata aratat (`ofacturare.prg:444-453` — calculeaza totalurile, apasa
- programatic `but_termin1.Click()`, apoi `Release()`, fara `Show()`). Deci **e afectat de golurile din
- `Do Case`** ca oricare alt tip; doar ca defectele nu se vad pe ecran. `27` chiar ramane pe calea lui.
-- **Alegerea de proiectare centrala, recomandata: tabel de configurare per tip**, un rand per `tip`, cu
- exact proprietatile pe care le seteaza azi `Do Case`-ul (titlu, cap cantitate, mesaj stoc, discount
- vizibil, are serie, tip doc, butoane, grup-sursa pentru meniul S4b). Motivul nu e estetic: **un
- `Do Case` fara `Otherwise` nu semnaleaza niciodata un tip lipsa** — exact mecanismul care a lasat
- patru tipuri pierdute ani la rand. Cu tabel, un tip necunoscut devine **eroare la deschidere**, iar
- completitudinea se verifica **mecanic**, cu un `SELECT` fata de `tipuri_documente_facturare.md`, fara
- sa porneasca formularul. Variantele „completeaza `Do Case`-ul" si „metoda per grup" au fost respinse
- motivat: amandoua raman implicite, deci nu adauga detectie.
-- **DECIS — decizia 48 (Marius, runda 13): tabelul e un CURSOR GENERAT IN COD la pornire**, nu `DBF`
- static (recomandarea raportului) si nu tabela pe Oracle. Ambele au fost puse pe masa cu argumentele
- lor si respinse: `DBF`-ul adauga un fisier de intretinut, de livrat la fiecare update si de tinut
- sincron intre produsele ROA; tabela Oracle ar cere script de migrare si o citire in plus la
- deschiderea formularului. **Ce NU se pierde prin alegerea asta:** detectia ramane intacta — tip
- necunoscut = **eroare la deschidere**, exact castigul pentru care exista propunerea —, iar proba
- mecanica de completitudine ramane posibila, doar ca ruleaza **din aplicatie**, nu cu un `SELECT`
- din afara. **Ce se accepta:** orice tip nou de document cere **recompilare si versiune noua de exe**,
- ca azi. Forma concreta: un `.prg` cu `CREATE CURSOR` + `INSERT`-uri, un rand per tip, incarcat o
- singura data si citit de `Init` prin `SEEK` pe `tip`.
-
-*Gata cand:* fiecare tip din `COMUN\docs\tipuri_documente_facturare.md` fie e acoperit, fie e
-declarat explicit ramas pe calea veche — **verificat prin proba mecanica de la sectiunea 8 a raportului**,
-nu prin citire. Include cele patru tipuri lipsa azi (`45,48,49,52`) si alinierea rutarii de cursor intre
-standard si prototip. Pe `48`/`49`, in plus: restrictia `IN_STOC = 0` mostenita ramane activa (decizia
-60) — nu se poate adauga un articol gestionabil.
-*Depinde de:* S4.
-
-#### S5b — Proforma si copierea pe formularul unificat
-Deciziile 10 si 11. Amandoua vin **aproape gratuit**, pentru ca folosesc deja acest drum: proforma e
-o valoare in combo-ul de tip document, copierea e `factureaza(tip, toFactura)` cu antetul
-precompletat. De facut, concret:
-- combo-ul `Ct_clb_fdoc` ramane in antetul unificat, cu realocarea de serie si numar la comutare;
-- garzile `eProforma = 0` de pe notele contabile si atasamente raman intacte, iar raportul propriu de
- proforma continua sa fie ales;
-- copierea deschide formularul in starea „document nou”, cu antetul editabil (comportamentul de azi);
-- **degradarea de tip din `do_copiaza` ramane pentru copiere si nu se aplica la regenerare** (D) —
- sunt doua moduri distincte ale aceluiasi formular, nu acelasi comportament.
-*Gata cand:* o proforma emisa din formularul unificat nu produce nota contabila si se listeaza pe
-raportul ei; o copie produce un document nou cu numar nou si acelasi continut.
-**VERIFICAT (runda 9) — `docs\cercetare\s5b_proforma_descarcare_gestiune.md`. Verificarea 4 e inchisa.**
-**NU, gestiunea nu se descarca pe proforma** — pentru niciun articol, indiferent daca e gestionabil in
-nomenclator. Si nu e un efect colateral al ascunderii stocului, e **prin design**: VFP marcheaza toate
-liniile proformei negestionabile inainte de compunerea documentului, ceea ce le trimite cu sentinela
-`id_gestiune = -1000`, iar pe Oracle `contabilizeaza_articol` sare apelul catre `descarca_gestiune`
-exact pe acest sentinel. Intentia e explicita in changelog (12.03.2021 / 2.7.x): *„Articolele din
-proforma sunt marcate 'negestionabile', astfel incat nu mai este necesara existenta articolelor in stoc
-pentru a genera proforma."* — deci cerinta a fost „proforma trebuie sa mearga si fara stoc", nu „nu arata
-plafonul". **Se corecteaza presupunerea din plan** ca zeroizarea `gestionabil` ar fi doar cosmetica.
-Consecinta pentru S5b: sentinela `-1000` e contractul care trebuie pastrat — vezi sectiunile 6 si 7 ale
-raportului pentru constrangerile de proiectare si ce lipseste la copiere.
-
-**PROIECTAT (runda 12) — `docs\cercetare\s5b_proiectare_proforma_copiere.md`. „Aproape gratuit" nu mai
-tine: proiectarea a scos la iveala un risc de date care nu era semnalat nicaieri.**
-
-- **Mecanismul real care tine proforma curata nu e sentinela, ci routing-ul.** In `do_scrie_factura`
- (`ofacturare.vc2:14282-14300`), `eProforma = 1` alege `scrie_proforma`, care **nu cheama niciodata**
- `contabilizeaza_articol` — comentariul din cod o spune direct: *„salveaza doar in vanzari, nu si in
- contabilitate"* (verificat de sesiunea principala). Sentinela `-1000` e al doilea strat, nu primul.
-- **RISCUL CENTRAL — „drumul invers", nesemnalat pana acum si cu consecinta pe date.** Operatorul
- adauga linii cu documentul pe **Proforma** (deci marcate `gestionabil = 0` / `id_gestiune = -1000`),
- apoi comuta combo-ul inapoi pe **Factura** inainte de „Termina". Atunci routing-ul alege
- `scrie_factura2`, care **chiar** cheama `contabilizeaza_articol` — dar acesta sare `descarca_gestiune`
- exact pe sentinela `-1000` (`PACK:7472-7476`). Rezultatul: **o factura reala iese cu stocul
- nedescarcat, silentios** — `-1000` e o valoare valida, nu ridica nicio exceptie. **Azi nu exista
- nicio plasa pentru acest caz**, si nici nu putea exista: combo-ul traieste in dialogul separat
- `frm_date_factura`, inchis **inainte** sa existe vreo linie. Riscul se naste **din unificare**.
-- **De aici si de ce marcarea negestionabila nu mai poate fi un singur `UPDATE` de masa:** in
- formularul unificat trebuie extrasa intr-o metoda refolosita din **trei** puncte — la incarcare, la
- adaugarea unei linii, si la comutarea tipului cu linii deja prezente.
-- **`id_c` la copiere: SIGUR, cu dovada.** `do_copiaza` degradeaza tipul spre grupul-tinta
- **`{1,5,7,10,22,23}`**, care nu intra niciodata in ramurile Rol A din `do_scrie_factura` / `do_sterge`.
- Coliziunea tehnica exista in date, dar **n-are efect observabil**. (Intrebarea venea din corectia lui
- S4e — vezi acolo.)
- > **CORECTIE (runda 13, verificata direct pe cod).** Grupul-tinta scris pana acum in plan
- > (`{1,5,10,22}`) era **gresit**, si la fel era si `{1,5,7,10}` din raportul S5c. Setul real e cel de
- > mai sus, citit din primul `CASE` al lui `frm_facturi.do_copiaza`
- > (`COMUN\clase\ofacturare_comun.vc2:3693-3694`), care lasa neatinse exact `T1,T5,T7,T10,T22,T23`.
- > Concluzia „copierea e sigura" **nu se schimba** — `7` si `23` nu au bookkeeping Rol A —, dar cifrele
- > se corecteaza peste tot unde apar. Aceeasi corectie se aplica lui
- > `s5b_proiectare_proforma_copiere.md` §2.1 / §7.
-- **DEFECT PREEXISTENT, gasit in trecere la verificarea de mai sus — de raportat, NU de reparat acum.**
- In `frm_facturi.do_copiaza`, ramura de avize scrie `lnTip = T22`
- (`COMUN\clase\ofacturare_comun.vc2:3703`) in loc de `loFactura.tip = T22` — **singura ramura din tot
- `Do Case`-ul care nu atribuie in obiect**; toate celelalte cinci scriu `loFactura.tip`. Consecinta:
- la copierea unui aviz (`21,24,26,30,-7,-9,-10,-13,28,29,42`) **degradarea nu se produce**, iar
- `copiere_factura` cheama `factureaza(toFactura.Tip, ...)`
- (`COMUN\programe\oproceduri_facturare.prg:150-152`) cu tipul **original** — deci copia unui „aviz pe
- baza de comanda" reintra pe ruta de comanda, nu pe cea de lista de preturi. **Verificat ca `factureaza`
- nu citeste un `lnTip` privat** (`ofacturare.prg:101` declara `lnTipTemp`, nu `lnTip`), deci
- atribuirea chiar se pierde; in plus `lnTip` e nedeclarat in metoda, deci poate suprascrie un `lnTip`
- al apelantului. **Fisierul e in perimetrul interzis (#6) — se raporteaza, nu se atinge.**
-
-**VERIFICAT (runda 12, la cererea lui Marius) — `docs\cercetare\verif_proforma_alegere_stoc.md`.
-Pe proforma NU se alege stoc azi, si asta e deliberat.**
-
-- **Un singur mecanism activ, si e in VFP, la incarcare:** `ofacturare.prg:333-336` face
- `UPDATE (lcCursor) SET gestionabil = 0` cand `eProforma = 1`, **inainte** sa se deschida gridul.
- Comentariul din cod spune intentia direct: *„Daca este o proforma, consider toate articolele
- negestionabile, **pentru a nu mai alege din stoc**"* (12.03.2021). Deci `Do Case`-ul de la
- `ofacturare.vc2:13803` vede mereu `gestionabil = 0` → **`do_alege_stoc` nu ruleaza niciodata**.
- Valabil pe **toate** cursoarele de creare directa a unei proforme; **niciunul** n-are parametru
- `V_PROFORMA` (verificat pe ~9 proceduri `cursor_` din pachet).
-- **Mecanismul Oracle exista, dar e mort in fluxul curent:** `cursor_retur_document` (`PACK:3993-4000`)
- are `CASE V_PROFORMA = 1 THEN 0`, insa se cheama doar la **copiere**, unde `V_PROFORMA` trimis e
- `eProforma` al documentului **nou** — mereu `0`. **Nu e o contradictie intre rapoarte**: sunt doua
- mecanisme reale, doar unul activ.
-- **`pret_achizitie` depinde de sursa:** pe calea principala (lista de preturi) ramane `0` —
- `cursor_preturi` nici nu-l selecteaza. Pe surse care carata un document existent (avize, copiere)
- vine real din `VANZARI_DETALII.PRET_ACHIZITIE`.
-- **Daca liniile ar pastra gestiunea reala pana la salvare, nu s-ar strica nimic pe contabilizare sau
- stoc:** `adauga_articol_factura` se cheama oricum si pentru proforma, dar `scrie_proforma` **nu**
- cheama `contabilizeaza_articol`, deci `descarca_gestiune` tot n-ar rula; iar **`do_alege_stoc` nu
- rezerva stoc** (doar `SELECT` + scadere locala in memorie, zero scriere Oracle). Singurul loc unde
- s-ar vedea o diferenta e la **relistare** (`crsDetaliiListare` / `fact_vfacturi2` citesc
- `id_gestiune` fara filtru pe `eproforma`) — **neconfirmat** daca vreun raport chiar il tipareste.
-
-**Consecinta care schimba forma deciziei: cele doua sensuri nu sunt simetrice.**
-- **FACTURA → PROFORMA cu linii deja adaugate:** liniile au trecut deja prin `do_alege_stoc`, deci au
- gestiune reala si pret de achizitie corect. **E sigur, si sentinela se poate aplica abia la salvare**
- — exact varianta ceruta de Marius. **Fara atentionare.**
-- **PROFORMA → FACTURA cu linii deja adaugate:** liniile au fost adaugate **fara** alegere de stoc
- (`gestionabil` fortat `0`), deci **nu au gestiune**. Aici e riscul „drumului invers".
-- **A forta alegerea stocului si pe proforma NU e o optiune** — ar regresa cerinta din 12.03.2021
- (*„nu mai este necesara existenta articolelor in stoc pentru a genera proforma"*): un articol fara
- stoc n-ar mai putea intra pe proforma, pentru ca `do_alege_stoc` ar cere un lot inexistent.
-
-### Decizia 43 (Marius, runda 12) — proforma NU alege stoc, si factura se face DIN proforma
-
-**Pe proforma nu se alege stoc, si asta e cerinta, nu efect colateral.** Motivul, in cuvintele lui
-Marius: *„sa dau o proforma chiar si in absenta stocului, pentru ca ma intereseaza doar pretul de
-vanzare, nu si cel de achizitie din stoc"*. Deci:
-- **Varianta (b) — realegerea gestiunii linie cu linie la comutare — e RESPINSA.** Nu se mai
- reargumenteaza.
-- **Comutarea PROFORMA → FACTURA cu linii prezente se blocheaza**, cu mesaj explicit. Comportamentul de
- azi (`gestionabil = 0` fortat la incarcare, `ofacturare.prg:333-336`) se **pastreaza**, nu se rafineaza.
-- **Sensul FACTURA → PROFORMA ramane liber**, fara atentionare, cu sentinela aplicata **la salvare** —
- liniile au deja gestiune reala, deci nu se pierde nimic.
-
-**Cerinta noua: „ulterior o sa vreau si o factura din proforma".** Nu prin comutarea tipului pe acelasi
-document, ci ca **document nou**, generat din proforma. **Mecanismul pare sa existe deja pe calea de
-copiere** — `cursor_retur_document` reface gestionabilitatea reala cand `V_COPIERE = 1`
-(`GESTIONABIL = B.IN_STOC`, `PACK:3993-4000`), deci liniile venite dintr-o proforma **redevin
-gestionabile**, trec prin `do_alege_stoc` la adaugare, primesc `id_gestiune` real si descarca gestiune
-normal (`docs\cercetare\s5b_proiectare_proforma_copiere.md` §2.6). **De verificat inainte de a te baza
-pe asta**, pentru ca §2.6 descria copierea in general, nu cazul „sursa e o proforma":
-1. poate fi azi o **proforma** aleasa ca sursa de copiere, sau e exclusa undeva?
-2. `do_copiaza` degradeaza tipul spre `{1,5,10,22}` — ce tip rezulta dintr-o proforma si e cel dorit?
-3. ~~se pastreaza legatura proforma → factura?~~ **RASPUNS (Marius, runda 12): DA — „ar fi bine sa aiba
- urma sursei, la fel ca factura din aviz".** Deci trasabilitatea **e ceruta**, si tiparul de urmat e
- cel deja existent pentru aviz → factura: `scrie_corespondente_vanzari(1)`, chemata din
- `finalizeaza_factura`, care scrie in **`VANZARI_CORESP`** perechea
- `(ID_VANZARE_FACT = factura, ID_VANZARE_AVIZ = documentul sursa, TIP = 1)`. Numele coloanei e generic,
- deja reutilizat pentru mai multe feluri de perechi (`TIP = 1/2` aviz-factura, `TIP = 3` retur), deci
- **structura nu se schimba — se adauga o valoare noua de `TIP`** pentru proforma → factura.
- **De proiectat, nu de presupus:** ce valoare de `TIP` se aloca; de unde stie fluxul de copiere ca
- sursa a fost o proforma (azi `do_copiaza` degradeaza tipul, deci informatia s-ar putea pierde
- **inainte** de scriere — vezi punctul 2); si daca `marcheaza_facturat` / `FACTURAT` trebuie sau nu
- atinse (pe aviz sunt, pe proforma probabil **nu**, pentru ca proforma nu e un document de livrare —
- **de confirmat, e exact genul de detaliu care se copiaza gresit din tiparul avizului**).
-~~**Aceasta e prima sarcina de proiectare a rundei 13.**~~ **LIVRATA — vezi S5c mai jos.**
-
-*Depinde de:* S5.
-
-#### S5c — Factura din proforma (decizia 43, cerinta noua)
-**PROIECTAT (runda 13) — `docs\cercetare\s5c_factura_din_proforma.md`. Toate cele trei intrebari si
-ambele capcane au raspuns cu dovada. Vestea buna: mecanismul de baza chiar exista, si nu se atinge.**
-
-- **(a) O proforma poate fi azi aleasa ca sursa de copiere, fara nicio excludere.** `IsCopy` returneaza
- **necondiționat `.T.`** (`COMUN\clase\ofacturare_comun.vc2:4969`, cu comentariul explicit *„POT SA
- COPIEZ ORICE, TRATEZ TIPURILE IN DO_COPIAZA"*; filtrul vechi pe tip e comentat dedesubt, la `:4971`) —
- **verificat direct**. Nici vizibilitatea butonului, nici filtrul de grid „Facturi&Avize / Proforme" nu
- se uita la `eproforma`. Deci nu e nimic de deblocat.
-- **(b) Tipul rezultat e corect, fara schimbare.** Copierea produce un document real
- (`nIdTipDoc = 5`, `eproforma = 0`) — factura fiscala, exact ce trebuie. Degradarea lasa neatins
- grupul-tinta **`{1,5,7,10,22,23}`** (vezi corectia de cifre de mai sus).
-- **(c) `TIP = 4` e liber in `VANZARI_CORESP`** si se aloca pentru „factura din proforma". Confirmat
- **cod + date** pe schema vie: tabela are un **singur scriitor in toata baza**
- (`pack_facturare.scrie_corespondente_vanzari`), iar azi se folosesc doar `1/2/3`. **Structura nu se
- schimba.**
-- **Capcana (i) — confirmata, si e miezul poveștii.** `id_vanzare` al proformei **supravietuieste**
- copierii (prin `poDate.listaid`), dar faptul ca **sursa era o proforma se pierde**:
- `completeaza_setari_document` copiaza `.listaid`, dar **nu** si `eproforma`
- (`COMUN\programe\ofacturare_comun.prg:387` — **verificat direct: `eproforma` nu apare nicaieri in tot
- fisierul**). De aceea legatura **nu se poate agata de `CASE`-ul din `finalizeaza_factura`**, care e
- cheiat pe `ntip` — `ntip` nu poarta distinctia. Solutia: un semnal nou, client-side
- (`poDate.lProformaSursa`), capturat exact acolo unde informatia mai exista, plus un **apel Oracle
- explicit separat** care reutilizeaza `scrie_corespondente_vanzari(4)` **neschimbata**. Zero cod PL/SQL
- nou pe calea recomandata.
-- **Capcana (ii) — INFIRMATA presupunerea comoda, cu patru argumente: `marcheaza_facturat` NU se cheama
- pe proforma.** Proforma n-are `VANZARI_CANTITATI`, n-are ramura de reversare la stergere in
- `sterge_factura`, nimic nu filtreaza dupa `FACTURAT` pe proforme, si oricum calea aleasa e in afara
- `CASE`-ului care il cupleaza azi. Era exact detaliul care se copia gresit din tiparul avizului.
-
-**Ce NU se schimba:** `IsCopy`, vizibilitatea butonului de copiere, filtrul de grid, degradarea de tip
-din `do_copiaza`, `cursor_retur_document` (`GESTIONABIL = B.IN_STOC`), si `scrie_corespondente_vanzari`
-insasi.
-
-**INCHISE, nu de reintrebat (marcaj pus in runda 17).** Cele cinci puncte de mai jos au primit raspuns: punctul 1 (`TIP = 4`) prin **decizia 51**, restul in bloc prin **decizia 56** („da la toate"). Lista ramane ca **inventar al recomandarilor acceptate**, ca sa se stie ce s-a decis si de ce — nu ca intrebari:
-1. **`TIP = 4`** — liber azi, dar alocarea e **ireversibila in date** odata intrata in productie. De
- confirmat explicit, nu tacit.
-2. **Apel pe starea de sesiune a pachetului (`clistaid` / `nid_vanzare`) vs. procedura noua cu
- parametri expliciti.** *Recomandarea raportului:* varianta simpla (zero cod Oracle nou), **cu
- conditia** verificata la implementare ca niciun apel Oracle intercalat nu reseteaza starea intre
- scrierea facturii si scrierea corespondentei.
-3. **Aceeasi proforma poate fi copiata de N ori**, fiecare copie cu randul ei `TIP = 4`. E comportamentul
- implicit al oricarei copieri de azi. *Recomandare:* daca deranjeaza, avertisment — **nu** blocare.
-4. **Garda simetrica la stergere** (*„nu poti sterge o proforma care are deja factura generata din ea"*),
- pe tiparul `TIP IN (1,2,3)` din `sterge_factura` — de decis daca se doreste.
-5. **Afisarea „provine din proforma X"** pe factura noua — vine gratis din legatura scrisa, la nivel de
- **document** (ca la retur), nu de linie. De decis daca intra acum sau mai tarziu.
-
-*Gata cand:* dintr-o proforma emisa se genereaza o factura reala, cu numar nou, care descarca gestiunea
-normal, are rand `TIP = 4` in `VANZARI_CORESP` catre proforma sursa, iar proforma **nu** e marcata
-`FACTURAT`.
-*Depinde de:* S5b.
-
-### Decizia 49 (Marius, runda 13) — cele doua formulare merg IN PARALEL, si ALEGE UTILIZATORUL
-
-**Cerinta, in cuvintele lui Marius:** *„utilizatorul sa poata accesa alternativ, daca doreste"*. Deci
-**nu** o setare care ruteaza tacit pe un flux sau altul, si **nu** un pilot pe cativa oameni: ambele
-formulare raman accesibile, iar **alegerea o face omul, in momentul in care factureaza**. Rostul e sa
-existe mereu **un flux despre care se stie ca functioneaza**, cat timp cel nou se stabilizeaza.
-
-> **Corectie a rundei 13:** prima formulare a acestei decizii descria un pilot per utilizator, prin
-> optiunea de firma. **Gresit** — Marius a corectat: optiunea **nu alege**, ci doar **face alegerea
-> disponibila**. Nu se reargumenteaza in varianta veche.
-
-**Mecanismul exista deja in produs si face exact asta**, nu se inventeaza:
-- `factureaza` (`COMUN\programe\ofacturare.prg:87-93`) verifica `gnFacturareNou` si, cand e pornita,
- **intreaba la fiecare facturare**: `AMESSAGEBOX('Facturare noua (DA) sau standard (NU)?', 4+32, ...)`.
- Optiunea deschide alegerea; raspunsul il da utilizatorul, de fiecare data.
-- `gnFacturareNou` e o **optiune de firma**: `optiuni_firma` (`COMUN\programe\oinit_optiuni.prg:225-275`)
- cheama `SCRIE_OPTIUNI(gcUserName)`, parcurge `v_optiuni` si **declara dinamic** globalele publice dupa
- tip (`Public gn&lcvarname` pentru `NUMERIC`), cu filtru optional pe program
- (`Isnull(programe) Or gcNumeProgram $ programe`). **Deci se activeaza si se dezactiveaza din date,
- fara livrare de exe.**
-- **Fluxul vechi ramane intreg:** `factureaza` + `frm_facturare_articole`. S2 sterge doar
- **`factureaza2`**, un fork mort din 2017 (executia interogarii dezactivata, `lnSucces = 1` hardcodat,
- zero utilizatori reali) — **nu** calea veche. **S2 nu are voie sa desfiinteze alegerea.**
-- **Pentru etapa II plasa e alta, si exista deja:** editarea prin regenerare e o **actiune noua**, deci
- „fluxul vechi" pentru ea e **fluxul lui #6**, pe care decizia 38 il pastreaza oricum.
-
-**Cum se prezinta alegerea — de ales la implementare, ambele satisfac cerinta:**
-- **(A) intrebarea de azi**, modal la fiecare facturare. Exista deja, zero cod. Neajuns: intreaba si
- cand utilizatorul stie de o luna ce vrea.
-- **(B) doua intrari distincte** in meniu / doua butoane („Facturare" si „Facturare (nou)"). Aceeasi
- libertate, fara modal la fiecare document. **Recomandat.** Se poate porni cu (A), care e gata, si trece
- la (B).
-
-**Limita, si trebuie spusa explicit ca sa nu creeze o falsa siguranta: alegerea acopera VFP-ul, nu
-Oracle.** Modificarile din pachete — parametrul nou al lui `contabilizeaza_articol` (decizia 34),
-variabila noua din `SET_IDFACT`, si `INSERT` → `MERGE` in `DOCUMENTE` (S9) — sunt **cod comun al
-intregii suite** si se aplica **tuturor deodata**, indiferent pe ce formular alege omul sa lucreze.
-Proiectarea le face **inerte prin constructie** (parametru `NULL` → executie identica cu azi;
-`WHEN MATCHED` care nu se declanseaza pe drumul normal), dar asta e o garantie de regresie zero,
-**nu** o cale de intoarcere. Consecinta practica: pe formular si procedura intoarcerea e imediata; pe
-baza de date, siguranta vine din **testarea unui ciclu normal de scriere in fiecare produs** (deja
-ceruta in S9).
-
-### Decizia 50 (Marius, runda 13) — se editeaza documente curente, nu documente dintr-un lant
-
-**Formularea lui Marius:** *„in principiu nu se poate edita un document pentru care s-a facut retur;
-de principiu se pot modifica documente curente, nu cele care fac parte dintr-un lant"*.
-
-**Deci garda de azi ramane, si devine regula declarata, nu limitare tolerata.** `sterge_factura` arunca
-`ORA-20000` cand documentul are deja facturi / avize de retur emise peste el; S7 **semnaleaza conditia
-inainte de intrarea in formular**, cu mesaj clar, nu ca eroare Oracle la final. Utilizatorul care chiar
-vrea sa editeze sterge intai documentele-copil — comportament existent, nu ceva de construit.
-
-**PRECIZAT de Marius (runda 13), si inchide punctul: „lantul" se citeste IN AMONTE, nu in ambele
-sensuri.** In cuvintele lui: *„daca este generata factura din aviz, avizul nu se mai poate modifica,
-factura da, pentru ca este documentul curent; ma refeream la documentele din lant anterioare"*.
-
-Deci regula, in forma finala:
-- **Documentul care are urmasi se blocheaza** — avizul din care s-a facut factura, factura peste care
- s-a emis retur. Are deja o reprezentare in cod: garda din `sterge_factura`.
-- **Documentul de la capatul lantului ramane editabil** — el e „documentul curent". **Factura din aviz
- (`ntip = 4`) ESTE editabila**, chiar daca are parinte.
-- Prin urmare **perimetrul etapei II nu se restrange**, iar intrebarea deschisa din S10 despre `ntip = 4`
- (aceeasi re-derivare tacuta ca pe contract, dar cu alta sursa de comparat) **ramane in picioare** — nu
- dispare, cum s-ar fi intamplat la citirea stricta.
-
-**VERIFICAT in runda 14 — si premisa era gresita.** Raport: `docs\cercetare\garda_aviz_facturat.md`.
-Se credea ca garda de azi blocheaza documentul doar cand are **retururi** peste el. **Nu e asa:** a doua
-garda din `sterge_factura` testeaza `TIP IN (1, 2)`, iar **`TIP = 1` este corespondenta aviz → factura
-normala, nu retur** (`EXPORT:5464-5476`, semantica citita ramura cu ramura din `CASE`-ul lui
-`finalizeaza_factura`, `EXPORT:14818-14839`). Formularea gresita venea din citirea comentariului
-`-- verific daca exista facturi sau avize de retur`, in care „de retur" se distribuia si peste „facturi";
-codul zice altceva. **Deci regula ceruta de decizia 50 e deja implementata pentru avize** — nu e nevoie de
-nicio garda noua ca *regula*.
-
-**Dar sunt trei garzi, nu doua, si a treia schimba enuntul deciziei 50:**
-
-| garda | `EXPORT` | ce blocheaza |
-|---|---|---|
-| 1 | 5452-5462 | **factura** care are facturi de retur peste ea (`TIP = 3`) |
-| 2 | 5466-5476 | **aviz** care are factura (`TIP = 1`) sau aviz de retur (`TIP = 2`) peste el |
-| 3 | 5480-5494 | **factura din aviz** ale carei avize-sursa au primit intre timp aviz de retur |
-
-Prin urmare **„factura din aviz ESTE editabila" nu e neconditionat**: e editabila doar cat timp niciunul
-dintre avizele ei nu a primit aviz de retur. Nu e „capat de lant" prin definitie.
-
-**Ce lipseste nu e regula, e MOMENTUL.** Garda traieste in interiorul lui `sterge_factura`, deci se
-manifesta ca `ORA-20000` **in mijlocul** pasului de stergere din regenerare — dupa ce utilizatorul a
-completat formularul si dupa deschiderea tranzactiei. S7 are nevoie de un **pre-flight read-only** pe
-**exact aceeasi conditie**, fara reimplementarea regulii (vezi S7). Interogarea se face pe
-`VANZARI_CORESP`, **nu** pe `VANZARI.FACTURAT`: `FACTURAT` e un marcaj derivat, scris si resetat, dar
-**necitit de nicio garda** — semnalul autoritar e `VANZARI_CORESP`.
-
-**GOLUL REAL NU E PE AVIZ, E PE PROFORMA — si a devenit relevant chiar in runda 14, odata cu decizia 51.**
-`pack_facturare.sterge_proforma` (`EXPORT:5610-5635`) **nu are nicio garda**: corpul ei e doua
-`UPDATE ... SET STERS = 1`. E o procedura **complet separata**, care nu cheama `sterge_factura`, deci
-garda existenta **nu se extinde automat** la `TIP = 4`. O proforma din care s-a emis factura se poate
-sterge azi fara niciun avertisment. Calea VFP iese devreme din `do_sterge`
-(`ofacturare_comun.vc2:4707-4719`), inainte de restul verificarilor. **Asta e continutul concret al
-punctului deschis 4 din S5c** („garda simetrica la stergere") — nu mai e o intrebare de principiu, e o
-garda de scris intr-o procedura care azi n-are niciuna.
-
-**Comanda si contractul nu trec prin `VANZARI_CORESP`** si n-au garda de tip „are urmasi" pe factura:
-comanda se leaga prin `VANZARI.ID_COMANDA` + `inchide_comanda`, iar garda ei e **in VFP si pe comanda**,
-nu pe factura (`COMUN\clase\ocomenzi.vc2:1806-1807` la modificare, `:2065-2066` la stergere); contractul
-se leaga prin `VANZARI.ID_CTR` + `CTR_RATE_FACTURI`.
-
-### Deciziile lui Marius, runda 13 (10.08.2026) — luate, nu de reluat
-
-Cele cinci puncte neblocante ramase din runda 12. **Patru din cinci au mers pe recomandare; al
-cincilea (48) a respins-o motivat.** Fiecare e scrisa si la locul ei, in povestea careia ii apartine.
-
-44. **`poArticol` devine parametru explicit** al dialogurilor de linie (`do_verifica_articol`,
- `do_alege_stoc` / `frm_articol_gest_factura`), in loc de variabila `Private` populata de apelant.
- **O singura solutie pentru golul din S4e si cel din S4f (R7)** — e aceeasi problema structurala.
- Schimbare de contract, **aprobata ca atare**; cere inventarul si actualizarea tuturor apelantilor
- existenti inainte de prima editare. (S4e, S4f)
-45. **Asimetria din `do_modifica`** se lasa sa se **corecteze de la sine** prin recalculul la cerere,
- dar corectia se **declara explicit in changelog**. (S4, punctul 2)
-46. **Corectia pe tipurile `23,41` asteapta punctul 2** (recalculul pe server, care acopera Rolul B).
- Punctul 1 **nu se redeschide** acum. (S4, punctul 2)
-47. **`zi_curs`: simetrie.** Campul se ascunde la loc la stergerea ultimului articol in valuta;
- „clipitul" e acceptat ca pret al unei reguli unice. (S4d)
-48. **Tabelul de configurare per tip = cursor generat in cod la pornire**, nu `DBF` static, nu tabela
- Oracle. Detectia tipului necunoscut (eroare la deschidere) se pastreaza; se accepta recompilarea
- la orice tip nou. (S5)
-
-### Deciziile lui Marius, runda 14 (11.08.2026) — luate, nu de reluat
-
-51. **`TIP = 4` in `VANZARI_CORESP` = „factura scrisa dintr-o proforma".** Confirmat explicit, dupa ce
- i s-a explicat ce inseamna `1/2/3` (`TIP` = **natura legaturii parinte-copil**, nu tipul
- documentului: `1` = aviz → factura, `2` = aviz → aviz de retur, `3` = factura → factura de retur).
- `4` intra in aceeasi familie cu `1`. Valoarea e libera pe ambele fronturi (niciun apel cu `4` in
- pachet, zero randuri in date), tabela are un singur scriitor in toata suita, structura nu se
- schimba. **Alocarea e ireversibila odata cu primele date de productie** — acceptat ca atare. (S5c)
-52. **`do_modifica` ramane activ pentru multi-selectie.** Formularul unificat preia cazul cu un singur
- document; calea veche ramane pentru modificarea in bloc. **Nicio capacitate nu se pierde la
- retragere** — dar consecinta e ca S2 nu poate desfiinta nici aceasta ruta, nu doar alegerea de la
- decizia 49. (S8b, punctul 10)
-53. **Atasamentul PDF se sterge la reemitere**, nu se remigreaza si nu se marcheaza „versiune
- inlocuita". Documentul reemis porneste curat; PDF-ul se regenereaza la prima listare. **Consecinta
- semnalata explicit lui Marius si acceptata de el:** urma a ceea ce s-a trimis efectiv clientului
- dispare din sistem. Pasul `UPDATE ATASAMENTE_VANZARI SET id_vanzare = :nou`, adaugat in S9 la runda
- 13, **se inlocuieste cu stergere**. (S11, punctul 15)
-54. **La reemitere se scriu valorile din formular, nu se reciteste sursa.** Formularea lui Marius:
- *„nu inteleg de ce se schimba valorile fata de ce se incarca din factura sursa care se modifica?
- asta este comportamentul pe care il doresc — modific sursa"*. **Asta rastoarna S10:** intrebarea nu
- mai e „ce garda punem peste re-derivare", ci **„re-derivarea chiar se produce pe calea de
- reemitere?"** — si daca da, se **elimina**, nu se avertizeaza. Avertizarea + confirmarea propuse de
- raportul S10 sunt **respinse**: nu se cere utilizatorului sa confirme o schimbare pe care n-a
- cerut-o. Vezi S10, rescris. (S10, punctele 11 si 12)
-56. **„DA LA TOATE" — Marius a acceptat in bloc toate recomandarile deschise, runda 14.** Formularea
- lui: *„da la toate, mai putin"* cele doua puncte pe care le-a intrebat separat (48/49 si voiajele).
- **Nu se mai reintreaba niciunul dintre punctele de mai jos** — sunt luate, si fiecare e scris si la
- locul lui, in povestea careia ii apartine:
- - **S8** — canalul de citire a liniilor: **(B), procedura noua `cursor_editare_document`** (nu se
- extinde `cursor_retur_document`, ca sa nu se schimbe comportamentul copierii; nu
- `FACT_VFACTURI_DETALII`, care pierde `ID_POL`, `PRETD` si tratamentul valutar — argument intarit
- de faptul ca **`VVANZARI_ARTICOLE` nu expune `ID_POL` / `ID_CTR`**, vezi S10).
- - **S8** — `GESTIONABIL` la editare: **din document**, nu din nomenclatorul curent.
- - **S8** — `text_aditional`: **se normalizeaza la incarcare** (`Chr(170)` → `CR+LF`) si se
- re-normalizeaza la comparatie. Formele diferite salvate de cele doua rute de scriere se
- **semnaleaza separat** ca defect preexistent.
- - **S8** — `zi_curs` pe calea de editare: **ascuns** (precedent: tipurile 8/9). Abatere mica de la
- decizia 5, asumata.
- - **S8** — `poDate.lEditare`: **proprietate pe `oDateFactura`**, nu parametru (patru locuri au
- nevoie de semnal; `lCopiere` e deja acolo cu acelasi rol).
- - **S8** — `id_ruta`: **proprietate noua pe `oDateFactura`** (fara ea S8c nu poate implementa unul
- din cei 14 parametri).
- - **S8** — defectul de prefixare `text_aditional` la `Init` pentru contracte: **se ocoleste in #13**
- prin `lEditare` si **se semnaleaza separat**, nu se repara pe calea de emitere.
- - **S5c** — apelul Oracle pentru legatura proforma → factura: **varianta simpla**, pe starea de
- sesiune a pachetului, zero cod PL/SQL nou — **cu conditia verificata la implementare** ca niciun
- apel intercalat nu reseteaza starea intre scrierea facturii si scrierea corespondentei.
- - **S5c** — aceeasi proforma facturata de N ori: **avertisment, nu blocare**.
- - **S5c** — garda simetrica la stergerea proformei: **se scrie**. Nu e reutilizare —
- `sterge_proforma` n-are azi nicio garda (vezi decizia 50, sectiunea rescrisa).
- - **S5c** — afisarea „provine din proforma X": **da**, la nivel de document.
- - **S4g** — `CU_TVA = 1` hardcodat: **se verifica pe date inainte de implementare**, nu se
- presupune inofensiv. Efectul prin `nproc_tva_max` e masurat, pe linie scutita + discount global.
- - **S4g** — trasabilitatea `CONT_VENIT` pe `VANZARI_DETALII`: **da**, se pastreaza coloana.
- - **Decizia 54, cele trei consecinte: acceptate toate trei.** `IN_STOC` vine din formular (si **S8
- trebuie sa-l incarce** — vezi S10, consecinta 1); **se pierde validarea** liniei fata de comanda
- pe ramura comenzi, asumat; **`PROC_TVAV` ramane derivat** — reemiterea dupa o modificare legala
- de cota va da cota noua, **acceptat deocamdata**; transformarea lui in parametru ramane o
- decizie separata, daca se cere vreodata reproducere exacta si peste asta.
- - **Defectul `lnTip` din `do_copiaza`** (runda 13): **se repara la #6**, fisierul fiind al lui.
- - **Punctele pur interne** (numarul codului de eroare `FACT-0xx`, numele cheii de optiune
- `FACT_SCD_ARTFPRET`, forma semnalului de regenerare) — **lasate la latitudinea implementarii**,
- cu recomandarile deja scrise in povestile lor.
-
- **Raman deschise doar doua**, si amandoua din motive proprii, nu din lipsa de raspuns:
- **(a) tipurile 48/49** (custodie) — Marius a cerut sa stie implicatiile, i s-au explicat, decizia
- n-a fost inca data. *Inchis intre timp — decizia 60, runda 16: da, sunt editabile prin #13,
- cu executia conditionata de verificarea custodiei in curs.*
- **(b) cota si explicatia de TVA a discountului de document** —
- **cercetare TERMINATA** (sectiunea K-bis): cota era regula implicita „cota maxima de pe factura",
- explicatia e azi o constanta hardcodata (`ReasonCode="95"`, text „Discount"). **Partea de
- repartizare s-a decis — decizia 59, runda 16: proportional pe cote.** Ramane deschis doar campul
- text optional de motiv — **inchis si el: decizia 61** (da, se adauga), cu asezarea fixata de
- **decizia 66** (in banda de totaluri, langa discount).
-55. **Metoda de executie e obligatorie, si e scrisa in plan.** La implementare planul **se sparge pe
- stories**, fiecare story fiind o livrare de sine statatoare; **fiecare pas se testeaza**, nu doar
- capetele de etapa (S6 / S12); si **fiecare story trece prin code review dupa implementare si dupa
- teste, inainte de commit**. Sectiunea **„Metoda de executie"**, imediat inainte de Etapa I. S13
- nu mai e momentul review-ului, ci al inchiderii.
-
-### Deciziile lui Marius, runda 15 (11.08.2026) — luate, nu de reluat
-
-57. **Asezarea zonei de jos: VARIANTA D.** Aprobata explicit („sunt de acord cu varianta D"), dupa doua
- corectii cerute de el pe drum: (a) *„imi place linia de totaluri de la varianta C, dar incasarea si
- alte date le vreau tot in acelasi formular, colapsate, mai jos de totaluri"*; (b) *„sectiunile
- incasare si alte date colapsate trebuie sa fie pe acelasi rand — este destul loc pentru amandoua,
- detaliile pot sa fie grupate pe orizontala, nu pe verticala"*. A / B / C **cad**.
-
- **Ce inseamna D, concret, pentru S1 si S3:**
- 1. **Banda de totaluri** (preluata din C): pe toata latimea, lipita de grid, cu baza, discountul pe
- articole, discountul de document **cu procentul editabil pe loc** si TVA desfacute pe un rand;
- totalul mare, singur, la dreapta.
- 2. **Incasare si Alte date sunt sectiuni colapsabile in formular, nu dialoguri modale** — **una
- langa alta pe acelasi rand**, sub totaluri, fiecare pe jumatate de latime. Randul inchis arata
- **rezumatul continutului** („NUMERAR · 5 570,55 lei"), nu doar un titlu. Independente: se poate
- tine deschisa doar una. Campurile dinauntru se aseaza **pe orizontala**, doua randuri fiecare.
- 3. **Nu exista bara de comenzi jos.** `but_renunt` / `but_termin` raman unde sunt azi — in banda de
- titlu, sus in dreapta (`COMUN\clase\cmd_butoane.vc2:288` si `:386`, butoane-imagine cu
- `Top = 1`, `Anchor = 8/9`, tooltip „Renuntare (ESC)" / „Terminare (CTRL+F)").
- 4. **Antetul strans la doua randuri**, fara titluri de grup, si **panoul „Discount pe document"
- dispare** ca panou separat.
-
- **Patru consecinte de dus in executie, nu de redescoperit:**
- - **Dispare „renunt doar la incasare".** Fara `Accept` propriu pe dialog, ce se completeaza in
- sectiune se scrie la `Termina`, impreuna cu documentul. **I-a fost spus explicit** inainte de
- aprobare si a acceptat.
- - **Validarea incasarii nu mai are moment propriu** — se muta in `Termina`, langa restul
- verificarilor. **De scris explicit in S9.**
- - **Starea deschis/inchis a sectiunilor** — de decis daca se retine intre documente sau porneste
- mereu inchisa. Nu blocheaza nimic; recomandare: porneste inchisa, se retine per utilizator.
- - **Caption pe cele doua butoane.** Sus in dreapta, langa `✕`-ul ferestrei, un `✓` verde fara text
- e ambiguu. Punctul era deja notat in v8 pentru `But_renunt1` / `But_reset1`; D il face mai
- apasat, pentru ca acum ele sunt **singura** cale de iesire.
-
- **INCHIS.** Cercetarea despre cota si explicatia de TVA a discountului de document (punctul
- deschis (b) de la decizia 56) **s-a terminat** — vezi sectiunea K-bis — si repartizarea s-a decis
- (**decizia 59, runda 16**: proportional pe cote, fara sa se ceara cota de la utilizator), deci a
- treia sectiune „grea" (cota + explicatie proprii) nu mai e in discutie. Ramane varianta minimala:
- **decizia 61 (runda 16) a materializat-o** — Marius vrea campul text optional de motiv. Asezarea
- lui a oscilat o data: decizia 64 il facea a treia sectiune jos, **decizia 66 (runda 17) o
- rastoarna si il muta in banda de totaluri, langa discount**. **Punctul 2 de mai sus ramane deci
- exact cum a fost aprobat: doua sectiuni jos, fiecare pe jumatate de latime.** D ramane intr-un etaj.
-
-58. **Mockup-ul asezarii ramane doar online.** Formularea lui: *„nu vreau artifactul html, doar online,
- ca sa nu mai intretii 2 variante"*. `docs\mockup_13_variante_asezare_jos.html` **a fost scos din
- `docs\`**; sursa de adevar e
- **https://claude.ai/code/artifact/dfc70d38-856f-48fd-b6af-3da78e9da4f7**.
- Ca sa-l modifici: `WebFetch` pe URL → scrie HTML-ul intr-un fisier de lucru **in scratchpad, nu in
- `docs\`** → `Artifact` cu **`url` = link-ul de mai sus** (fara `url` se creeaza link nou).
- **`docs\mockup_13_formular_unificat.html` (v8) nu intra sub regula asta** — cerinta a fost data
- numai pentru mockup-ul asezarii.
-
-### Decizia 59 (Marius, runda 16) — luata, nu de reluat
-
-59. **Discountul de DOCUMENT se repartizeaza PROPORTIONAL PE COTE.** Formularea lui: *„discount pe
- document repartizat proportional pe cote"*. Se adopta recomandarea cercetarii din **K-bis**:
- regula de azi („toata valoarea discountului primeste cota MAXIMA de pe factura", prin
- `Calculate Max(proc_tvav)`) **se inlocuieste** cu repartizarea proportionala cu baza fiecarei
- cote de pe factura. **Nu se cere utilizatorului cota** — repartizarea e automata.
-
- **Ce atrage dupa sine, tot din K-bis:**
- 1. **Doua locuri de schimbat, nu unul, si in ACEEASI livrare:** `prelucreaza_facturacrs` (VFP,
- `COMUN\programe\ofacturare_comun.prg:1886-1897`) trebuie sa insereze cate un rand-sentinela
- **per cota** in loc de unul singur; si `recalculeaza_totaluri_vanzari` (PL/SQL,
- `ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16081-16092`) trebuie sa inlocuiasca `MAX(...)`
- cu suma repartizarii. Daca se schimba doar unul, `VANZARI.TOTAL_TVA` si TVA-ul din eFactura
- **diverg** pe facturile cu cote mixte. **Nu e optional si nu se poate esalona.**
- 2. **Bucatile de discount trebuie sa primeasca `id_jtva_coloana` al grupului pe care il reduc**,
- nu doar cota. Cheia de grupare din `xmlefactura.prg:246` are cinci campuri si `expltva` se
- completeaza tot prin `id_jtva_coloana`. O implementare care seteaza doar `proc_tva` **lasa
- grupul orfan exact unde e azi** — repara jumatate din defect si o lasa pe cealalta.
- 3. **eFactura nu cere nicio modificare** — `xmlefactura.prg:758-792` grupeaza deja
- `GROUP BY proc_tva` si emite cate un `AllowanceCharge` per cota.
- 4. **Diferenta de rotunjire cade pe cota cu baza cea mai mare**, ca suma bucatilor sa fie exact
- `VANZARI.DISCOUNT`. E recomandarea cercetarii, luata ca implicita — Marius a fost instiintat
- ca se merge asa fara sa mai fie intrebat, deci se schimba doar daca obiecteaza. (Raportul
- spune pe alocuri „ultima cota preia diferenta"; **regula care se implementeaza e cea de aici**,
- ca sa nu ramana doua formulari in circulatie.)
- 5. **Doua consecinte vizibile, acceptate implicit prin decizie:** factura tiparita va arata **N
- randuri** „Discount X % Factura" in loc de unul, pe facturile cu cote mixte; si **nota
- contabila** primeste TVA-ul discountului spart pe cote.
- 6. **Rezolva si grupul orfan** de pe facturile scutite / taxare inversa / intracomunitare
- (K-bis), fara garda separata, si desfiinteaza ambiguitatea lui `agettipcota(1)`.
-
- **Raman DESCHISE, nu de presupus rezolvate:**
- - **campul text optional de motiv** (`AllowanceChargeReason` in locul constantei „Discount";
- `ReasonCode` ramane `95`) — Marius **nu s-a pronuntat**; de el atarna si intrebarea de asezare
- din S1 / decizia 57 (a treia sectiune pe rand sau rand propriu);
- - **retroactivitatea la relistare / retrimitere**: o factura veche relistata sau retrimisa in
- eFactura ar genera alt XML decat cel trimis initial. **Nedecis.**
-
-### Deciziile 60-65 (Marius, runda 16) — luate, nu de reluat
-
-60. **Facturile de marfa in CUSTODIE (tipurile 48 si 49) SUNT editabile prin #13.** Formularea lui:
- *„vreau sa fie posibila editarea si a facturilor in custodie"*. Intra deci in perimetrul
- **etapei II**, contrar recomandarii „nu acum" din raportul S8 (intrebarea 7, §8.2).
-
- **Inchide** punctul **(a)** de la **decizia 56** (tipurile 48/49, singurul ramas deschis din
- blocul „da la toate") si **necunoscuta N5** din `docs\cercetare\s8_incarcare_document.md` §8.1,
- plus restul intrebarii 7 din §8.2.
-
- **Ramificatie noua pentru S8:** pe tipurile 48/49, controlul `ct_clb_altele` e scos
- **neconditionat** la copiere (`ofacturare.vc2:9705-9712`), spre deosebire de tipurile 1/5/10
- unde copierea il **pastreaza** si il reeticheteaza (`s8_incarcare_document.md` §3.2, ramura 3).
- Calea de **editare** trebuie sa-l pastreze si pe custodie — ramura 48/49 a copierii nu poate fi
- refolosita ca atare.
-
- **VERIFICAT — blocantul CADE, dar premisa initiala era gresita.** Raportul:
- `docs\cercetare\custodie_48_49_stergere_reemitere.md`. `scrie_fact_aviz_custodie` **nu are
- legatura cu tipurile 48/49** — are un singur apel in tot pachetul (`PACK:7521`), pe ramura
- `pack_facturare.ntip <> 4` (`:7472`), deci serveste `ntip = 4` (factura din avize), nu custodia;
- numele procedurii a indus in eroare, si premisa gresita a circulat pana in aceasta decizie.
- Emiterea unui document 48/49 **nu atinge deloc stocul**: sursa lor unica de articole e
- `cursor_articole_k` (`PACK:3595-3701`), restransa explicit la `WHERE C.IN_STOC = 0` (`:3695`),
- iar `descarca_gestiune` se cheama doar cand `in_stoc = 1` (garda dubla, la apelant `:7472-7475`
- si in corpul procedurii `:7789-7797`). `sterge_factura` (`:5432-5607`) nu are ramura dedicata
- pentru 48/49, si nici cele trei garzi de refuz al stergerii (`:5452-5494`) nu le prind — dar
- **n-are ce reversa**, fiindca nimic legat de stoc n-a fost scris la emitere. **Regenerarea e
- sigura pe 48/49**, nu pentru ca reversarea ar functiona, ci pentru ca nu exista nimic de
- reversat.
-
- **Rezerva, de scris, nu de ascuns:** siguranta atarna de un invariant azi impus doar de sursa de
- articole — „documentele 48/49 contin numai articole cu `IN_STOC = 0`". Invariantul **nu s-a
- verificat exhaustiv**, doar constatat pe sursa curenta. #13 schimba modul de adaugare a
- articolelor (**S4** — cautare pe server, in linie; **S4g** — adaugare de articole la modificarea
- oricarui document): daca formularul unificat ajunge sa permita adaugarea unui articol
- **gestionabil** pe un document 48/49, invariantul se rupe si concluzia de siguranta pica.
- **Cerinta pentru S4/S4g/S5: pe tipurile 48/49 se pastreaza restrictia la articole `IN_STOC = 0`**
- — vezi notele de executie la acele povesti; devine **criteriu de test**, nu presupunere.
-
- Pentru **emitere**, tipurile 48/49 erau oricum deja acoperite de etapa I (S5 completeaza cele
- patru randuri lipsa din `Do Case`: 45, 48, 49, 52) — decizia 60 priveste doar **editarea**.
-
-61. **Discountul de document primeste un CAMP TEXT OPTIONAL de motiv.** Formularea lui: *„la
- discount, da, un camp text optional"*.
-
- **Inchide** ultimul punct ramas deschis din **K-bis** si din **decizia 56 (b)** — campul de
- motiv nu mai e „Marius nu s-a pronuntat".
-
- **Ce inseamna concret:**
- - inlocuieste constanta hardcodata `"Discount"` ca `cbc:AllowanceChargeReason`
- (`COMUN\programe\xmlefactura.prg:774-776`); **`ReasonCode` ramane `95`**;
- - cere **stocare noua** — azi nu exista nicio coloana pe `VANZARI` pentru motivul discountului
- de document;
- - cere **un control nou in formular** — singura bucata din reparatia discountului (K-bis /
- decizia 59) care chiar cere UI nou, restul fiind repartizare automata fara interactiune.
-
- **Redeschisese, in varianta minimala, intrebarea de asezare de la decizia 57. INCHISA DEFINITIV
- PRIN DECIZIA 66 (runda 17): campul sta in banda de totaluri, langa discount.** Decizia 64, care il
- facea a treia sectiune jos, **e rasturnata** — randul de jos ramane cu doua sectiuni, ca la decizia
- 57. Varianta D ramane intr-un etaj. Paragrafele din **S1** si din **decizia 57** sunt actualizate
- in acest sens.
-
-62. **Restrictia de modificare e „documentul sa NU fi fost trimis in eFactura" — si de aici
- retroactivitatea NU mai e o intrebare.** Formularea lui: *„singura restrictie pentru modificare
- este sa nu fie trimisa in eFactura, deci nu are legatura retroactivitatea"*.
-
- Garda insasi nu e noua — **S7** o are deja, reutilizata din #6
- (`COMUN\programe\ofacturare_editare.prg:19-28`, functia `EsteInEFactura`; apelata din
- `COMUN\clase\ofacturare_comun.vc2:3764`). Ce era intrebare deschisa era
- doar partea lasata de **decizia 59**: daca o factura veche, retrimisa, ar trebui tratata altfel
- fata de una noua. Raspunsul lui Marius **inchide** acea intrebare: nu se leaga de nicio data si
- de niciun flag suplimentar — verificarea `EsteInEFactura` ramane singurul criteriu de
- modificare.
-
- **Ramane un rest neacoperit, semnalat lui Marius, nedecis inca:** o factura **veche, deja
- trimisa**, daca e doar **relistata** (tiparita din nou, nu editata), trece iar prin
- `prelucreaza_facturacrs` si — dupa decizia 59 — ar produce **N randuri de discount in loc de
- unul** pe facturile cu cote mixte, deci hartia ar diferi de originalul trimis in eFactura.
- Relistarea nu e modificare, deci garda `EsteInEFactura` nu o acopera.
-
-63. **CERINTA NOUA DE AUDIT pe documente.** Formularea lui: *„este doar util de stiut data crearii,
- data modificarii daca este cazul, utilizatorul crearii si al modificarii daca este cazul,
- respectiv data stergere si utilizator stergere daca este cazul, pentru audit"*. Sase informatii:
- **data + utilizator** pentru **creare**, **modificare** si **stergere**.
-
- Scrisa initial ca cerinta, cu cercetarea in curs. **Cercetarea TERMINATA**, raport:
- `docs\cercetare\audit_vanzari_creare_modificare_stergere.md`.
-
- **Verdict, in doua randuri:** patru din cele sase informatii cerute **exista deja** pe `VANZARI`
- si se scriu consecvent (`ID_UTIL`/`DATAORA` la creare, `ID_UTILS`/`DATAORAS` la stergere); **lipseste
- complet perechea de modificare** (nicio coloana, verificat cu filtru `%MODIF%` pe
- `all_tab_columns`), iar editarea prin stergere+reemitere (S9) ar **suprascrie tacit** perechea de
- creare cu utilizatorul si data regenerarii, daca nu se transporta explicit — acelasi risc deja
- rezolvat pentru `ID_FACT` (sectiunea „E. `ID_FACT`", linia 762).
-
- **Poveste noua, proiectata: S14** — verdict complet, recomandare si punctele ramase de decis cu
- Marius acolo.
-
-64. ~~**Asezarea campului de motiv: RANDUL SE IMPARTE IN TREI.**~~ **RASTURNATA DE DECIZIA 66
- (runda 17) — NU MAI E IN VIGOARE.** Formularea de atunci: *„campul de motiv imparte randul in 3"*;
- randul de jos ar fi avut trei sectiuni (incasare, alte date, motivul discountului), ~440 px
- fiecare la 1366 px.
-
- **Se pastreaza ca istorie, nu ca regula**, si merita pastrata: varianta a fost **construita in
- mockup (v9) si respinsa dupa ce Marius a vazut-o** — *„motiv discount vreau sa fie langa discount,
- nu a treia coloana"*. E argumentul cel mai bun din tot planul pentru **de ce se face mockup
- inainte de cod**: decizia luata pe descriere s-a intors la prima privire pe forma desenata.
- Ce e in vigoare: **decizia 66**, mai jos.
-
-65. **Auditul (decizia 63) se afiseaza in gridul din `frm_facturi`, nu in formularul facturii.**
- Formularea lui: *„auditul presupun coloanele dataora si utilizator adaugat/modificat/sters, le
- vreau pe grid-ul din formularul frm_facturi, nu in formularul facturii propriu-zise - este
- posibil sa fie deja coloane"*.
-
- Confirma continutul cerintei de audit (decizia 63): trei perechi **data + utilizator**, pentru
- **adaugat**, **modificat** si **sters**. Locul de afisare e **gridul din `frm_facturi`**, nu
- formularul unificat — deci **S14 nu cere controale noi in formularul unificat**, cere **coloane
- in gridul listei de facturi**. E o cerinta mai usoara decat presupunea S14, si e de spus explicit.
-
- **Sarcina de verificat la implementarea lui S14, adaugata ca prim pas al povestii:** Marius
- banuieste ca unele coloane exista deja in acel grid. **Nu s-a verificat.** S14 incepe deci cu
- **inventarul gridului din `frm_facturi`** — ce coloane de audit sunt deja acolo, ce surse au —
- si abia apoi adauga ce lipseste. Nu se presupune nici ca exista, nici ca nu.
-
-### Decizia 66 (Marius, runda 17) — luata, nu de reluat. RASTOARNA DECIZIA 64.
-
-66. **Motivul discountului sta LANGA DISCOUNT, in banda de totaluri — nu ca a treia sectiune jos.**
- Formularea lui: *„motiv discount vreau sa fie langa discount, nu a treia coloana"*.
-
- **Anuleaza decizia 64** (randul de jos se imparte in trei). Randul de jos revine la **doua
- sectiuni colapsabile** — incasare si alte date — adica exact la ce aprobase decizia 57, punctul 2,
- inainte ca decizia 61 sa redeschida discutia. **Decizia 57 ramane intreaga; nu se mai atinge.**
-
- **Ce inseamna concret, pentru S1 si S3:**
- - campul de motiv e un **control in banda de totaluri**, imediat dupa suma discountului de
- document, inainte de TVA; ia latimea ramasa pana la totalul mare, care sta la dreapta;
- - **cele doua sectiuni de jos redevin pe jumatate de latime** (~660 px la 1366 px), nu ~440 —
- argumentul „strans, asumat ca atare" din decizia 64 **cade odata cu ea**;
- - **regula de activare, adaugata de proiectare, nu ceruta explicit:** campul e activ **numai cand
- discountul de document nu e zero**. Un motiv fara discount n-are ce explica, si ar ajunge in
- `AllowanceChargeReason` pe un `AllowanceCharge` inexistent. Daca Marius vrea altfel, e o linie
- de schimbat.
-
- **Consecinta de asezare, de stiut la implementare:** banda de totaluri devine plina — baza,
- discount articole, discount document (procent + suma + bifa „evidentiat"), motiv, TVA, total. La
- latimi mici **se rupe pe doua randuri** (`flex-wrap`), si asta e acceptat: alternativa ar fi
- scoaterea bifei „evidentiat" din banda, care n-a fost ceruta.
-
- Restul deciziei 61 (stocare noua pe `VANZARI`, `AllowanceChargeReason`, `ReasonCode` ramane `95`)
- **e neatins** — se schimba doar locul controlului in formular.
-
-#### S6 — Test pe fluxul real, formularul unificat
-Headless (`COMUN\docs\depanare_testare_vfp.md`) + UI (`COMUN\docs\testare-ui-vfp.md`), cate un caz
-pe fiecare sursa: lista de preturi, comanda, contract, aviz, retur, transfer, valuta. Comparatie
-directa cu documentul emis pe calea veche: `vanzari`, `vanzari_detalii`, `act`, `rul`, totalurile
-denormalizate, listarea.
-*Depinde de:* S5.
-
-### Etapa II — editarea prin regenerare
-
-#### S7 — Actiunea si garzile
-Actiune noua pe `frm_facturi`, sub tokenul de drepturi existent. Garzi refolosite din
-`COMUN\programe\ofacturare_editare.prg` (`EsteInEFactura:12`, plus luna inchisa, luna curenta,
-`ReferinteDocumenteNota`) — **nu se rescriu**, sunt deja extrase de #6. Plus garzile proprii
-regenerarii: refuz daca documentul are **urmasi**.
-
-**PRECIZAT in runda 14, pe cod** (`docs\cercetare\garda_aviz_facturat.md`): regula exista deja integral
-in Oracle, in **trei** garzi consecutive din `sterge_factura` — factura cu retururi (`TIP = 3`,
-`EXPORT:5452-5462`), **aviz cu factura sau aviz de retur** (`TIP IN (1,2)`, `EXPORT:5466-5476`), si
-factura din aviz ale carei avize-sursa au primit intre timp aviz de retur (`EXPORT:5480-5494`).
-**S7 nu reimplementeaza regula** — o citeste **mai devreme**, read-only, inainte de intrarea in
-formular:
-
-```sql
-select count(*) from vanzari_coresp
- where sters = 0 and id_vanzare_aviz = :id_vanzare and tip in (1, 2, 3)
-```
-
-plus subinterogarea din garda 3 pentru cazul „factura din aviz". Se interogheaza `VANZARI_CORESP`,
-**nu `VANZARI.FACTURAT`** — `FACTURAT` e derivat si necitit de nicio garda. Garda din `sterge_factura`
-**ramane pe loc ca plasa de siguranta**: nu se muta, nu se slabeste.
-
-**Gol de acoperit, iesit tot in runda 14:** pentru **proforma** (`TIP = 4`, decizia 51) garda **nu
-exista deloc** — `sterge_proforma` (`EXPORT:5610-5635`) e o procedura separata fara nicio verificare,
-iar calea VFP iese din `do_sterge` inainte de restul (`ofacturare_comun.vc2:4707-4719`). Garda simetrica
-ceruta de S5c e **cod nou**, nu reutilizare.
-*Gata cand:* actiunea refuza corect si cu mesaj clar documentele trimise in eFactura, sterse, din
-luna inchisa, referentiate, sau care au urmasi (retur, factura din aviz, factura din proforma) —
-**inainte** de deschiderea formularului, nu ca `ORA-20000` la final.
-*Depinde de:* S6, si de inchiderea perimetrului cu #6 (fisier partajat).
-
-#### S8 — Incarcarea documentului in formular
-
-> **PROIECTAT INTEGRAL in runda 14 — `docs\cercetare\s8_incarcare_document.md` (52 KB, 8 sectiuni).**
-> **Schita de mai jos e corecta ca directie, dar gresita in piese, si nu marunt:**
-> 1. **`completeaza_setari_document(toFactura, .T.)` copiaza 16 proprietati din ~120**
-> (`COMUN\programe\ofacturare_comun.prg:361-411`) si **niciuna de identitate**. Lipsesc serie,
-> numar, data, scadenta, `text_aditional`, `id_facturare`, `id_ruta`, `tip_saft`, `efactura`,
-> `listare_detaliata`, `dataora_exp`, discountul de document, `discount_evidentiat`, `eproforma`,
-> valuta, cursul.
-> 2. **`cursor_retur_document(V_COPIERE = 1)` nu umple documentul, ci selectorul-sursa.** Rezultatul
-> intra in `crsarticole` (gridul din stanga); `crsfactura` se creeaza **gol si ramane gol** —
-> comentariul din cod e explicit (`COMUN\programe\ofacturare.prg:338`, `:455-457`). Transferul se
-> face doar prin `do_adauga_tot` → `do_adauga_articol`, care pentru articolele gestionabile trece
-> **prin dialogul de alegere din stoc**.
-> 3. **`cursor_retur_document` nu intoarce `ID_VANZARE_DET` si nici `TAXCODE`**
-> (`PACK_FACTURARE:3949-4054`). Fara `ID_VANZARE_DET`, cheia de linie presupusa de S8b **nu exista**,
-> iar ruta ieftina `modifica_explicatie_articol` **devine neapelabila** — primul ei parametru *este*
-> `V_ID_VANZARE_DET` (`PACK_FACTURARE:14511-14519`).
->
-> **Recomandarea centrala:** S8 se construieste pe precedentul care face deja exact asta —
-> `relisteaza_ofacturare_stoc` (`COMUN\programe\ofacturare_stoc.prg:456-742`), care reconstituie
-> `poDate` + cursorul de linii dintr-un document salvat, prin `FACT_VFACTURI` + `FACT_VFACTURI_DETALII`
-> (ambele au `ID_VANZARE_DET` si `TAXCODE`). Canalul final e intrebarea 1 din §8.2 al raportului
-> (*recomandat:* procedura noua `cursor_editare_document`, ca sa nu se schimbe comportamentul copierii).
->
-> **CORECTIE la raportul S8, facuta de sesiunea principala (runda 14):** raportul lasa deschis (N6,
-> intrebarea 7) daca „`frm_facturare_articole2` (varianta paralela)" intra in perimetru, si recomanda
-> „nu acum". **Premisa e gresita: `frm_facturare_articole2` NU e o varianta paralela de exclus — e
-> PROTOTIPUL pe care se construieste formularul unificat**, conform S1 („se porneste de la prototip",
-> `ofacturare.vc2:15741-19355`). Deci S8 il tinteste pe el, nu pe `frm_facturare_articole`. Faptul ca
-> are `do_adauga_tot` / `do_adauga_articol` proprii, cu logica divergenta (fara testul `llGestionabil`,
-> `ofacturare.vc2:17476`, `:17124`), **nu e un motiv de excludere, e exact driftul din 2017 pe care S2
-> il inchide** — cele doua se unifica, nu se aleg. Partea de tipuri 48/49 din intrebarea 7 **s-a
-> inchis prin decizia 60**: sunt editabile. Intrebarea 7 e deci inchisa integral.
-
-> **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
-> complet al celorlalte initializari „pentru document nou" care trebuie sarite (§2.2).
-
-`completeaza_setari_document` pentru antet + `cursor_retur_document(V_COPIERE = 1)` pentru linii,
-**fara** degradarea de tip din `do_copiaza`. Se incarca in plus, fata de copiere: serie / numar /
-data / scadenta reale, discountul de document (`VANZARI.DISCOUNT`), `discount_evidentiat`, textul
-aditional, datele din `frm_alte_date` (delegat, auto, agent, adresa de facturare), explicatia si
-`taxcode` pe fiecare linie, si legatura cu sursa (`id_comanda`, `id_ctr`, lista de avize din
-`vanzari_coresp`) — ca reemiterea sa reconsume aceeasi sursa.
-**Campul de sursa exista deja** — nu e de adaugat, ci de pastrat vizibil: e `Ct_clb_altele`, cu
-eticheta schimbata pe tip de `do_schimba_explicatia` („Nr. contract” / „Nr. comanda” / „Nr. factura” /
-„Nr. facturi” / „Locatie”, `ofacturare.vc2:9633-9643`), eliminat azi din formular cand
-`gnScadereStoc = 0` si tipul e 1/5/10 fara copiere. La modificare e blocat: schimbarea sursei ar
-insemna alt document, nu o corectie.
-Formularul arata **identic** cu cel de introducere: fara banda de avertizare, fara coloane cu
-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; **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
-Comasarea celor trei actiuni de modificare (G-bis): la confirmare se compara starea din formular cu
-cea incarcata si se alege ruta — `modifica_date_factura` pentru antet, `modifica_explicatie_articol`
-pentru explicatia liniei, regenerare pentru orice atinge sumele, nimic daca nu s-a schimbat nimic.
-Cele trei actiuni vechi de pe `frm_facturi` (`do_modifica`, `do_modifica_explicatie`) se retrag
-abia dupa ce formularul unificat le acopera, nu inainte.
-**PROIECTAT (runda 13) — `docs\cercetare\s8b_rutarea_scrierii.md`. Reteta G-bis e corecta ca directie,
-dar avea un gol nedocumentat, si el schimba forma solutiei.**
-
-- **Cele patru rute NU sunt teste independente, ci un lant cu prioritate — sumele primele.**
- Motivul e concret: **`modifica_date_factura` nu e singura ruta care scrie cei 14 parametri de antet.**
- **Sapte din 14** (`id_delegat`, `id_masina`, `id_facturare`, `listare_detaliata`, `dataora_exp`,
- `id_agent`, `text_aditional`) sunt scrisi **si** de calea normala de emitere, prin `scrie_factura2`,
- direct din `poDate` — **verificat direct de sesiunea principala** pe apelul de la
- `COMUN\clase\ofacturare.vc2:14345-14359`. Nu exista doi proprietari ai acestor campuri: e **acelasi
- obiect `poDate`** citit de ambele cai.
-- **Deci, cand regenerarea porneste, `modifica_date_factura` NU se mai cheama.** Inainte de regenerare
- ar scrie pe randul care urmeaza sa fie sters — pierdut. Dupa, ar fi a doua scriere pe aceleasi sapte
- coloane, pe alt `ID_VANZARE`. Regenerarea **este** deja calea de scriere a antetului cand sumele se
- schimba, nu o cale care trebuie compusa cu alta.
-- **Ordinea rutarii:** (1) s-au schimbat liniile / discountul de document? → **regenerare, gata**;
- (2) altfel, antet? → `modifica_date_factura`; (3) altfel, doar explicatie de linie? →
- `modifica_explicatie_articol`; (4) altfel → **nimic**.
-- **Explicatia de linie e transportata gratuit de regenerare**, prin parametrii nativi ai lui
- `adauga_articol_factura` (`V_EXPLICATIE`, `V_TAXCODE`) — **cu conditia** ca regenerarea sa citeasca
- din cursorul curent al formularului, nu dintr-un snapshot separat.
-- **Cel mai probabil fals pozitiv al criteriului „deschid si inchid → nicio scriere":** lookup-ul
- „ultimul delegat / masina al clientului" din `frm_alte_date.Init`
- (`COMUN\clase\ferestre_cere_date.vc2:3119-3136`). E cod gandit pentru **document nou**. Pe calea de
- editare ar suprascrie delegatul **incarcat corect din document** cu ultimul folosit de client — deci
- ori documentul apare „modificat" fara ca nimeni sa fi atins nimic, ori, daca ruleaza inainte de
- snapshot, **salveaza tacit delegatul gresit**. **S8 trebuie sa-l sara explicit pe calea de editare.**
-- **Comparatia se face pe valori rotunjite la precizia de scriere** (`gnPc` / `gnPPretV` / `gnPCant`),
- nu pe valoarea binara — altfel rotunjirea singura produce diferente.
-
-**INCHIS, nu de reintrebat (marcaj pus in runda 17).** Punctul de mai jos are raspuns: **decizia 52** — `do_modifica` ramane activ pentru multi-selectie, iar formularul unificat preia doar cazul cu un singur document. Se pastreaza enuntul, nu intrebarea:
-1. **Editarea multipla** — `do_modifica` de azi lucreaza pe multi-selectie, capacitate fara echivalent
- in formularul unificat. Se accepta pierderea ei la retragere, sau `do_modifica` ramane activ separat
- exact pentru cazul asta?
-
-**Doua goluri de inchis inainte de implementare (semnalate, nu presupuse):**
-- **Ce canal scrie `serie_act` / `numar_act` / `data_act` / `data_scad` / `id_ruta` / `tip_saft` /
- `efactura`** pe documentul reemis — **nu apar in `scrie_factura2`**, deci vin pe alt drum. Raspunsul
- decide daca mai e nevoie de o scriere separata dupa regenerare. **Se inchide in S9.**
-- ~~**`cursor_retur_document` re-deriva pretul la incarcare?**~~ **INCHIS (runda 13): NU** — pretul vine
- din `VANZARI_DETALII.PRET` stocat, fara `JOIN` catre contract sau politici (`PACK_FACTURARE:3960-4062`,
- verificat direct). **Mecanismul de detectie e valid.** Detaliul despre rotunjire si `DIFERENTA` — in S10.
-
-*Gata cand:* fiecare din cele patru situatii din tabelul G-bis produce exact scrierile din tabel si
-nimic in plus; in special, deschiderea si inchiderea fara modificari nu scrie nimic.
-*Depinde de:* S8.
-
-#### S8c — Butonul comutator de antet si salvarea separata a antetului
-Decizia 9, proiectata in I. Antetul unui document existent porneste **blocat**; un singur
-`but_modifica` il deschide si isi schimba imaginea in discheta de salvare; a doua apasare cheama
-`modifica_date_factura` si **nu atinge articolele** — exact ce face azi `do_modifica`, dar din
-formularul unificat, dupa care antetul se blocheaza la loc si butonul revine la creion. **Fara nicio
-bifa**: butonul deschide tot antetul, inclusiv serie / numar / data / scadenta; cele patru bife de
-azi nu se transpun. `Termina` ramane salvarea intregului document.
-Se generalizeaza reteta de blocare din `clb_tx_data.dezactiveaza()` / `reactiveaza()`
-(`lb_tx.vc2:521-538`) la containerele de antet care azi nu au niciuna (I), si se aplica **uniform**
-tuturor campurilor de antet — asta e ce face posibila eliminarea bifelor.
-Comutarea imaginii butonului se copiaza din `frm_rulaje.se_modifica_assign` (`rulaje.vc2:4716-4773`):
-o singura instanta `but_modifica`, cu `.cpicturedown` / `.cpictureup` / `.Picture` rescrise impreuna
-si `.Refresh()` — vezi decizia 9 pentru capcana hover-ului.
-**Ce deschide efectiv butonul (decizia 25, verificat pe cod in G-bis).** „Tot antetul” nu inseamna
-ca totul se salveaza pe aceeasi ruta:
-- **cei 14 parametri** — pe loc, prin `modifica_date_factura`. Asta livreaza S8c;
-- **grupul B** (tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi) si
- **grupul C** (incasare) — **nu au ruta de scriere pe loc**, deci raman **blocate in etapa I**, cu
- explicatie la hover; se deschid in etapa II, cand modificarea lor marcheaza documentul pentru
- regenerare;
-- **grupul A** (analiticele) — **read-only permanent in #13** (decizia 26), editarea e a lui #6.
-
-Deci in etapa I butonul deschide **exact cei 14**, si asta nu e o abatere de la decizia 9, ci
-consecinta ei corecta pe starea de azi a codului: restul campurilor n-ar avea unde sa se scrie.
-*Gata cand:* se poate corecta delegatul unui document emis, salva antetul si inchide formularul,
-**fara nicio scriere in `VANZARI_DETALII` si fara recalcul de sume in note sau rulaje**; se poate
-corecta si data scadentei prin acelasi buton, fara alt control intermediar; iar un document deschis
-si inchis fara a apasa butonul nu produce nicio scriere.
-*Atentie la formularea criteriului:* „nicio scriere in note si rulaje” ar fi un criteriu imposibil —
-schimbarea seriei / numarului / datei propaga coloanele de identitate in `JV2007` si `RUL` prin
-procedura insasi (I-bis). Ce se verifica e ca **nu se ating sumele**, nu ca nu se atinge tabelul.
-*Depinde de:* S8.
-
-#### S9 — Stergerea si reemiterea intr-o singura tranzactie, cu `ID_FACT` pastrat
-Partea grea. Doua lucruri simultan:
-
-**Constrangere de la decizia 35, inainte de orice:** reemiterea **scrie prin `pack_facturare`**, pe acelasi
-drum ca emiterea (`scrie_factura2` → `contabilizeaza_articol`, cu parametrul de cont de la decizia 34).
-`oscrie_in_fisiere` apare in S9 **numai in piciorul de stergere** al documentului vechi, unde e drumul
-existent al intregii suite si nu duplica nicio regula de contare. **Nu se scrie si nu se corecteaza niciun
-rand din `ACT_TEMP` direct din VFP.** Consecinta de secventiere: **S9 nu poate porni inaintea parametrului
-deciziei 34** — nu mai exista varianta „editarea nu cere nimic in pachet".
-
-**VERIFICAT ca decizia 35 e realizabila** (`docs\cercetare\parametru_cont_contabilizeaza_articol.md`,
-sectiunea 1): pe partea Oracle, **a doua emitere a aceluiasi document merge pe cod identic**.
-`scrie_factura2` cheama `initializeaza_date_factura` (`PACK_FACTURARE:1808-1846`) la fiecare apel, iar
-aceasta face `DELETE FROM VANZARI_DETALII_TEMP` (`:1835`) si `nid_act := 0` (`:1836`) — contorul folosit
-de `scrie_nota` / `scrie_discount` / `scrie_tva` la fiecare `INSERT INTO ACT_TEMP` **porneste curat si la
-reemitere**. Nimic din `contabilizeaza_articol`, ramura noua inclusa, nu citeste vreo stare care sa
-presupuna „documentul e nou": variabilele de sesiune sunt **citite**, nu comparate cu o stare anterioara.
-**Singurul obstacol real al regenerarii e in alt pachet** — `PACK_CONTAFIN`, prin `SET_IDFACT` si
-`PK_DOCUMENTE`, exact ce e deja analizat mai jos in acest S9. Adica: „cod separat" inseamna **alta
-procedura, in alt pachet**, nu o a doua ruta de contare — deci **decizia 35 nu e contrazisa**.
-
-- **Tranzactia.** Apelul de stergere (`oscrie_in_fisiere` + `finalizeaza_stergere_nota` +
- `sterge_factura`) se muta in interiorul tranzactiei deschise de `do_scrie_articole`, inaintea
- primului `adauga_articol_factura`. Fara `commit` intermediar (`VANZARI_DETALII_TEMP` e GTT
- `ON COMMIT DELETE ROWS`). La orice eroare, rollback total.
-- **Tripleta de mai sus e si ce face ciclul NEUTRU fata de stoc — nu se simplifica.** `sterge_factura`
- **nu** reverseaza rulajele. Revenirea stocului vine din `PACK_CONTAFIN.STERGE_DIN_RUL`
- (`UPDATE RUL SET STERS = 1, ID_UTILS = ..., DATAORAS = ...`,
- `ff_2026_07_29_03_COMUN_PACK_CONTAFIN.sql:1867-1882`, apelata la `:8473`), la care se ajunge prin
- `finalizeaza_scriere_act_rul(tnScrieSterge = 2)` ← `oscrie_in_fisiere(2, ...)`. Adica **stocul e
- derivat** din miscari nesterse, iar marcarea lor `STERS = 1` inchide subiectul — dar **numai daca
- piciorul de stergere chiar trece prin `oscrie_in_fisiere`**. O implementare care „simplifica" pasul
- la un apel direct de `sterge_factura` ar lasa rulajele in picioare si reemiterea ar descarca
- gestiunea **a doua oara**, tacut. Verificat pe sursa pachetului.
- `docs\cercetare\stoc_la_stergere_si_reemitere.md`.
-- **`ID_FACT`.** Se citeste inainte de stergere (vezi capcana `STERS = 0` din E) si se impune
- documentului nou, printr-un comutator folosit **numai** de regenerare. `SET_IDFACT` nu se schimba
- neconditionat — e cod comun intregii suite.
-- **`ID_UTIL` / `DATAORA` (audit de creare, S14).** Acelasi tipar ca la `ID_FACT`: se citesc din
- documentul vechi **inainte** de stergere si se impun explicit documentului nou — altfel `INSERT
- INTO VANZARI` de la reemitere le rescrie cu utilizatorul si momentul curente, si „data/utilizatorul
- crearii" se pierde tacut. Detaliu si recomandare de coloane: S14.
-
-**VERIFICAT — se poate, dar cere TREI schimbari simultane, nu una.** Raport:
-`docs\cercetare\idfact_refolosire_si_documente.md`. Verdict: **DA, cu conditii.**
-
-1. **Varianta comentata din `SET_IDFACT` NU rezolva S9** — nu se reactiveaza.
- (`PACK_CONTAFIN.pck:3016-3035`) cauta documentul pe `NRACT + SERIE_ACT + DATAACT + ID_CTR` cu
- `STERS = 0`; dupa soft-delete `STERS` e deja 1, deci **nu-l gaseste** si cade tot pe secventa.
- In plus e vulnerabila la coliziuni cu un document viitor neinrudit care are aceleasi patru campuri.
- `ID_FACT`-ul se **citeste explicit inainte de stergere** (VFP il are in cursor) si se **transmite**.
-2. **`SET_IDFACT` are nevoie de o cale de intrare noua, inerta implicit.** Azi **nu exista niciun
- canal**: `pack_contafin.nIdFact` e scrisa neconditionat de fiecare apel, si nu exista alt global sau
- parametru de sesiune. Solutia cu suprafata minima: **variabila noua de pachet** („ID_FACT fortat",
- implicit `NULL`), citita **doar in corpul activ** al lui `SET_IDFACT`, consumata si resetata la prima
- folosire. **Nu se atinge semnatura `SET_IDFACT(V_GCS)`** — altfel s-ar schimba apelul pentru toti.
-3. **Blocajul real nu e in `SET_IDFACT`, ci in `DOCUMENTE`** — si asta e descoperirea care schimba
- estimarea. Scrierea de azi (`PACK_CONTAFIN.pck:796-817`) e un **`INSERT` simplu** pe `ID_DOC`, care e
- **PRIMARY KEY** (`PK_DOCUMENTE`, `fn_script.sql:5192-5198`). Stergerea (`STERGE_DIN_ACT:1835-1855`) e
- **soft-delete pur** — randul vechi ramane fizic in tabel cu `STERS = 1`. Deci reemiterea cu acelasi
- `ID_FACT`, cu codul de azi, **arunca `ORA-00001`**. Dovada, nu presupunere.
- `MERGE`-ul deja comentat (`:818-847`) **nu ajuta**: are doar `WHEN NOT MATCHED`, deci ar ignora tacit
- randul existent si documentul reemis ar ramane cu `STERS = 1`. E nevoie de **upsert real**, cu
- `WHEN MATCHED THEN UPDATE SET STERS = 0, ...` pe restul coloanelor de identitate.
-
-**Succesiunea corecta**, in aceeasi tranzactie: citeste `ID_FACT` **si lista sursa** -> sterge documentul
-vechi (soft-delete, ca azi) -> seteaza variabila fortata -> scrie documentul nou pe drumul obisnuit ->
-**remigreaza atasamentele** -> commit doar daca toate au reusit; orice eroare -> rollback total,
-documentul vechi intact.
-
-**DOI PASI ADAUGATI DE S11 (runda 13) — niciunul nu „vine gratis" din drumul normal:**
-1. **Citirea listei sursa INAINTE de stergere, si refurnizarea ei la reemitere.** `VANZARI_CORESP` si
- `marcheaza_facturat` **se rescriu singure** prin `CASE`-ul pe `ntip` din `finalizeaza_factura` — dar
- **numai daca** `ntip` si lista sursa (`clistaid` / `clistaid_avize`) sunt refurnizate. Ele traiesc in
- randurile `VANZARI_CORESP` ale documentului **vechi**, care dupa stergere nu mai sunt disponibile.
- **Fara acest pas nu apare nicio eroare — corespondenta si `FACTURAT` pur si simplu nu se scriu.**
- Scriere lipsa silentioasa, exact tipul de defect care trece de o verificare vizuala.
-2. ~~**`UPDATE ATASAMENTE_VANZARI SET id_vanzare = :nou`**~~ — **INLOCUIT de decizia 53 (runda 14):
- atasamentele NU se remigreaza, se sterg la reemitere.** Documentul reemis porneste curat; PDF-ul se
- regenereaza la prima listare. Pasul ramane **cod nou**, dar e o **stergere**, nu un `UPDATE`
- (`STERS = 1`, ca sa ramana consistent cu view-ul `VATASAMENTE_VANZARI`, care filtreaza `b.sters = 0`
- — vezi S11). Consecinta acceptata explicit de Marius: **urma PDF-ului efectiv trimis clientului
- dispare din sistem.**
-
-**Suprafata de risc pentru suita**, masurata: **~25-30 cai de apel** — cate o copie a lui
-`COMUN\programe\oscrie_in_fisiere.prg` in fiecare produs ROA, plus trei variante care cheama
-`SCRIE_IN_ACT` direct. Toate converg in acelasi punct, `SET_IDFACT(V_GCS)`. **Garantia e structurala,
-nu prin inspectie:** cu variabila implicit `NULL` si citita strict local, toate cele ~25-30 de cai raman
-identice cu azi — nu trebuie verificat fiecare apelant.
-**Dar `INSERT` -> `MERGE` in `DOCUMENTE` e cod comun apelat de toata suita.** Practic ramura noua e
-inerta (secventa e monoton crescatoare, `WHEN MATCHED` nu se declanseaza niciodata pe drumul normal),
-**dar se testeaza un ciclu normal de scriere in fiecare produs care scrie facturi sau note**, nu doar in
-ROAFACTURARE.
-
-*Gata cand:* o editare care mareste cantitatea peste stocul curent trece (stocul documentului
-initial e eliberat inainte); documentul reemis are **acelasi `ID_FACT`, serie, numar si data** ca
-inainte; **randul din `DOCUMENTE` e acelasi, revenit la `STERS = 0`**, nu unul nou; o eroare la scriere
-lasa documentul initial intact; si un ciclu normal de scriere ramane neschimbat in celelalte produse.
-*Depinde de:* S8b.
-
-#### S10 — Pretul care nu trebuie re-derivat
-Inventarul ramurilor din `adauga_articol_factura` (H) si, unde e nevoie, un mod in care preturile
-vin din formular.
-
-**VERIFICAT (runda 9) — `docs\cercetare\s10_pret_rederivat.md`. Verificarea 3 e inchisa.**
-**Exista exact o ramura care suprascrie pretul: contractul.** Cu `OPT_FACTURARE = 3` (sau `NULL`, care
-se implicit-eaza tot la 3), daca `CTR_ARTICOLE.PRET_UNITAR` e diferit de 0, acea valoare **inlocuieste**
-pretul trimis de VFP — `DECODE(A.PRET_UNITAR, 0, V_PRET_TEMP, A.PRET_UNITAR)` — necondiționat de faptul
-ca linia a fost sau nu atinsa pe ecran. Procedura **nu are nicio notiune de „reemitere"**: la fiecare
-apel cu acelasi `V_ID_CTR` se reface derivarea din contract. Pe celelalte ramuri (implicita, restaurant)
-pretul trimis de VFP e respectat ca atare. **Nu exista niciun parametru sau flag care sa opreasca
-re-derivarea** — deci S10 nu poate „cere pachetului sa nu re-derive", trebuie sa lucreze in jurul
-ramurii de contract. Riscul se materializeaza doar cand pretul din contract s-a schimbat intre emitere
-si reemitere; pana atunci rezultatul e identic si nimeni nu observa. Detaliile pe discount, TVA si curs
-sunt in sectiunile 6 si 7 ale raportului.
-**PROIECTAT (runda 13) — `docs\cercetare\s10_pret_contract_reemitere.md`. Faptul portant al rundei 9
-se reconfirma la sursa, dar problema e mai larga decat „pretul".**
-
-- **Nu e doar pretul: acelasi `SELECT` de pe ramura de contract alimenteaza CINCI valori.**
- **Verificat direct de sesiunea principala** (`PACK_FACTURARE:5149-5166`): `DECODE(A.PRET_UNITAR, 0,
- V_PRET_TEMP, A.PRET_UNITAR)` **impreuna cu** `B.PROC_TVAV`, `B.ID_VALUTA`, `A.PRET_CU_TVA` si
- `C.IN_STOC` intra in aceeasi interogare. Raportul semnalase trei (pret, TVA, valuta); sunt **cinci** —
- se adauga flagul „preturi cu TVA" si **gestionabilitatea**, care vine din **nomenclatorul curent**,
- nu din document. **Orice garda trebuie sa acopere tot setul**, nu doar pretul.
-- **Nu exista alt loc care suprascrie pretul mai departe in lant** — `scrie_in_vanzari` copiaza `PRET`
- neschimbat din `VANZARI_DETALII_TEMP` in `VANZARI_DETALII`.
-- **Divergenta e reala, nu ipotetica:** pe baza de dezvoltare, **3 din 11** linii deja facturate pe
- contract au azi alt pret in contract decat cel facturat. Esantionul e mic si **nu se extrapoleaza** la
- productie — dar demonstreaza ca situatia se intampla.
-- **Discountul ramane passthrough** — acolo nu e nicio problema.
-- **Recomandarea raportului: varianta (c) — se avertizeaza si se cere confirmare, cu diferenta
- afisata.** Satisface literal criteriul „decis explicit, nu accidental", se implementeaza **integral in
- VFP**, fara sa se atinga `pack_facturare`. Variantele: (a) accepta tacit — respinsa, e exact ce cere
- criteriul sa nu se intample; (b) blocheaza — mai sigura, dar frustranta daca divergentele sunt dese;
- (d) ocoleste ramura trimitand `V_ID_CTR = NULL` — **respinsa motivat**, pierde **permanent** legatura
- `VANZARI_DETALII.ID_CTR`.
-- **„Reemitere identica" nu e garantata uniform:** pe ramurile `ELSE` / restaurant, da; pe **comenzi**
- esueaza **tare** (eroare, deci vizibila); pe **contract** si pe **aviz (`ntip = 4`)** esueaza **tacit**.
- Riscul pe aviz **nu fusese semnalat pana acum** ca decizie explicita.
-
-**GOLUL LUI S8b E INCHIS — `cursor_retur_document` NU re-deriva pretul.** Verificat direct de sesiunea
-principala (`PACK_FACTURARE:3960-4062`): pretul vine din **`VANZARI_DETALII.PRET`** stocat, printr-un
-`FROM VANZARI_DETALII A1` fara niciun `JOIN` catre `CTR_ARTICOLE` sau catre politici; `PROC_TVAV` la fel,
-din document. **Deci mecanismul de detectare a schimbarii din S8b e valid** — un document deschis nu
-apare „modificat" din cauza citirii. **Confirmat independent si pe partea VFP** (raportul S10): in
-`ofacturare.prg:266-283`, ramura `Case m.llCopiere` are **prioritate indiferent de tip** — pentru un
-document de contract (`2,6,26,52`) **nu se ajunge deloc** la `cursor_contract` la incarcare. Citirea si
-scrierea sunt guvernate de **cursoare complet diferite, fara cod comun**: riscul de suprascriere tacita
-apare **strict la re-scriere**, niciodata la deschidere. O garda pusa la scriere nu afecteaza citirea si
-nu e afectata de ea.
-> **Dar citirea nu e o copie curata, si asta conteaza pentru S12.** Pretul returnat e
-> `ROUND(A.PRET, nzecimale_pretv) + A.DIFERENTA` (pe valuta: `ROUND(CURS * ROUND(PRET, ...) /
-> MULTIPLICATOR, ...) + DIFERENTA`). Adica **rotunjit la precizia de sesiune si cu `DIFERENTA` pliata
-> inauntru**. La reemitere se trimite inapoi valoarea pliata, deci **impartirea `PRET` / `DIFERENTA` se
-> reface**, nu se conserva. De verificat in S12 ca o reemitere identica reproduce **suma**, chiar daca
-> nu reproduce neaparat aceeasi impartire — si ca `DIFERENTA` nu se acumuleaza la reemiteri repetate.
-
-### RASTURNAT de decizia 54 (Marius, runda 14) — nu garda, ci eliminarea re-derivarii
-
-Cele trei intrebari de mai sus (blocare vs. avertizare; ramura de aviz; masurarea frecventei) **sunt
-inchise, si nu prin alegerea uneia dintre variante — prin respingerea premisei lor.** Formularea lui
-Marius: *„nu inteleg de ce se schimba valorile fata de ce se incarca din factura sursa care se modifica?
-asta este comportamentul pe care il doresc — modific sursa"*.
-
-**Deci:** la reemitere se scriu **valorile din formular** (incarcate din documentul editat), nu se
-reciteste sursa. Nu se cere utilizatorului sa confirme o schimbare pe care n-a cerut-o. Variantele
-(b) si (c) **cad amandoua**; ramane obiectivul (a-invers): re-derivarea, unde exista pe calea de
-reemitere, se **elimina**.
-
-**Si aici e problema reala, spusa pe fata:** runda 9 a stabilit deja ca **„nu exista niciun parametru
-sau flag care sa opreasca re-derivarea"**, iar singura varianta care ocolea ramura — (d), `V_ID_CTR =
-NULL` — a fost **respinsa motivat**, pentru ca pierde permanent legatura `VANZARI_DETALII.ID_CTR`.
-Prin urmare decizia 54 **cere, cel mai probabil, o modificare in `pack_facturare`** (un semnal „nu
-re-deriva, foloseste ce ti-am trimis" pe `adauga_articol_factura`), nu o solutie curat VFP. Asta atinge
-un pachet din `COMUN`, partajat de toata suita — **iar modificarile de pachet se aplica tuturor
-deodata, fara cale de intoarcere prin alegerea de la decizia 49.** Trebuie proiectata ca inerta pentru
-apelantii de azi (implicit = comportamentul actual), exact ca la S4g.
-
-**VERIFICAT in runda 14 — `docs\cercetare\s10_rederivare_pe_calea_reemiterii.md`.** Confirmat pe fisier
-**si** pe DB (`all_source`, corp VALID, `last_ddl_time = 2026-08-09 20:03:50`).
-
-**Se pierd intr-un SINGUR loc:** `adauga_articol_factura`, in `CASE`-ul de la `PF:5052-5220`, adica
-**inainte** de `INSERT INTO VANZARI_DETALII_TEMP` (`PF:5222`). Tot ce urmeaza — copierea temp →
-`VANZARI_DETALII` (`PF:13705-13757`) — e **1:1**, deci „copiaza `PRET` neschimbat" e adevarat dar **nu
-e o protectie**: dauna e amonte de temp.
-
-**RAMURILE CARE RE-DERIVA SUNT TREI, NU UNA. Raportul rundei 9 gresea.**
-
-| valoare | **contract** (2/6/26/52) | **aviz** (`ntip = 4`) | **comenzi** (3/21/28/42/47) | restaurant (45) | `ELSE` |
-|---|---|---|---|---|---|
-| `PRET` | re-derivat din `CTR_ARTICOLE.PRET_UNITAR` daca `<> 0`; temp daca `= 0`; **NULL daca e NULL** (`PF:5149`) | **re-derivat neconditionat** din avizul sursa (`PF:5082`) | temp de facto — `WHERE A.PRET = V_PRET_TEMP` (`PF:5077`) | temp | temp |
-| `PROC_TVAV` | re-derivat din `CRM_POLITICI_PRET_ART` | re-derivat din aviz | re-derivat din `COMENZI_ELEMENTE.PTVA` | derivat din `JTVA_COLOANE` | derivat din `JTVA_COLOANE` pe `ID_JTVA_COLOANA` **din formular** |
-| `ID_VALUTA` | re-derivat | re-derivat | re-derivat | temp | temp |
-| `PRET_CU_TVA` | re-derivat | re-derivat | re-derivat | temp | temp |
-| `IN_STOC` | re-derivat din `NOM_ARTICOLE` | re-derivat | re-derivat | temp | temp |
-
-- **Ramura AVIZ e cea mai agresiva din tot `CASE`-ul** (`PF:5080-5103`): `PRET` se inlocuieste
- **neconditionat**, nu exista nici `DECODE`, nici `AND A.PRET = V_PRET_TEMP`, **si nu exista bloc
- `EXCEPTION`**. Un pret modificat pe ecran e inlocuit tacit. In plus **nu filtreaza `A.STERS = 0`**,
- desi coloana exista — linii sterse ale avizului sursa pot fi citite. Si depinde de `clistaid`, care
- la reemitere **trebuie repopulata** (leaga direct de pasul 1 adaugat in S9).
-- **Ramura comenzi esueaza tare, nu tacit** — fara `EXCEPTION`, o linie care nu se mai potriveste da
- **ORA-01403**, vizibila. Mai putin periculoasa, dar tot re-derivare.
-- **Ramura contract are o portita** — `EXCEPTION WHEN NO_DATA_FOUND` (`PF:5167-5185`) pune **toate cele
- cinci** pe valorile din formular. **Comportamentul cerut de decizia 54 exista deja in cod**, dar
- numai pe calea de exceptie. Aviz si comenzi **nu au** asa ceva.
-- **Capcana NULL, dedusa din semantica `DECODE`, nerulata:** daca `CTR_ARTICOLE.PRET_UNITAR` e `NULL`
- (nu `0`), `DECODE` nu potriveste literalul `0` → rezultatul e **NULL**, deci pretul din formular se
- pierde complet si linia intra cu `PRET` gol. In dev cazul nu apare (27 randuri, 0 NULL) — **ceea ce
- nu spune nimic despre productie**.
-- **`PROC_TVAV` nu vine din formular pe NICIO ramura** — nu e parametru al procedurii. Pe calea „buna"
- se deriva din `JTVA_COLOANE` pe `ID_JTVA_COLOANA`-ul trimis de formular, deci reproduce documentul
- **doar cat timp cota nu s-a schimbat**. La o modificare legala de cota, reemiterea schimba TVA-ul
- **chiar si pe `ELSE`**.
-- **`IN_STOC` nu ajunge in `VANZARI_DETALII`** — coloana nu exista (verificat pe DB). Traieste doar in
- temp, unde decide **descarcarea de gestiune**.
-- **Dupa insertul in temp nimic nu mai suprascrie cele cinci valori.** `adauga_diferente_pret` atinge
- numai `DIFERENTA`, `scrie_factura_avize` numai `CANTITATE`, `scrie_seturi` numai `ID_VANZARE_SET`.
-
-### Cum se implementeaza decizia 54
-
-**Curat VFP nu se poate — confirmat cu dovada pozitiva, nu prin absenta.** Semnatura n-are comutator
-(`PF:4989-5015`, 27 de parametri, toti date de linie); globalele pachetului n-au (`PF:126-212`); poarta
-`CASE`-ului se decide pe `ntip` (care ajunge in `VANZARI.TIP`, deci nu se poate falsifica) si pe
-`CONTRACTE.OPT_FACTURARE` (date de contract, nu parametru). Singurele parghii VFP care ar devia pe
-`NO_DATA_FOUND` sunt `V_ID_CTR = NULL` — **deja respinsa** — si `V_ID_POL = NULL`, care are **exact
-acelasi defect pe alta coloana** (`PF:5258` → `temp.ID_POL` → `PF:13737` → `VANZARI_DETALII.ID_POL`) si
-in plus ar rupe ramura aviz, care potriveste pe `A.ID_POL`. **Notata aici tocmai ca sa nu fie
-redescoperita ca „solutie" intr-o runda urmatoare.**
-
-**Deci decizia 54 cere obligatoriu modificare in `pack_facturare`** — dar mica, si care nu adauga
-comportament nou:
-
-- **Semnalul:** variabila noua de pachet („regenerare in curs"), implicit `0` = comportamentul de azi,
- scrisa de VFP **dupa** `initializeaza_date_factura` (`ofacturare.vc2:13981`) si inainte de bucla de
- `adauga_articol_factura`. *Recomandata* fata de un parametru `DEFAULT 0`, din trei motive: se
- potriveste cu stilul pachetului (deja o punga de stare de sesiune); se scrie o data pe document, nu
- o data pe linie, in toate produsele; si **punctul de resetare exista deja** —
- `initializeaza_date_factura` (`PF:1808-1917`) reinitializeaza ~40 de globale si goleste temp
- (`PF:1835`), deci flag-ul nu poate scapa in documentul urmator.
-- **Ce face:** un `WHEN` nou, **primul** in `CASE`-ul de la `PF:5052`, cu **acelasi corp ca `ELSE`-ul de
- azi** (`PF:5189-5203`). Nimic inventat — se forteaza ramura care exista deja. **Acopera dintr-o data
- toate trei ramurile problematice**, fiind in acelasi `CASE`. `INSERT`-ul de la `PF:5222` ramane
- neatins.
-- **Inert prin constructie** pentru toti apelantii de azi, exact ca la S4g. **Consecinta de livrare:
- DB inainte de EXE.**
-
-### Trei consecinte de acceptat explicit, nu de descoperit la S12
-
-1. **`IN_STOC` ar veni din formular.** Nu murdareste documentul (coloana nu exista), dar schimba
- **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
- exact asta, dar e schimbare de comportament — **se declara, nu se descopera**.
-3. **`PROC_TVAV` ramane derivat, nu preluat.** Reproducerea exacta cere ca S8 sa pastreze
- `ID_JTVA_COLOANA` **si** ca `JTVA_COLOANE` sa nu se fi schimbat. Daca se cere reproducere exacta si
- peste o modificare legala de cota, `PROC_TVAV` trebuie sa devina **parametru** — schimbare mai mare
- decat flag-ul, **de decis separat**.
-
-### Obstacol pentru S9, gasit in treacat
-
-**`VVANZARI_ARTICOLE` nu expune `ID_POL` si nu expune `ID_CTR`** (lista de coloane interogata pe DB) —
-exact cei doi pe care `adauga_articol_factura` ii cere (`V_ID_POL`, `V_ID_CTR`) si pe care
-`VANZARI_DETALII` ii pastreaza. **Reemiterea nu poate folosi acest view ca atare**: ori se completeaza
-view-ul, ori loader-ul citeste direct din `VANZARI_DETALII`. Se leaga de intrebarea 1 din S8 (canalul de
-citire a liniilor) — **un argument in plus pentru varianta (B), procedura noua.**
-
-*Gata cand:* pentru fiecare tip, documentul reemis are **exact valorile din formular** — pret, TVA,
-valuta, flag „preturi cu TVA" — iar o reemitere fara modificari reproduce documentul identic, inclusiv
-dupa ce pretul din contract s-a schimbat intre timp.
-*Depinde de:* S9.
-
-#### S11 — Legaturile care raman pe `ID_VANZARE`
-`ID_FACT`, seria, numarul si data se pastreaza (E, F), deci legaturile prin `ID_FACT` sunt in
-regula. Ramane discontinuitatea pe **`ID_VANZARE`**, care se schimba: `ATASAMENTE_VANZARI`,
-`marcheaza_facturat`, `vanzari_coresp`, si eventualele referinte de incasari / plati.
-De verificat si daca `DOCUMENTE` primeste un al doilea rand pe acelasi `ID_DOC` sau il refoloseste.
-
-**PROIECTAT (runda 13) — `docs\cercetare\s11_legaturi_id_vanzare.md`. Inventarul s-a facut prin
-FK-urile reale din Oracle, nu prin grep — si asta a scos doi consumatori pe care nicio cautare de text
-nu-i gasise.**
-
-- **Premisa centrala, corectata: mecanismul lui #6 NU se mosteneste de S9.** La #6, documentul isi
- **pastreaza randul** din `VANZARI` — `actualizeaza_vanzari` face `UPDATE ... SET COD = nou,
- STERS = 0`, deci **`ID_VANZARE` nu se schimba**, doar `COD`, si atasamentele se realiniaza in acelasi
- gest. La S9, reemiterea merge pe drumul normal de emitere (`INSERT ... RETURNING ID_VANZARE`), deci
- **rand nou, cheie noua, si `actualizeaza_vanzari` nu se declanseaza deloc.** Tot ce e protejat azi
- tacit de #6 e **expus** la regenerare. Asta nu era in plan.
-- **Sapte tabele au FK declarat pe `VANZARI.ID_VANZARE`. Doua nu erau in nicio lista:**
- **`REST_NOTE_PLATA`** (modul restaurant) si **`IPS_VOYAGES_VANZARI`** (modul specific unui client).
- Clasificate **(A) suspecte** — pachetele lor PL/SQL n-au fost citite integral.
- **INCHIS de Marius, runda 14 — riscul dispare, si nu prin presupunere.** Intrebat direct, a raspuns:
- *„daca este vorba despre facturarea voiajelor din ROAACNPRO, acolo nu merge modificarea de genul
- acesta, ci doar editarea de la #6"*. **Documentele acestor module sunt IN AFARA domeniului
- regenerabil al #13** — pentru ele ramane calea #6 (modificare pe loc). Pachetele lor **nu mai trebuie
- citite**. Doua consecinte de dus mai departe: **(a) garda lui S7 trebuie sa le refuze EXPLICIT**, nu
- doar sa nu le trateze — altfel „in afara domeniului" e o intentie, nu o garantie; **(b)** conditia se
- declara in S13, la actualizarea `tipuri_documente_facturare.md`.
-- **`ATASAMENTE_VANZARI` — corectie de premisa, in favoarea noastra.** **Nu** sunt documente incarcate
- de utilizator: sunt **PDF-uri auto-generate la listare** (`poDate.scrieAtasamente()` dupa
- `export2pdf`; cursorul nu vine din niciun dialog de fisier — cautat explicit, zero potriviri). Deci
- **nu e pierdere ireparabila**, cum presupusese briefingul. Se rup totusi real: view-ul
- `VATASAMENTE_VANZARI` filtreaza pe `b.sters = 0`, deci dupa regenerare atasamentele vechi **dispar
- tacit** din toate interogarile (inclusiv din ROAGEST / ROAIMOB), desi BLOB-ul ramane fizic.
- ~~**(A) — remigrare printr-un simplu `UPDATE ... SET id_vanzare = :nou`**~~ — **INCHIS altfel,
- decizia 53 (runda 14): se STERG la reemitere.** Marius a ales a treia varianta, nici remigrare, nici
- marcaj „versiune inlocuita". Documentul reemis porneste curat. **Consecinta i-a fost spusa explicit
- si a acceptat-o:** motivatia care sustinea remigrarea — *pastrarea urmei PDF-ului trimis clientului* —
- **cade odata cu ea**; dupa editare nu mai exista in sistem dovada a ce a primit clientul. Punctul 15
- se inchide aici.
-- **Incasarile si platile nu sunt afectate — si dovada e structurala, nu statistica:** niciun tabel de
- incasari/plati n-are FK pe `ID_VANZARE`, si nici referinta text. Se leaga prin **`ID_FACT`**, care se
- pastreaza. **(C)**, cu dovada dubla.
-- **eFactura, `DOCUMENTE`, listarile, `VANZARI_CANTITATI` — (C)**, toate cheiate pe `ID_FACT` sau
- rescrise automat.
-
-**INCHISE, nu de reintrebat (marcaj pus in runda 17).** Punctul 1 e transat de cercetarea garzilor din runda 14 (garda exista si e corecta; S7 o muta in pre-flight read-only) — ramane **limitare declarata**. Punctul 2 e rasturnat de **decizia 53**: atasamentul vechi **nu se remigreaza, se sterge**, deci premisa „factura editata ajunge cu PDF-ul vechi" nu se mai produce. Punctul 3 e inchis in runda 14, cu cerinta ca **S7 sa refuze explicit** cele doua tipuri. Se pastreaza ca inventar:
-1. **Editarea unui document care are deja retur emis pe el e azi BLOCATA, nu doar riscanta** —
- `sterge_factura` arunca `ORA-20000`. Garda e corecta (protejeaza lantul), iar **S7 planifica deja
- sa semnaleze conditia inainte de intrarea in formular**, nu ca eroare Oracle la final. Ce ramane de
- decis: se accepta ca **limitare declarata** (utilizatorul sterge intai documentele-copil), sau se
- vrea alt comportament?
-2. **Atasamentul vechi arata continutul dinainte de editare.** Remigrat pe documentul nou, factura
- editata ajunge sa aiba atasat PDF-ul **vechi**. De decis daca asta e exact ce se vrea (audit trail),
- sau daca vechiul ar trebui marcat cumva ca „versiune inlocuita".
-3. **`REST_NOTE_PLATA` / `IPS_VOYAGES_VANZARI`** — de confirmat ca tipurile lor sunt in afara
- domeniului regenerabil.
-
-*Gata cand:* documentul reemis se regaseste corect in borderoul eFactura, in listari, in atasamente
-si in rapoartele care il cauta dupa numar.
-*Depinde de:* S9.
-
-#### S12 — Test pe fluxul real, regenerarea
-Cate un caz pe fiecare sursa, rulat de doua ori (o data fara modificari — reemitere identica, o data
-cu modificari de cantitate, pret si linii adaugate / sterse). Se verifica: documentul initial
-`sters = 1` cu nota si rulajele lui, documentul nou corect, sursa eliberata **si** reconsumata
-(comanda redevine facturabila si redevine facturata), stocul corect dupa ciclu, totalurile
-denormalizate din `VANZARI`, si ca o reemitere identica produce **exact** aceleasi sume.
-
-**Probe adaugate de runda 13:**
-- **Reemitere repetata de trei ori pe acelasi document** — `DIFERENTA` **nu se acumuleaza**. Motivul:
- `cursor_retur_document` intoarce pretul deja **rotunjit si cu `DIFERENTA` pliata inauntru** (S10), iar
- reemiterea trimite inapoi valoarea pliata, deci impartirea `PRET` / `DIFERENTA` se **reface** la
- fiecare ciclu. Se verifica **suma**, nu impartirea — dar se verifica si ca impartirea nu deriveaza.
-- **„Reemitere identica" nu e garantata uniform** (S10): pe `ELSE` / restaurant da; pe **comenzi**
- esueaza **tare** (eroare vizibila); pe **contract** si pe **aviz (`ntip = 4`)** esueaza **tacit**.
- Fiecare din cele patru situatii isi are cazul lui de test, cu rezultatul asteptat **declarat dinainte**
- — inclusiv cele care trebuie sa dea eroare.
-- **Deschid si inchid fara sa modific nimic → nicio scriere** (S8b), rulat pe un document al unui client
- **cu activitate recenta** — cazul in care lookup-ul „ultimul delegat / masina" ar polua antetul.
-
-*Depinde de:* S10, S11.
-
-#### S14 — Audit: creare, modificare si stergere pe document
-
-**Cerinta (decizia 63):** pentru fiecare document, sase informatii de audit — data + utilizator
-pentru creare, pentru modificare (daca e cazul) si pentru stergere (daca e cazul).
-
-**Cercetarea s-a terminat** — `docs\cercetare\audit_vanzari_creare_modificare_stergere.md`.
-Verificat pe `all_tab_columns` (`ROA_CENTRAL`, schema live) si pe cod.
-
-**Ce exista deja, pe `VANZARI`:**
-- `ID_UTIL` + `DATAORA` — **creare**, ambele `NOT NULL`, scrise consecvent la fiecare `INSERT`
- (`PACK_FACTURARE.scrie_in_vanzari`, `EXPORT:13598-13640`, si a doua ruta din
- `finalizeaza_avize_lucrare`, `EXPORT:14930`). Niciun `UPDATE VANZARI SET ID_UTIL/DATAORA` in tot
- pachetul (cautare directa, zero rezultate).
-- `ID_UTILS` + `DATAORAS` — **stergere**, nullable, scrise consecvent de `sterge_factura`
- (`EXPORT:5496-5499`) si `sterge_proforma`.
-- (neceruta, dar arata conventia) `ID_UTILFACT` + `DATA_FACTURAT` — facturare din aviz.
-- Pe `VANZARI_DETALII`: acelasi tipar de creare/stergere, plus `ID_UTIL_VALID` + `DATAORA_VALID`
- (validare).
-
-**Conventia casei:** o pereche utilizator + data per eveniment. Patru din cele sase informatii
-cerute exista deja si se scriu consecvent.
-
-**Ce lipseste, integral:** nicio coloana de **modificare**, nici pe `VANZARI`, nici pe
-`VANZARI_DETALII`. Interogat explicit `all_tab_columns` cu filtru pe `%MODIF%` — zero rezultate.
-`DATA_ACT` nu e echivalentul: e data contabila, propagata in `ACT`/`DOCUMENTE`/`JV2007`/`RUL`
-(verificat in `modifica_date_factura`, `EXPORT:14439-14500`), nu un marcaj de audit.
-
-**Capcana, si e miezul povestii:** editarea din #13 se face prin stergere + reemitere (S9), iar
-documentul nou se scrie pe **acelasi `INSERT`** ca o creare normala (`scrie_in_vanzari`). Fara un
-pas explicit, `ID_UTIL` / `DATAORA` ale documentului reemis ar deveni tacut utilizatorul si data
-**modificarii**, iar informatia despre creare s-ar pierde — exact ce cere decizia 63 sa nu se
-intample. **Precedentul de rezolvare exista deja in plan, pentru `ID_FACT`** (sectiunea „E.
-`ID_FACT`", linia 762, si S9: se citeste din documentul vechi inainte de stergere si se impune
-celui nou). **Niciun pas echivalent nu e proiectat azi pentru `ID_UTIL` / `DATAORA`** — cautare
-directa in tot planul, zero mentiuni.
-
-**Atenuare, nu solutie:** la regenerare randul vechi ramane cu `STERS = 1` si cu `ID_UTILS` /
-`DATAORAS` completate — iar acea stergere **este** momentul modificarii. Cum `ID_FACT` se pastreaza
-peste regenerare, lantul vechi → nou e parcurgibil, deci o parte din istoric e reconstruibila din
-randurile existente, fara coloane noi. O pereche explicita pe documentul curent ramane insa
-preferabila: se citeste direct, fara parcurgerea lantului.
-
-**Complicatie reala, verificata pe cod livrat de #6:** editarea de linie
-(`COMUN\programe\ofacturare_editare.prg`) scrie `id_utils` / `dataoras` pe `VANZARI_DETALII` si pe
-randuri care **nu sunt sterse** — `ofacturare_editare.prg:492-494` (corect, cu `sters = 1`),
-`:501-505` (odata cu `sters = 0`, pe rand viu) si `:522-525` (pe un rand proaspat inserat). Acolo
-perechea de stergere e folosita ca marcaj „cine a umblat ultima data", nu strict ca „sters de/la".
-**Consecinta:** un raport de audit nu poate citi `ID_UTILS` / `DATAORAS` ca „sters de/la" fara sa
-puna si `STERS` in conditie. `ofacturare_editare.prg` e perimetrul lui #6, in lucru — semnalat aici,
-neatins.
-
-**Recomandare (de confirmat, nu decisa):**
-1. **O singura pereche noua pe `VANZARI`**, urmand conventia casei — nume propus
- `ID_UTILM` / `DATAORAM` (utilizator si data ultimei modificari). Numele e de confirmat.
-2. **La regenerare (S9): `ID_UTIL` / `DATAORA` se transporta din documentul vechi in cel nou**,
- exact ca `ID_FACT` — vezi nota adaugata la S9. Perechea noua de modificare primeste utilizatorul
- curent si `sysdate`. Fara acest pas, creare si modificare se suprapun.
-3. **Perechea de stergere nu are nevoie de nimic** — exista si e scrisa consecvent.
-4. **Cere migrare de DB** (`ALTER TABLE` pe `VANZARI`) — **DB inainte de EXE**, ca la S10. Scriptul
- intra in `D:\ROA\DATABASE\SCRIPTURI_CLAR\`, `versiune_db.txt` se bumpeaza.
-
-**De decis cu Marius — AMBELE INCHISE prin decizia 65 (runda 16):**
-- **(a)** Auditul e cerut numai pe antet (`VANZARI`) sau si pe linii (`VANZARI_DETALII`)? **Raspuns
- prin deductie, nu spus explicit de Marius:** locul de afisare ales de el e gridul din `frm_facturi`,
- care listeaza **documente** — deci auditul e pe **antet**.
-- **(b)** Se afiseaza undeva in interfata (formular / lista), sau ramane doar pentru interogare?
- **Da, se afiseaza** — in **gridul din `frm_facturi`**, nu in formularul facturii propriu-zise.
- Prim pas de implementare: inventarul acelui grid, posibil sa existe deja coloane de audit.
-
-*Gata cand:* documentul reemis pastreaza `ID_UTIL` / `DATAORA` ale creatiei originale; perechea noua
-de modificare e completata la fiecare regenerare, cu utilizatorul si momentul curente; perechea de
-stergere ramane neschimbata fata de azi; migrarea DB e aplicata inainte de EXE.
-*Depinde de:* S9.
-
-#### S13 — Diff, review, changelog, documentatie
-
-**Atentie: S13 NU e momentul in care se face review-ul.** Conform metodei de executie, **fiecare story
-isi are propriile teste, propriul diff si propriul code review, inainte de commit-ul ei** — S13 nu
-strange la final ce n-a fost revizuit pe parcurs. Ce ramane aici e **inchiderea**, adica exact ce nu se
-poate face per story:
-
-- **Review de ansamblu**, pe suma povestilor: coerenta intre ele, cai ramase orfane, cod mort din
- fluxul vechi care trebuia retras si n-a fost, si verificarea ca alegerea de la decizia 49 chiar
- functioneaza in ambele sensuri.
-- **Changelog** `:nou:`, cu mentiunile declarate explicit pe parcurs: asimetria `do_modifica`
- corectata prin recalculul la cerere (decizia 45), si faptul ca `do_modifica` ramane activ pentru
- multi-selectie (decizia 52).
-- **Documentatie**: `COMUN\docs\tipuri_documente_facturare.md` — ce tipuri sunt regenerabile si ce
- tipuri sunt **declarate explicit ca neacoperite** (48/49 si `frm_facturare_articole2`, daca se merge
- pe recomandarea din S8), plus confirmarea din S11 pentru `REST_NOTE_PLATA` si `IPS_VOYAGES_VANZARI`.
-- **Rularea suitei complete** — toate testele scrise per story, la un loc, nu doar cele ale ultimei
- povesti.
-- **Commit-urile finale**, in **ambele** repo-uri (ROAFACTURARE si COMUN), dupa aprobare.
-
----
-
-## Riscuri
-
-- ~~**Cel mai mare: perimetrul comun cu #6.**~~ **Inchis prin decizia 30** — implementarea lui #13
- incepe dupa terminarea lui #6, deci nu exista doi scriitori simultan pe `ofacturare_comun.vc2` /
- `ofacturare_editare.prg`. Riscul revine doar daca ordinea se schimba.
-- ~~**Riscul „cod nou in `pack_facturare`" e evitat prin constructie (decizia 27-bis).**~~ **Caduc dupa
- deciziile 34 si 35, si riscul revine ca risc principal.** Politica tehnica per `SCC` si scrierea in
- `CRM_POLITICI_PRET_ART` nu se mai fac — deci cade si riscul ca o politica tehnica sa apara in
- `caut_politici_curente_util()`. In locul lui: **`pack_facturare` se modifica** (parametru de cont +
- ramura fara politica in `contabilizeaza_articol`), iar pachetul e **comun intregii suite** — ROACONT,
- ROAGEST, ROACONTRACTE, ROAAUTO, ROAACNPRO. Mitigarea e structurala, nu prin inspectie: parametru
- **`DEFAULT NULL` la finalul listei** si ramura inerta cand lipseste, astfel incat apelantii existenti
- sa fie identici cu azi.
- **MASURAT — `docs\cercetare\suprafata_regresie_contabilizeaza_articol.md`. Riscul e mai mic decat parea.**
- `contabilizeaza_articol` are **trei apelanti, toti interni pachetului**, toti pozitionali cu acelasi
- singur argument — **zero apelanti externi, nici PL/SQL, nici VFP, in niciunul din cele sapte produse**.
- `adauga_articol_factura` e apelata **pozitional peste tot**, niciodata cu notatie pe nume (`=>`), iar
- cele sapte copii `COMUN\clase\ofacturare.vc2` sunt **acelasi sit de apel duplicat**, nu sapte
- implementari care ar putea diverge: fisierele difera intre ele (patru variante distincte pe MD5), dar
- **textul apelului e identic cuvant cu cuvant**, doar offsetul de linie difera. Exista in plus doua
- implementari proprii reale — ROAGEST (`Programe\ofactureaza.prg:264`) si ramura `_deviz` din ROAAUTO /
- ROAACNPRO.
- **Precedentul e activ, nu teoretic:** ROAGEST apeleaza azi `adauga_articol_factura` cu **24 din 25 de
- parametri**, omitand `V_TAXCODE` si `V_LOT` tocmai pentru ca au `DEFAULT NULL`. Tiparul propus e deja
- in uz in productie.
- **Ce ramane:** toate cele **sapte** produse emit efectiv prin acest pachet, deci aria de regresie e
- toata suita chiar daca niciun apelant nu se modifica.
-- ~~**Anomalie preexistenta: `scrie_factura2` apelata cu 16 din 17 parametri.**~~ **INCHISA — fals
- pozitiv, nu intra ca risc.** `oExecuta` (`COMUN\programe\oproceduri_comune.prg:121-159`) deleaga la
- `oExecute` (`:173-504`), care face `SQLExec(lnHandle, lcSql, lcCursor)` (`:330`) — **textul SQL nu e
- rescris**, deci al 17-lea parametru chiar n-are placeholder. Explicatia e tiparul cunoscut al
- driverului ODBC Oracle: cand ultimul parametru declarat e un `REF CURSOR OUT`, driverul il ia din
- catalog, nu din textul apelului, si intoarce randurile ca *result set* — captat exact de al treilea
- argument al lui `SQLExec`. *Nuanta de pastrat:* mecanismul din interiorul driverului **nu poate fi
- confirmat din codebase**, e verificabil doar prin comportament; dovada e indirecta, dar consistenta —
- acelasi tipar in toate cele patru situri, neschimbat de la `v 2.0.13` la `v 2.0.93`, iar ecranul de
- verificare depinde de acel cursor populat la fiecare emitere, deci un apel esuat s-ar fi vazut demult.
-- **Decizia 35 leaga etapa II de aceeasi modificare de pachet.** Editarea prin regenerare nu mai are cale
- proprie (canalul `oscrie_in_fisiere` e respins ca al doilea cod de contare), deci **un blocaj pe
- parametrul deciziei 34 blocheaza si S9-S12**, nu doar etapa I. In schimb dispare riscul de divergenta
- intre regula de contare de la emitere si cea de la editare.
-- **`ofacturare.vc2` e in COMUN si are 843 KB / 25 de clase**, folosite de toata suita. Formularul
- vechi trebuie sa ramana functional pana cand cel nou acopera toate tipurile — deci comutator, nu
- inlocuire.
-- **`ID_FACT` pastrat cere atingerea unui punct comun intregii suite.** `SET_IDFACT` e in
- `PACK_CONTAFIN` si e chemat de fiecare scriere de note din toate produsele ROA. Comutatorul din S9
- trebuie sa fie inert pentru toate celelalte cai; altfel regresia nu e in ROAFACTURARE, ci peste tot.
-- **Formularul identic la introducere si la modificare taie o plasa de siguranta.** Decizia 9 o repune
- **doar pe antet** — butonul protejeaza campurile de antet, nu si liniile. Pe articole nu exista niciun
- semnal ca modificarea va sterge si va rescrie documentul; confirmarea de la `Termina` ramane
- singurul moment in care se poate spune ce urmeaza sa se intample. De formulat cu grija.
-- **Ascunderea datei de curs poate lasa un document fara curs corectabil.** `poDate.zi_curs` se
- trimite neconditionat catre cursoarele de articole; daca lipseste cursul pentru acea zi, Oracle da
- eroarea 20005 si se deschide formularul de curs — dar utilizatorul nu mai are unde sa corecteze data
- daca i-am ascuns campul. Regula din M trebuie sa aduca inapoi campul in exact acest caz.
-- **Sectiunea pliata ascunde campuri care schimba documentul.** Analiticele si datele de incasare
- intra sub un panou inchis implicit. Daca un camp obligatoriu pe un anumit tip ajunge acolo,
- utilizatorul primeste eroarea fara sa vada campul. Panoul trebuie sa se deschida singur cand
- contine un camp necompletat si obligatoriu, si sa arate in antet ca are ceva completat.
-- **Mutarea `frm_alte_date` muta si alocarea de numere.** Bonul fiscal, POS-ul si chitanta primesc
- numar din masina de stari a incasarii. Daca ea ajunge sa ruleze la deschiderea formularului in loc
- de la alegerea tipului de incasare, se aloca numere pentru documente care nu se mai emit.
-- **`S3c` si `S4c` ating cod comun.** Parametrizarea sursei atinge `factureaza` (toata suita), iar
- discountul editabil atinge listarile si eventual eFactura. Fiecare merge separat, cu regresie
- proprie.
-- **Reemiterea nu e idempotenta prin constructie.** Daca la reemitere pretul se re-deriva (H) sau
- cursul valutar al zilei difera, documentul "nemodificat" iese cu alte sume decat originalul.
- Testul din S12 (reemitere identica) exista tocmai ca sa prinda asta.
-- **`verifica_total_document`** (`PACK_FACTURARE:16009+`) insereaza automat o linie de corectie cand
- totalul difera de suma notelor. La regenerari repetate trebuie confirmat ca nu se acumuleaza —
- aceeasi intrebare ca S7 din #6.
-- **Cautarea in linie schimba un obicei.** Utilizatorii care lucreaza azi cu gridul de articole
- vizibil si filtrare locala pierd vederea de ansamblu. Merita verificat pe un client inainte de a
- scoate definitiv gridul vechi.
-
-## Dependente
-
-- **#7 (pret cu TVA pe linie)** — flagul `pret_cu_tva` pe linie apare in gridul unificat; se
- pastreaza comportamentul stabilit acolo.
-- **#12 (nomenclator ca lista de preturi)** — S4 construieste cautarea in linie peste politici de
- preturi; daca #12 muta pretul in nomenclator, S4 se rescrie.
-- **#16** — bug-ul de focus / renumerotare la revenirea din cursul valutar. Confirmat ca apare **dupa**
- ce antetul s-a inchis si s-a eliberat (`ofacturare.prg:248`), la recuperarea erorii Oracle 20005.
- In formularul unificat nu mai exista un antet inchis la care sa te intorci, deci **mecanismul lui
- dispare** — de confirmat in S4d, nu de presupus.
-- **#6** — **dependenta de calendar, nu de perimetru** (decizia 30): implementarea lui #13 incepe
- dupa ce #6 se termina. Proiectarea si cercetarea merg mai departe in paralel.
-
-## Preconditii de mediu
-
-- Orice DDL / modificare `PACK_FACTURARE`: sursa de referinta e `MARIUSM_AUTO` pe `ROA_CENTRAL`,
- nu productia (`COMUN\docs\scripturi-migrare-db.md`). Scripturi nivel Oracle 10.2, CRLF,
- idempotente, `versiune_db.txt` actualizat.
-- Sursa completa `PACK_FACTURARE` nu e in working copy; copia pe disc e
- `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql` (16 948 linii),
- cu alta numerotare decat exportul din baza.
-- Editarile pe `.vc2` / `.sc2` trec prin `git_sync.ps1` + `txt2vcx.ps1`, cu atentie la
- `COMUN\docs\conventie_encoding_cp1252.md` (diacriticele din `.vc2` sunt cp1250 — vezi si memoria
- proiectului).
+# Plan #13 — formular unificat de facturare + editare prin regenerare
+
+Sursa: `COMUN\docs\todos.txt` punctul 13.
+Mockup: `docs\mockup_13_formular_unificat.html` (versiunea 5).
+Cercetare pe cod, toata in `docs\cercetare\`: `inventar_controale_formulare.md`,
+`proforma_copiere_puncte_intrare.md`, `import_roris_roaacnpro.md`, `discount_pe_articol.md` si
+`discount_verificare2.md` (a doua il corecteaza pe primul), `modifica_antet_bifa.md`,
+`valuta_si_curs.md`, `buton_comutator_picture.md`, `modifica_date_factura_parametri.md`,
+`retur_si_lista_preturi.md`, `factura_retur_document.md`, `roaauto_facturi.md`,
+`roaauto_articole_lista_preturi.md`, `cont_venit_articol_fara_politica.md`.
+Stare: **propunere, neinceput**. Analiza facuta pe cod la 09.08.2026, in sase runde.
+
+## Cerinta, asa cum a fost formulata
+
+Trei lucruri intr-un singur punct:
+
+1. **Unificarea formularelor** — `date_factura` / `date_aviz` sa intre in formularul de facturare,
+ ca sa nu mai fie doua ferestre pentru acelasi document.
+2. **Fara incarcarea prealabila a tuturor articolelor** din toate politicile de preturi — pot fi mii
+ si dureaza mult aducerea lor de pe server.
+3. **Editarea facturii / avizului prin regenerare**, in toate variantele (politici de preturi,
+ comanda, contract, aviz): formularul se redeschide completat ca inainte de salvarea initiala, se
+ fac modificarile ca la introducere, iar la confirmare documentul initial se marcheaza `sters = 1`
+ si se salveaza unul nou — ca sa se vada ce s-a modificat.
+
+Decizia lui Marius, 09.08.2026: **intai unificarea, apoi editarea prin regenerare.** Explicit
+**nu** pe calea editarii directe a notelor / rulajelor / articolelor.
+
+## Deciziile lui Marius, 09.08.2026 — luate, nu de reluat
+
+1. **#13 coexista cu #6**, nu il inlocuieste.
+2. **`ID_FACT` se pastreaza**, ca la orice modificare. Documentul reemis nu-si schimba identitatea.
+3. **Toate datele se pastreaza, inclusiv numarul documentului.** Scopul e modificarea documentului,
+ nu emiterea altuia.
+4. **Antetul care intra in generarea lui `ID_FACT` (serie, numar, data) are cale proprie de
+ modificare** — nu trece prin regenerare.
+5. **Un singur formular, aceeasi infatisare la introducere si la modificare.** Fara banda de
+ avertisment, fara coloane cu valorile initiale, fara panou de diferente.
+6. **Se integreaza si modificarea de antet, si modificarea de articol care exista azi** — sa nu
+ ramana trei actiuni de modificare pe acelasi document.
+
+## Deciziile lui Marius, runda 3 (09.08.2026) — luate, nu de reluat
+
+7. **`frm_alte_date` intra in formular**, in sectiunea pliata. Se inchide intrebarea ramasa deschisa
+ in runda 2 (recomandarea de atunci — „ramane dialog” — **cade**).
+8. **Sectiunea pliata primeste in plus analiticele**: venit / cheltuiala, sectie, responsabil (si,
+ prin simetrie, lucrare). Antetul vizibil ramane aerisit, cu **controalele grupate** pe intelesuri,
+ nu insirate.
+9. **Un singur buton comutator pe antet.** Antetul se deschide blocat. Un singur `but_modifica`
+ (creionul) il deblocheaza si **isi schimba imaginea in discheta lui `but_salvare`**; a doua
+ apasare salveaza **doar antetul** si il blocheaza la loc. Un singur control, nu bifa plus buton —
+ mai compact. **Toata factura se salveaza in continuare din `Termina`.** Rostul ramane acelasi:
+ antetul se editeaza intentionat, nu din greseala, si se poate corecta fara a trece prin articole.
+
+ **Butonul singur deschide tot antetul. Nu mai exista bife individuale** — nici cele patru de azi
+ (serie / numar / data / scadenta). Un singur control comanda toata protectia antetului.
+
+ *Istoric, ca sa nu se reia:* runda 3 propusese un buton `Modificare / Salveaza` care bloca **tot
+ documentul** — respins, protectia e doar pe antet. Runda 4 propusese **bifa + buton separat** —
+ respins la 09.08.2026 in favoarea butonului comutator. Runda 5 propusese **pastrarea celor patru
+ bife individuale sub buton** — respins la 09.08.2026: bifele dispar cu totul.
+
+ **Verificat pe cod la 09.08.2026** (`docs\cercetare\buton_comutator_picture.md`): **tiparul exista
+ deja in suita si se copiaza, nu se inventeaza.** `frm_rulaje.se_modifica_assign`
+ (`COMUN\clase\rulaje.vc2:4716-4773`) comuta exact asa **o singura instanta** de `but_modifica`
+ intre creion si discheta — nu instantiaza a doua clasa. Trei lucruri de retinut din el:
+ - se rescriu **impreuna** `.cpicturedown`, `.cpictureup` **si** `.Picture`, plus `.ToolTipText`,
+ urmate de `.Refresh()`. Numai `.Picture` nu ajunge: hover-ul standard din
+ `buton.MouseEnter` / `MouseLeave` (`_cmd_base.vc2:88-97`) rescrie `Picture` din `cPictureUp` /
+ `cPictureDown`, deci iconita veche ar reveni la primul mouse-over;
+ - numele de fisier se dau **fara cale** (`"save_sus.bmp"`), rezolvate prin `SET PATH` — care
+ include si `GRAFICE`, si `COMUN\GRAFICE` (`Programe\roafacturare.prg:85-108`). Calea relativa
+ `..\grafice\...` din clasa e buna doar la design-time;
+ - imaginile exista: `COMUN\grafice\save_sus.bmp` / `save_jos.bmp` (discheta),
+ `modific_sus.bmp` / `modific_jos.bmp` (creion, perechea folosita de clasa).
+
+ Clasa de salvare din biblioteca se numeste **`but_salveaza`**, nu `but_salvare`
+ (`cmd_butoane.vc2:340-352`); e sursa numelor de imagini, dar nu se instantiaza. Clasa
+ `but_modifica` e la `cmd_butoane.vc2:184-198`. Butoanele **nu** au `do_activeaza` /
+ `do_dezactiveaza` — pe ele se lucreaza direct pe `.Enabled`.
+
+ **Consecinta asupra celor patru bife individuale** (serie / numar / data / scadenta, vezi I):
+ **se elimina**, si **odata cu ele se abandoneaza si conditia lor** de azi
+ (`chkSerieAct.Enabled = !EMPTY(NVL(poRec.numar_act,0))`, `ofacturare_comun.vc2:5736-5750`).
+ Decis de Marius la 09.08.2026: **butonul deschide tot**, fara conditii pe camp. Un singur control,
+ o singura regula. Cat de departe merge „tot” — vezi **decizia 19**: exact cat scrie
+ `modifica_date_factura`, parametru cu parametru.
+10. **Proforma foloseste acelasi formular.**
+11. **Copierea foloseste acelasi formular**, ca document nou, cu antetul editabil.
+12. **Formularul trebuie sa *poata* fi apelat cu sursa deja completata** — din pagina de comenzi cu
+ comanda, si din programul de contracte cu contractul, fara ca utilizatorul sa mai aleaga ulterior.
+ **Nu se integreaza contractele acum**; nu depinde de #10.
+13. **Un singur buton de adaugare a articolelor, cu `xmenu()`** — nu doua butoane separate „adauga
+ tot” si „alege”. Optiunile din meniu se schimba dupa sursa si acopera **comanda, contractul si
+ avizele**, cu alegere selectiva acolo unde are sens (de exemplu o singura rata de contract).
+ Butoanele de linie stau deasupra tabelului.
+14. **Discountul pe articol, procent si valoare absoluta**, amandoua accesibile.
+15. **Data cursului valutar apare doar cand are sens.** Sunt doua concepte diferite, care azi impart
+ acelasi camp mereu vizibil: (a) **factura in valuta**, unde si articolele au pret in valuta, si
+ (b) **factura in lei cu articole care pot avea pret in valuta**, convertite in lei la cursul din
+ data cursului, cu documentul si contabilitatea in lei. Formularul trebuie sa fie **ergonomic si
+ simplu** — campul nu apare cand nu e nimic de convertit.
+
+### Deciziile lui Marius, runda 6 (09.08.2026)
+
+16. **Lista de preturi e disponibila mereu, indiferent de sursa — si liniile suplimentare se pot si
+ sterge.** Pe o factura din comanda sau din contract trebuie sa se poata **adauga si sterge**
+ articole libere din lista de preturi, nu doar articole din sursa. Cazul real, formulat de Marius:
+ clientul a comandat ceva, iar la facturare mai vrea ceva in plus sau vrea sa schimbe — deci
+ documentul trebuie sa poata devia de la comanda, in ambele sensuri. Sursa umple documentul, nu il
+ inchide. Optiunea „Cauta in lista de preturi…" ramane in meniul butonului de adaugare **pentru
+ toate sursele**, inclusiv pentru documentele deja emise care se modifica.
+ **Verificat pe cod** (`docs\cercetare\retur_si_lista_preturi.md`, B): **contractul o are deja**
+ (`crsarticole` e populat de `cursor_preturi` / `cursor_contract` cu lista intreaga, al doilea grid
+ e un adaos, nu o restrictie), **comanda nu** — `cursor_comanda` umple `crsarticole` **doar** cu
+ articolele comenzii (`ofacturare.prg:266-308`). Deci golul real e pe comanda, si e in **continutul
+ cursorului**, nu in vreun `Visible` de buton. Reteta exista deja in produs: ramura de copiere
+ adauga lista de preturi peste cursorul sursei cu `APPEND FROM` (`ofacturare.prg:454-473`) — se
+ generalizeaza ea, nu se inventeaza alta.
+17. **Returul intra in formularul unificat, cu tot cu alegerea facturilor sursa.** Factura de retur
+ facuta din facturi anterioare e un caz de acoperit explicit — lipsea si din mockup, si din
+ proiectare. *Vezi sectiunea N.*
+ **Sunt doua mecanisme distincte, si prima cercetare l-a vazut doar pe al doilea:**
+ (a) **factura de retur ca document** (tipurile 8, 9, si avizul 24) — alege facturile sursa **la
+ nivel de document**, cu selectie multipla, si isi populeaza liniile din ele; **gestiunea si
+ pretul de achizitie vin neschimbate din linia originala**, verificat in `cursor_retur_document`.
+ **Exista deja si merge** — nu se reproiecteaza. Vezi N.1;
+ (b) **`But_retur`** — retur de articole intr-o factura de vanzare normala (tipurile 1, 5, 7, 10),
+ unde factura sursa se alege **per articol**, iar gestiunea nu se mosteneste, ci se alege. Vezi N.2.
+ Sunt doua fluxuri de cod independente, fara punct comun. Decizia 17 le duce pe amandoua in
+ formularul unificat; ce se proiecteaza nou e (b) ridicat la nivel de document, nu (a).
+18. **Facturile emise din ROAAUTO intra in perimetru la modificare.** ROAAUTO le emite din formularul
+ lui, dar scrie tot in `VANZARI_DETALII`, si pe ele trebuie sa se poata adauga articole din lista
+ de preturi. **Emiterea ramane la ROAAUTO** — se unifica doar modificarea.
+ **Verificat pe cod** (`docs\cercetare\roaauto_facturi.md`): acelasi `PACK_FACTURARE`, acelasi drum
+ `VANZARI_DETALII_TEMP` -> `VANZARI_DETALII`, tip de document **`-12`**, pe care editorul lui #6 il
+ **vede deja**, testat pe date reale.
+ **Precizarea lui Marius, 09.08.2026, verificata pe cod**
+ (`docs\cercetare\roaauto_articole_lista_preturi.md`): in ROAAUTO **exista deja adaugarea de
+ articole reale**, pe langa liniile generice — mecanismul „Alte servicii” din `frm_incasare_finala`.
+ Deci descrierea „doar linii sintetice cu `id_articol` negativ” din primul raport e **incompleta**.
+ Nuanta care conteaza pentru proiectare: sursa lui e **nomenclatorul brut**, nu lista de preturi,
+ articolele oferite sunt **fara stoc** (`in_stoc = 0 and in_crm = 1`), iar **pretul se tasteaza
+ manual** — nu vine din politici. Ce se cere e ca **acelasi lucru sa fie posibil si la modificarea
+ documentului**, nu doar la emitere, **si nu numai pentru facturile auto, ci pentru orice tip**,
+ cu **ambele surse**: lista de preturi (cu pret calculat) sau nomenclatorul (cu pret tastat).
+ **Vezi O.**
+19. **Toti parametrii lui `modifica_date_factura` trebuie sa fie modificabili din butonul de antet.**
+ Butonul comutator nu deschide un subset ales de noi: daca procedura Oracle stie sa scrie un camp
+ de antet, formularul trebuie sa aiba controlul prin care acel camp se poate schimba.
+ **Verificat pe cod** (`docs\cercetare\modifica_date_factura_parametri.md`): sunt 15 parametri,
+ din care **14 sunt campuri** — al 15-lea, `V_ID_VANZARE`, e identitatea randului si nu se
+ editeaza. Din cele 14:
+ - **13 au deja control** in `frm_modifica_factura` si se muta ca atare in antetul unificat;
+ - **`V_EFACTURA` nu are niciun control nicaieri** (`ofacturare_comun.vc2:4576` il forteaza `0`
+ la selectie multipla, altfel vine din `Scatter`) — **primeste unul**, e singurul camp nou-nout
+ cerut de decizia asta;
+ - `V_TIP_SAFT` are control, dar ascuns dupa `gl406` (`:5739-5741`) — ramane conditionat, nu se
+ forteaza vizibil.
+ Vezi I-bis pentru contractul procedurii, care impune si **cum** se cheama, nu doar ce se trimite.
+20. **Din nomenclator se aleg si articole gestionabile, si negestionabile.** Filtrul `in_stoc = 0`
+ al lui ROAAUTO **nu se preia** — acolo e o ocolire a subiectului gestiunii, nu o regula de produs.
+ Consecinta acceptata: pe documentele auto vor coexista linii care descarca stoc cu linii care nu
+ descarca, caz care azi nu exista nicaieri. *Vezi J si O-bis, intrebarea 2.*
+ **Intrebarea care insotea decizia — „cu ce cont de venit intra un articol fara politica de pret”
+ — s-a inchis prin cercetare: nu exista cont de venit pe linie.** Vezi **J-bis**.
+
+### Deciziile lui Marius, runda 7 (09.08.2026)
+
+21. **Cand `NOM_ARTICOLE.CONT` e gol pe un articol negestionabil, se aplica un fallback la un cont
+ implicit.** Nu se accepta `NULL` (comportamentul de azi al liniilor „Alte servicii" din ROAAUTO) si
+ nu se refuza adaugarea articolului. Contul anume se alege la implementare.
+ **Atentie la perimetru:** decizia priveste **contul de gestiune** (`VANZARI_DETALII.CONT`). Cand a
+ fost luata nu se stia inca faptul, stabilit mai tarziu in aceeasi runda, ca pe linie exista **doua**
+ conturi cu surse diferite — cel de venit (`NOTE_CONTABILE.SCC`, prin politica de pret) nu e acoperit
+ de aceasta decizie si e inca deschis. *Vezi J-bis.*
+ Ipoteza de la care a pornit Marius — corespondenta 3xx -> 7xx dintr-un tabel — **nu s-a confirmat
+ ca tabel**, dar intentia ei da: legatura articol -> cont de venit exista, prin politica de pret si
+ `NOTE_CONTABILE`, configurata manual de contabil.
+22. **Linia de retur fara factura originala e permisa.** Pe tipurile 8, 9, 24, „Cauta in lista de
+ preturi…" si „Alege din nomenclator…" se comporta ca pe orice alt document — nu apar doar pentru
+ corectii si nu sunt marcate special. Consecinta acceptata: gestiunea si pretul de achizitie se
+ aleg (nu se mostenesc), iar maximul returnabil de pe server nu se aplica acelei linii. *Vezi N.3.*
+23. **Secventierea deciziei 18: `pack_auto` se cerceteaza acum**, inainte de orice estimare, nu cand ii
+ vine randul la livrare. *Vezi O, „Secventierea".* **Rezultat:** riscul tehnic nu exista —
+ `PACK_AUTO` nu citeste `VANZARI` / `VANZARI_DETALII` deloc. Decizia 18 nu mai trebuie sa fie ultima.
+24. ~~**Articolul ales din nomenclator primeste `id_pol`-ul unei politici de pret implicite.**~~
+ **RETRASA in runda 8, inlocuita de decizia 27.** Ramane in plan doar ca sa nu fie reintrodusa:
+ politica implicita ar fi evitat codul nou in `pack_facturare`, dar cu pretul unei intrebari de
+ configurare cu contabilul si al unui cont de venit uniform pentru orice articol adaugat asa.
+ Marius a ales in loc corespondentele `CORESP_CONT_VENCHELT`. *Vezi decizia 27 si J-quater.*
+25. **Butonul de antet deschide tot; ce nu se poate salva pe loc forteaza regenerare.** La a doua
+ apasare, cei **14 parametri** merg prin `modifica_date_factura`, iar orice camp schimbat din
+ **grupul B** (tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi)
+ sau **C** (incasare) **marcheaza documentul pentru regenerare**, aplicata la `Termina`. Decizia 9
+ ramane intacta ca intentie — butonul chiar deschide tot antetul —, dar ruta de scriere se bifurca
+ dupa camp, nu dupa buton. *Vezi G-bis.*
+ **Consecinta pe etape:** in **etapa I** regenerarea nu exista inca, deci acele campuri nu au unde
+ sa se salveze. **Planul le tine blocate in etapa I**, cu explicatie la hover, si le deschide odata
+ cu etapa II. Motivul alegerii, in lipsa unei instructiuni contrare: un camp care se deschide dar nu
+ se salveaza e o capcana — pierderea tacuta a unei modificari e mai rea decat un camp inca blocat.
+26. **Analiticele raman read-only in #13; editarea lor e a lui #6.** Venit/cheltuiala, sectie,
+ responsabil si lucrare se **afiseaza** in sectiunea pliata, cu valoarea de antet, dar nu se
+ editeaza din formularul unificat — cine vrea sa le schimbe trece prin editarea notei contabile.
+ Motivul: sunt deja editabile acolo, **la nivel de linie de nota**, iar #13 le-ar scrie uniform pe
+ tot documentul — doua ferestre care scriu acelasi camp cu semantici diferite, cu risc ca #13 sa
+ suprascrie tacit o diferentiere facuta din #6. **Zero suprapunere intre fire.** *Vezi G-bis.*
+ Asta **nuanteaza decizia 8**: analiticele intra in sectiunea pliata ca **afisare**, nu ca editare.
+
+ **RASTURNATA DE DECIZIA 72 (22.08.2026): analiticele raman EDITABILE**, si la introducere, si la
+ reemitere. Motivul semantic de mai sus ramane consemnat ca **consecinta acceptata**, nu ca
+ restrictie: la reemitere nota se reconstruieste uniform pe document, deci o diferentiere facuta
+ din #6 la nivel de linie de nota se pierde — efect al regenerarii, nu al editabilitatii.
+
+### Deciziile lui Marius, runda 8 (09.08.2026)
+
+27. **Contul de venit vine din corespondente si din nomenclator, nu dintr-o politica de pret
+ implicita. Decizia 24 se retrage.** Regula, pe doua ramuri:
+ - **articol gestionabil** (cont de gestiune de clasa 3xx): contul de venit se ia din tabelul de
+ corespondente `CORESP_CONT_VENCHELT` — `select id_ccv, cont, cont_chelt, cont_venit, sters,
+ dataoras, cont_aprovizionare, cont_diferente from coresp_cont_venchelt`, cautand pe `CONT`
+ (contul de gestiune al liniei) si luand `CONT_VENIT`;
+ - **articol negestionabil**: se foloseste `NOM_ARTICOLE.CONT` **daca e deja un cont de clasa 7xx
+ sau 6xx**; altfel, implicit **704**.
+
+ Motivul respingerii politicii implicite: ea muta problema in configurare (cine creeaza politica,
+ cu ce `SCC`, una sau mai multe) si obliga la o intrebare cu contabilul inainte de orice livrare.
+ Corespondentele exista deja ca date de productie si leaga contul de gestiune de cel de venit —
+ exact relatia cautata, doar ca sub alt nume decat s-a cautat in runda 7.
+27-bis. ~~**Regula din 27 se implementeaza FARA cod nou in `pack_facturare`.**~~ **RELAXATA de decizia
+ 34 si inchisa de decizia 35** — pachetul se modifica punctual, si e singurul cod de contare, si la
+ emitere si la editare. Textul de mai jos ramane doar ca istoric al rationamentului.
+ (Marius, runda 8, dupa
+ prima formulare a lui 27). Motivul: pachetul e mare si e folosit de toate produsele suitei — o
+ ramura noua acolo e un risc peste tot, nu doar in ROAFACTURARE.
+ Deci **regula de derivare a contului de venit se aplica pe partea VFP**, inainte ca articolul sa
+ plece spre Oracle, iar `contabilizeaza_articol` ruleaza **neschimbata**. Calea de verificat:
+ VFP calculeaza contul de venit dupa regula de mai sus si alege un `id_pol` a carui nota are deja
+ acel `SCC`, astfel incat `FACT-024` sa nu se mai poata declansa.
+ **Modificarea pachetului ramane planul B**, folosit doar daca se dovedeste ca nu exista nicio cale
+ dinspre VFP. *Vezi J-quater;* fezabilitatea: `docs\cercetare\coresp_cont_venchelt.md`, punctul 8.
+
+ **PREMISA A FOST VERIFICATA (Marius, runda 8):** „in ROAACNPRO, dar si la factura din comanda /
+ contract, se adauga articole fara politica de preturi — de ce nu se poate si aici?" **Raspuns:
+ observatia e reala, dar niciunul din cele doua exemple nu e un articol fara politica.** ROAACNPRO
+ nu cheama deloc `contabilizeaza_articol` (are propria contabilizare, `pack_acn.salveaza_regdoc`);
+ pe contract, articolele vin din `cursor_contract` / `cursor_preturi`, care le livreaza **cu `id_pol`
+ atasat**. `FACT-024` ramane blocantul. *Detalii, cu dovezi: J-quater, punctul 1.*
+ **REZULTAT: calea VFP exista si e mai buna decat modificarea pachetului** — se sprijina pe un RPC
+ existent (`pack_preturi.adauga_politica_pret_art`) si aduce, pe langa `SCC`, si `CU_TVA` /
+ `IN_VALUTA`, pe care un fallback in pachet ar fi trebuit sa le hardcodeze. *Vezi J-quater, punctul 3.*
+ **Planul B (modificarea `pack_facturare`) se abandoneaza.**
+28. **Pe factura ROAAUTO pot exista si alte articole decat cele de pe deviz.** Nepotrivirea de afisare
+ dintre ecranul de deviz si factura retiparita (O, intrebarea 1) **e acceptata**: cerinta e ca
+ **MANOPERA si MATERIALE sa fie conform devizului**, plus orice alte articole adaugate. Nu se cere
+ cod nou in ROAAUTO ca sa aduca ecranul de deviz la zi. *Vezi O, intrebarea 1.*
+29. **Stergerea unei linii venite din comanda ramane fara protectie.** Linia se sterge ca oricare alta;
+ comanda va aparea, corect, ca **facturata partial**. Nu se adauga confirmare, nu se marcheaza
+ „refuzat", nu se ajusteaza numararea acoperirii. *Vezi S4e.*
+30. **Nu se coordoneaza cu firul #6.** #13 **incepe dupa ce #6 se termina**, deci suprapunerea pe
+ fisiere nu se poate produce si nu e nevoie de impartire de perimetru. Consecinta pe interdictii:
+ cele doua fisiere ale lui #6 raman intangibile **cat timp #6 e in lucru**, dar restrictia expira
+ odata cu el, nu cere negociere. Decizia 26 (analiticele read-only in #13) era pastrata aici pentru
+ ca tinea de semantica, nu de coliziunea de lucru — dar a fost **rasturnata de decizia 72**:
+ analiticele sunt editabile, iar suprapunerea de semantica ramane consemnata acolo ca efect asumat
+ al regenerarii. *Vezi „Relatia cu #6".*
+
+### Deciziile lui Marius, runda 9 (10.08.2026)
+
+**31. Datele din Dev nu sunt baza de proiectare.** Fiecare client isi defineste propriile politici de
+pret, fiecare cu nota ei contabila de vanzare salvata pe un `ID_SET`. Orice masurare pe `MARIUSM_AUTO`
+vale ca **dovada ca un mecanism exista** si ca sursa de concluzii **structurale**, niciodata ca harta a
+ce e configurat la client. Nicio decizie de proiectare nu se sprijina pe numarul de politici sau de note
+gasite pe Dev. *(Generalizeaza regula „zero cazuri in date nu e dovada" in ambele sensuri: nici prezenta
+nu e dovada.)*
+
+**32. Intrebarea de raspuns inainte de orice implementare a contului de venit:** cum alege programul nota
+contabila de vanzare la **factura pe baza de comanda**, care **nu are politica de pret**? Daca acel
+mecanism se poate refolosi pentru articolul adaugat ad-hoc, **reteta in 4 pasi din J-quater se
+abandoneaza** in favoarea lui. Vezi J-quater, „Intrebarea deschisa care poate anula toata reteta".
+
+**34. `contabilizeaza_articol` primeste un parametru de cont contabil. Decizia 27-bis e RELAXATA.**
+Marius, 10.08.2026, textual: *„poți să adaugi parametrul contul contabil la `contabilizeaza_articol`."*
+Consecinta: **reteta in 4 pasi din J-quater se abandoneaza.** Nu mai e nevoie de politica tehnica, nici de
+interogarea inversa pe `SCC`, nici de inserarea articolului in politica. VFP calculeaza contul dupa regula
+deciziei 27 si **il trimite direct**.
+**Ce rămâne de proiectat, si nu e „doar un parametru":** contul nu e singurul lucru care venea de pe nota.
+`cursor_articol` aducea si `SCD`, `CU_TVA`, `IN_VALUTA`, `EXPLICATIE`, `ID_VENCHELT`, `ID_SECTIE`, iar bucla
+care il consuma apeleaza **si** `scrie_nota` **si** `descarca_gestiune`. Pe un articol fara politica,
+`FACT-024` sare inainte. Deci e nevoie de **parametru + ramura fara politica**, care sa furnizeze ce
+furniza nota si sa ruleze `descarca_gestiune` **exact o data**. Obiectia rundei 8 („`CU_TVA` si `IN_VALUTA`
+n-au sursa in afara lui `NOTE_CONTABILE`") **nu mai e blocanta, e proiectare** — de reevaluat daca se pot
+deriva din document.
+**Constrangeri de forma, ca sa nu se strice suita:** parametru nou **cu `DEFAULT NULL`**, la finalul listei,
+si ramura inerta cand lipseste — apelanții existenți nu se schimba. `pack_facturare` e comun **intregii
+suite**, deci cere regresie pe ROACONT / ROAGEST / ROACONTRACTE / ROAAUTO / ROAACNPRO, nu doar ROAFACTURARE.
+**Ramura noua nu moșteneste bug-ul de set multi-rand** din L.0-ter.
+**PROIECTATA** — `docs\cercetare\canal_cont_venit_fara_politica.md`, sectiunea „Proiectarea parametrului
+de cont contabil", liniile 13-227. Verdictul, in trei randuri, pentru ca schimba forma modificarii:
+`contabilizeaza_articol` primeste azi **un singur parametru**, `detalii_articol
+VANZARI_DETALII_TEMP%ROWTYPE` — deci contul **nu intra literal pe ea**, ar fi cosmetic. Intra ca
+**coloana noua `VANZARI_DETALII_TEMP.CONT_VENIT VARCHAR2(4) NULL`**, populata printr-un parametru nou
+`V_CONT_VENIT IN VARCHAR2 DEFAULT NULL` la **coada lui `adauga_articol_factura`** (procedura chemata
+direct din VFP), pe care `contabilizeaza_articol` o primeste automat: cei trei apelanti interni fac
+`SELECT * BULK COLLECT` intr-un `TABLE OF ...%ROWTYPE`, deci `scrie_factura2`,
+`scrie_factura_avize_retur` si `scrie_aviz_retur` **nu se ating deloc**.
+> **Corectie de nume, runda 11 — mecanismul insa rezista.** Al doilea apelant e **`scrie_factura_avize`**
+> (`:6708-6749`), nu `scrie_factura_avize_retur`, care nici nu cheama `contabilizeaza_articol`.
+> **Verificat pe cod ca toti trei apelantii reali** — `scrie_factura2` (`:6039-6063`),
+> `scrie_factura_avize` (`:6708-6749`), `scrie_aviz_retur` (`:7097-7106`) — fac intr-adevar
+> `SELECT * BULK COLLECT INTO` un `TABLE OF VANZARI_DETALII_TEMP%ROWTYPE`, **fara lista explicita de
+> coloane**. Deci coloana noua curge automat prin toti trei si **niciunul nu se atinge**; concluzia
+> proiectarii sta, doar doua din cele trei nume erau gresite. In `scrie_factura_avize`, `tab_detalii(i)`
+> e modificat inainte de apel doar pe `.cantitate` / `.id_rata` — `CONT_VENIT` ramane neatins. Efectul cerut de Marius e exact
+acelasi; doar mecanica de livrare difera de formularea literala. Precedentul e in aceeasi semnatura:
+`V_TAXCODE` si `V_LOT` sunt deja doi parametri adaugati ulterior, la coada, cu `DEFAULT NULL`, iar apelul
+VFP e pozitional si se opreste la `V_LOT`.
+Ramura noua se activeaza pe `detalii_articol.cont_venit IS NOT NULL`, **infasoara si blocul `FACT-024`**
+(garda ramane litera cu litera pe ramura veche: o linie fara politica **si** fara cont trimis cade in
+continuare cu `FACT-024`), n-are cursor deloc — deci `descarca_gestiune` ruleaza **exact o data prin
+constructie** si bug-ul de set multi-rand nu se mosteneste, fara sa se repare ramura veche.
+**Doua hardcodari raman decizii deschise pentru Marius**, nu descoperiri: `SCD = '4111'` si `CU_TVA = 1`
+— vezi „Ce ramane de decis" mai jos.
+
+**VERIFICATA ADVERSARIAL** — `docs\cercetare\parametru_cont_contabilizeaza_articol.md`. Proiectarea
+rezista; patru rezultate schimba insa detalii de executie:
+
+- **Parametrul se cableaza in DOUA locuri VFP, nu unul.** `ofacturare.vc2:14069` si `:18089` **nu** sunt
+ o duplicare a aceleiasi metode, cum se presupusese: sunt **doua clase distincte**,
+ `frm_facturare_articole.do_scrie_articole` (`:13967-14195`) si
+ `frm_facturare_articole2.do_scrie_articole` (`:18003-18221`), fiecare construindu-si separat apelul RPC.
+- **`CU_TVA = 1` nu e inofensiv, cum spunea proiectarea.** Actualizarea lui `nproc_tva_max` /
+ `nid_jtva_coloana` / `nTaxCode` e chiar in interiorul lui `IF V_CU_TVA = 1` (`:12537-12558`), iar
+ comparatia `nproc_tva_max < V_PTVA` **se uita doar la rata, nu la suma**. O linie fallback cu TVA real
+ 0% ar intra deci in comparatia de maxim si, daca e prima linie a documentului (`nproc_tva_max` porneste
+ `-1`, `:1885`), **castiga** — iar coloana si taxcode-ul ei ajung sa descrie **linia de discount a
+ intregii facturi** (`:6164-6184`). Combinatia e ingusta (linie scutita + discount global + acea linie e
+ „maximul" de pana atunci), dar efectul e real. Motivul pentru care decizia ii apartine lui Marius e
+ acum concret, nu formal.
+- **`INSERT INTO VANZARI_DETALII ... FROM VANZARI_DETALII_TEMP` are lista de coloane explicita** — 24 de
+ coloane, `PACK_FACTURARE:13705-13757`, in `scrie_in_vanzari`. Deci daca se vrea `CONT_VENIT` pastrat si
+ dupa fapt in `VANZARI_DETALII`, **lista trebuie extinsa explicit**; altfel coloana traieste doar in
+ `VANZARI_DETALII_TEMP` si `ACT_TEMP`.
+- **Articolul compus nu e o gaura in proiectare** — e exclus structural, nu prin presupunere. `COMPUS`,
+ asa cum il citeste `contabilizeaza_articol` (`:7279-7283`), e definit in `VCRM_POLITICI_PRET_ART` ca
+ proprietate a **perechii (articol, politica)**, identificata prin `ID_POL_ART`. O linie fara politica
+ n-are `ID_POL_ART`, deci intrebarea nu se poate pune.
+
+**Golul `ntip = 4` — INCHIS in runda 11.** Cercetat (`docs\cercetare\gol_ntip4_factura_din_avize.md`) si
+**verificat adversarial** (`docs\cercetare\verif_goluri_ntip_aviz.md`). Trei rezultate, dintre care doua
+schimba ce trebuie scris in pachet:
+
+- **`ntip = 4` e exclus structural — dar nu prin garda pe care o presupunea proiectarea.** Blocajul nu e
+ `FACT-024` din `contabilizeaza_articol`, ci **o functie mai devreme**: `adauga_articol_factura`, ramura
+ `WHEN ntip = 4` (`:5080-5103`), cauta randul sursa din `VANZARI_DETALII` prin `A.ID_POL = V_ID_POL`
+ **fara handler de exceptie**. Cu `V_ID_POL = NULL` — exact cazul liniei fara politica — comparatia nu
+ se poate potrivi niciodata, deci apelul cade cu `ORA-01403` **la adaugarea articolului**, in bucla
+ `do_scrie_articole` (`ofacturare.vc2:13967-14106`), care ruleaza intotdeauna inaintea `Do Case`-ului
+ (`:14282`). Linia nu ajunge niciodata la `contabilizeaza_articol`; ramura noua n-are nimic de tratat
+ acolo, si **nu are nevoie de garda defensiva** (ar fi redundanta peste doua straturi independente).
+- **GOL REAL, mai ingust decat parea, dar efectiv atins: `SCD` pe avize.** Ramurile de aviz care chiar
+ ajung la `contabilizeaza_articol` — `ntip IN (28,29)` → `SCD = '461'`, restul avizelor „simple"
+ (`21, 22, 24, 27`) → `SCD = '418'` (`:7413-7422`) — **sunt accesibile cu `cont_venit` populat**, pentru
+ ca `adauga_articol_factura` nu cere `id_pol` pe niciunul din ele. Ramura noua, care ia `SCD` din
+ optiunea deciziei 36 (`4111`), l-ar scrie **necontitionat de `ntip`** → **cont contabil gresit pe
+ aviz**. Deci ramura noua **alege `SCD` dupa `ntip`**: `'461'` pentru `IN (28,29)`, `'418'` pentru
+ celelalte avize atinse, si abia pe restul optiunea `RF_CONT_ART_FARA_POL`.
+ **Verificarea a restrans lista:** `ntip IN (23,25,30,41,42,47)` **nu ajung deloc** la
+ `contabilizeaza_articol` — sunt deviate mai devreme, in `scrie_factura2`, spre `transfera_articol`
+ (`23,25,30,41`) sau direct spre `descarca_gestiune` (`42,47`). Golul nu li se aplica.
+- **Al doilea gol confirmat: garda `ntip = 46`.** `nTipNotaPlata` **este** `46`, iar `scrie_nota` e
+ sarita azi intentionat pentru el (`IF ntip <> nTipNotaPlata`, `:7441`). Un articol fara politica poate
+ ajunge si pe acest tip. **Ramura noua trebuie sa reproduca garda** — altfel scrie o nota care azi e
+ sarita deliberat.
+
+**CORECTIE la proiectare — al doilea apelant intern e numit gresit peste tot.** Nu
+`scrie_factura_avize_retur`, ci **`scrie_factura_avize`** (`:6692-7058`) — care e chiar handler-ul Oracle
+al lui `ntip = 4`, apelat din `ofacturare.vc2:14318`; apelul catre `contabilizeaza_articol` e la `:6858`,
+in interiorul lui `IF articole_aviz(j).custodie = 1`. `scrie_factura_avize_retur` (`:6264-6657`) **nu
+cheama deloc** `contabilizeaza_articol` — insereaza direct in `VANZARI_DETALII_TEMP` din
+`VANZARI_DETALII`. Iar `scrie_aviz_retur` (`:7085-7171`) **n-are niciun apelant VFP gasit** in tot
+`COMUN\` si in tot proiectul — posibil cod mort sau apelata din alt produs. Greseala e propagata in
+`canal_cont_venit_fara_politica.md:67` si `nota_contabila_fara_politica.md:103`; se citeaza de acum
+lista corectata de mai sus.
+
+**Nota de metoda, valabila pentru toate rapoartele:** presupunerea ca liniile din exportul
+`PACK_FACTURARE` au un **offset constant `+17`** fata de rapoartele vechi e **falsa**. Nu exista offset
+universal (masurat: `+9` fata de `nota_contabila_fara_politica.md`, `0` fata de alte rapoarte). Numerele
+de linie se **re-verifica direct pe fisier**, niciodata prin corectie presupusa.
+
+**Nu se implementeaza** — decizia 30 sta, #13 incepe dupa #6.
+
+**33. Mockup-ul nu se republica la v7.** Se duce la **v8** cu rezultatele verificarilor rundei 9 si abia
+atunci se republica — o singura citire a HTML-ului, o singura republicare. Url-ul artifact rămâne la v6
+pana atunci.
+
+### Deciziile lui Marius, runda 10 (10.08.2026)
+
+**35. Un singur cod de scriere contabila: `pack_facturare`, si la emitere si la editare.
+`oscrie_in_fisiere` NU se foloseste in #13.** Marius, 10.08.2026, textual: *„nu doresc folosirea scrie in
+fisiere ci doar `pack_facturare` la emitere si la editare pentru ca nu vreau sa intretin doua coduri."*
+
+**Ce anuleaza:** impartirea propusa la finalul rundei 9 — „emiterea prin parametrul deciziei 34, editarea
+prin canalul generic catre `ACT_TEMP`, care nu cere nimic in pachet" — e **respinsa**. Canalul
+`actactan` / `tact` → `COMUN\programe\oscrie_in_fisiere.prg` → `pack_contafin.SCRIE_IN_ACT` exista si e
+folosit azi in productie de fluxul de editare al lui #6, dar folosirea lui in #13 ar insemna **doua
+implementari ale aceleiasi reguli de contare** — una in pachet, pe emitere, alta in VFP, pe editare —
+tinute in pas manual la fiecare schimbare a regulii deciziei 27. Motivul e de **intretinere**, nu tehnic,
+si nu se reargumenteaza cu „canalul exista deja".
+
+**Ce impune:** editarea prin regenerare (etapa II) scrie pe **exact acelasi drum** ca emiterea —
+`scrie_factura2` → `contabilizeaza_articol`, cu parametrul de cont de la decizia 34. Nu exista ramura de
+scriere separata pentru documentul reemis si nu exista editare directa a randului din `ACT_TEMP` din #13.
+
+**Ce nu atinge decizia 35:**
+- **fluxul lui #6** ramane cum e (`ofacturare_comun.vc2:3796-3821` → `frm_modific2024`) — decizia priveste
+ #13; retragerea lui e alt subiect si alt perimetru — **inchis de decizia 38: coexista, se decide dupa
+ ce #13 livreaza**;
+- **stergerea** documentului vechi din S9 ramane pe drumul existent (`do_sterge` → `oscrie_in_fisiere` +
+ `pack_contafin.finalizeaza_stergere_nota`), pentru ca acolo **nu exista al doilea cod de intretinut**:
+ `pack_facturare` nu are echivalent de stergere a notei, iar drumul de stergere e comun intregii suite.
+ *Presupunere declarata, de infirmat daca Marius vrea si stergerea mutata in pachet — ar fi alt mandat si
+ alta suprafata de risc.*
+
+**Ce castiga:** regula deciziei 27 traieste intr-un singur loc, si o corectie pe ea nu trebuie facuta de
+doua ori. **Ce costa:** etapa II nu mai are cale ieftina — depinde de parametrul deciziei 34 exact cat
+depinde etapa I, deci **S9 nu poate porni inaintea parametrului**, iar regresia pe suita se plateste o
+singura data, dar obligatoriu.
+
+**36. Cele doua campuri ramase fara sursa pe ramura fara politica — decis.** Verificarea a stabilit intai
+ca **nu exista in cod nicio sursa alternativa** pentru ele: nici optiune de firma existenta, nici cont pe
+partener, nici flag de scutire pe articol sau client (`parametru_cont_contabilizeaza_articol.md`,
+sectiunea 4). Deci sunt decizii de produs, si Marius le-a luat asa:
+
+- **`SCD` — fix, dar citit din configurare, nu hardcodat.** O optiune de firma, cu **`4111` ca implicit**.
+ **PROIECTATA** — `docs\cercetare\optiune_firma_cont_debit.md`. **Costul e mult mai mic decat parea:
+ tiparul exact exista deja in productie, in acelasi pachet, pe acelasi camp.**
+ `pack_facturare.scrie_incasare2` (`PACK_FACTURARE:13161-13234`) isi ia `V_SCD` in **trei niveluri**:
+ parametru explicit daca a fost dat → **optiunea de firma** (`RF_CONT_INCASARE_BONFISCAL` s.a.m.d., cate
+ una per tip de incasare) → **constanta hardcodata** daca optiunea lipseste. Se copiaza identic, si se
+ inlocuieste punctual linia `SCD := '4111'` din proiectarea ramurii noi.
+ Mecanismul are 15+ ani: tabelul `OPTIUNI` (458 randuri azi), `PACK_SESIUNE.getoptiunefirma`, si un
+ **ecran de editare complet generic** peste tabel (`frm_optiuni` / `frm_optiuni_nou`,
+ `COMUN\clase\oOptiuni.vc2`) — deci **cheia noua nu cere niciun cod VFP nou**, doar randul in tabel.
+ Nu exista `ID_FIRMA`: fiecare firma are schema Oracle proprie, deci `OPTIUNI` din schema de conexiune
+ **este** deja „optiunile firmei curente".
+ **Dubla plasa de siguranta, si asta acopera integral cerinta lui Marius:** implicitul `4111` traieste si
+ in randul din `OPTIUNI` (scris de migrare, editabil fara recompilare), si hardcodat langa
+ `getoptiunefirma` — deci si o instalare veche fara migrare, si un rand golit din ecran cad tot pe `4111`.
+ `getoptiunefirma` intoarce `''` cand nu gaseste, ceea ce in Oracle e `IS NULL`, deci ambele cazuri se
+ trateaza cu aceeasi conditie.
+ **`ASCD` nu trebuie atins** — se calculeaza deja din `V_SCD`, deci primeste automat valoarea corecta
+ indiferent de sursa.
+ **`PROGRAME` se pune larg, nu doar `ROAFACTURARE`** — intrebarea a ramas deschisa in raport, dar se
+ inchide combinand-o cu masuratoarea de regresie: apelul catre `adauga_articol_factura` traieste in
+ `COMUN\clase\ofacturare.vc2`, fisier prezent si folosit in **toate cele sapte produse**, deci ramura noua
+ e atinsa de toata suita, exact ca `RF_CONT_INCASARE_*` (care listeaza sase produse).
+- **`CU_TVA` — derivat din cota liniei**, nu fixat: `1` daca `proc_tvav > 0`, altfel `0`. Asta **elimina
+ prin constructie** efectul gasit la verificare: o linie scutita nu mai intra in comparatia de maxim din
+ `nproc_tva_max`, deci nu mai poate imprumuta coloana si taxcode-ul ei liniei de discount a intregii
+ facturi. Pretul e o regula in plus in pachet si un comportament **diferit de ce face azi nota** pentru o
+ linie scutita — diferenta e intentionata, nu accidentala, si se noteaza ca atare la testare.
+
+Deci lista parametrilor noi ramane la **unul singur** (`V_CONT_VENIT`): `SCD` vine din configurare, iar
+`CU_TVA` se deriva in pachet din date deja prezente pe rand.
+
+**37. Cheia optiunii si validarea — decise (10.08.2026).**
+- **Cheia: `RF_CONT_ART_FARA_POL`**, aliniata la familia `RF_CONT_INCASARE_*` — adica exact optiunile care
+ alimenteaza azi `SCD` in acelasi pachet. Cele cinci apar astfel **grupate alaturi in ecranul de
+ optiuni**, ceea ce le face inteligibile impreuna. Incape in `OPTIUNI.VARNAME` (`VARCHAR2(30)`).
+ `VARTYPE = 'CHARACTER'`, `VARVALUE = '4111'`, `PROGRAM = 'ROAFACTURARE'`, `PROGRAME` larg (vezi 36).
+- **Fara validare de cont**, nici la salvare, nici la citire — se copiaza tiparul existent. Motivul:
+ niciuna dintre optiunile de tip cont nu e validata azi nicaieri, iar `RF_CONT_INCASARE_*` traieste asa
+ de 15 ani; a introduce validare aici ar fi o imbunatatire noua, nu continuarea unui tipar, si ar cere
+ fie cod nou in pachet, fie prima logica per-cheie din ecranul generic `COMUN\clase\oOptiuni.vc2` —
+ fisier al intregii suite. **Garda gratuita ramane lungimea:** un `VARVALUE` peste 4 caractere da
+ `ORA-12899` la `INSERT INTO ACT_TEMP`, deci esec zgomotos, nu cont tacut gresit.
+ *De consemnat la testare ca risc acceptat constient:* un cont inexistent in planul de conturi, scris din
+ greseala in ecran, ajunge pe nota neschimbat — acelasi risc pe care produsul il are deja, nu unul nou.
+
+### Deciziile lui Marius, runda 11 (10.08.2026)
+
+**38. Fluxul de editare al lui #6 nu se retrage odata cu #13. Coexista, si se decide mai tarziu.**
+Intrebarea pusa la finalul rundei 10 — daca decizia 35 („un singur cod de scriere contabila") obliga la
+rerutarea editarii lui #6 pe acelasi drum — primeste raspuns: **nu acum**. #6 ramane pe editarea directa
+a randului din `ACT_TEMP` (`ofacturare_comun.vc2:3796-3821` → `frm_modific2024` → `oscrie_in_fisiere`),
+#13 merge pe regenerare prin `pack_facturare`. Cele doua traiesc separat, pe povesti separate.
+**Ce inseamna concret:** decizia 35 se citeste strict ca perimetru al lui #13 — nu se proiecteaza si nu
+se planifica nicio retragere a fluxului lui #6 in aceasta poveste, si nu se adauga in #13 nicio piesa
+care sa pregateasca acea retragere. Subiectul **nu e inchis definitiv**: se redeschide dupa ce #13
+livreaza regenerarea si se vede in practica daca intretinerea celor doua drumuri doare cu adevarat.
+Pana atunci nu se reargumenteaza in niciun sens.
+
+**39. S4 ramane integrala: se desface si registrul de cantitate ramasa.** Proiectarea rundei 11 a aratat
+ca `crsarticole` nu e doar sursa gridului, ci **registrul cantitatii ramase de facturat** — scris de
+`do_sterge` la stergerea unei linii (`ofacturare.vc2:14640-14669`) si citit prin
+`Calculate Sum(cantitate) To lnCantitateRamasa` ca sa se decida **inchiderea automata** a comenzii /
+avizului (`:14303-14311`, `:14334-14338`). Varianta ieftina ar fi fost sa se restranga S4 la lista de
+preturi; Marius a ales varianta intreaga: **bookkeeping-ul se decupleaza de cursorul incarcat in masa**,
+ca sa poata disparea incarcarea si pe comanda si pe aviz.
+**Consecinta, declarata explicit:** S4 nu mai e o poveste de performanta pe formular, ci atinge
+**inchiderea automata a documentelor sursa** — cea mai mare suprafata de regresie din etapa I, si
+singura care poate lasa o comanda deschisa (sau o poate inchide prematur) fara ca operatorul sa vada
+ceva. Criteriul de „gata" al lui S4 include de acum, obligatoriu, **paritate pe inchiderea automata**:
+acelasi document sursa, aceleasi linii facturate partial, acelasi `INCHISA` la final, pe fiecare tip cu
+document sursa. Registrul nou trebuie sa fie sursa unica — nu o a doua copie tinuta in pas cu prima,
+altfel povestea introduce exact tipul de dublura pe care decizia 35 il refuza in alta parte.
+
+**40. Bug-ul de dezalocare POS se repara in S3b, in trecere.** Vezi `L.4`. Consecinta acceptata: diff-ul
+lui S3b **nu mai e o mutare pur mecanica**, deci testarea lui trebuie sa acopere si dezalocarea POS pe
+calea veche, nu doar paritatea de emitere.
+
+**41. Sectiunea pliata are DOUA comutatoare, nu unul si nu cinci.** Grupul de **incasare** — singurul cu
+efecte laterale reale (alocare / dezalocare de numere) si singurul blocat pe document emis prin decizia
+25 — primeste comutator propriu. Delegat/transport, adresa, text aditional si analiticele stau impreuna
+sub al doilea. Motivul e izolarea riscului: garda de non-alocare la toggle
+(`opt_incasat.ProgrammaticChange`) se scrie si se testeaza **intr-un singur loc**, nu pe cinci stari.
+
+**42. Validarea de curs valutar se restrange la valuta articolului cautat.** Pe varianta filtrata a
+cursoarelor, `verifica_cursuri_valute` nu mai ruleaza global, ci doar pe valuta randului adus.
+**Schimbare de comportament asumata:** un curs lipsa pe **alta** valuta nu mai e semnalat la deschiderea
+formularului, ci abia cand se ajunge la un articol pe acea valuta. Se consemneaza la testare ca
+diferenta intentionata fata de azi, nu ca regresie.
+
+#### Puncte marunte ramase din proiectarile rundei 11 — se merge pe recomandare daca Marius nu spune altfel
+
+Nu blocheaza nimic; se inchid la implementarea povestii respective. Enumerate ca sa nu se piarda intre runde.
+
+| # | Punct | Poveste | Se merge pe |
+|---|---|---|---|
+| a | Textul exact al tooltip-ului pentru grupul de incasare blocat (cel pentru analitice cade odata cu decizia 72) | S3b | formularea propusa in raport, sectiunea 5.3 |
+| b | Eager vs. lazy pentru lookup-urile Oracle din `Init` (delegat / masina ultimei facturi, casa) | S3b, S3 | **lazy**, ca sa nu se plateasca la fiecare depliere; deschis si in `s3_portare_antet.md` §5 |
+| c | `_checkbox1` vs. `chkDetaliat` — care devine campul unic de „listare detaliata" | S3b, S1 | **INCHIS (runda 12)**, pe cod: sunt **doua controale distincte** in `frm_alte_date`, nu o duplicare — nu exista nimic de ales. `docs\cercetare\s4c_discount_in_grid.md`, sectiunea 11 |
+| d | Forma lui `toSursa`: obiect scatter (duck-typing) sau clasa dedicata | S3c | **duck-typing**, ca azi — o clasa noua n-ar schimba nimic functional |
+| e | Conversia comenzii si a contractului: un commit sau doua | S3c | **un singur commit** — ating aceleasi trei fisiere comune, separarea nu reduce regresia, doar amana testarea pe ROACONTRACTE |
+| f | `goComanda = ''` redundant la `Cw3.do_actiune` dupa conversie | S3c | **se lasa**, marcat explicit „intentionat" in diff, ca sa nu para omisiune la review |
+| g | Contractul are doua meniuri (articole vs. rate): eticheta generica sau diferentiata pe `OPT_FACTURARE` | S4b | **diferentiata** — „Alege ratele de facturat…" e gresita pe contractele cu articole |
+| h | „Alege facturile de returnat…" ramane doar la antet sau capata incarcare aditiva din bara | S4b | **ramane la antet** in etapa I; mutarea e o poveste separata |
+| i | `But_renunt1` / `But_reset1` primesc `Caption` pentru consistenta cu bara etichetata | S4b | **da** — decizia 13 cere etichete, nu iconite mute; exceptia ar fi inconsecventa |
+| j | Ordinea si formularea optiunilor din `xmenu()` per sursa | S4b | tabelul din sectiunea 3 a raportului, ca propunere |
+| k | UX-ul contractului cu doua surse pe acelasi grid conceptual (`crsarticole` filtrat + `crsarticole1`) | S4 | de confirmat vizual la mockup, nu pe hartie |
+
+### Ce s-a dovedit ca exista deja (deciziile 10, 11, 12, 14)
+
+Verificat pe cod la 09.08.2026; rapoartele complete sunt in `docs\cercetare\`
+(`proforma_copiere_puncte_intrare.md`, `discount_pe_articol.md`,
+`inventar_controale_formulare.md`, `import_roris_roaacnpro.md`).
+
+- **Proforma nu e tip de document si nu are formular propriu.** E valoarea `PROFORMA` din combo-ul
+ „Tip document” (`ct_clb_fdoc._combobox1`, `RowSource = "FACTURA,PROFORMA,BON FISCAL"`,
+ `ofacturare.vc2:8745-8754`), care seteaza `nIdTipDoc = 23` si, prin setter,
+ `eProforma = 1` (`ofacturare_comun.prg:593-599`, `nIdTipDocProforma = 23` la `:104`). Deci intra in
+ formularul unificat **fara nimic de portat**. Specific proformei si de pastrat: serie si numar
+ proprii, realocate la comutarea din combo (`ofacturare.vc2:9415,9427-9428`); **fara nota contabila
+ si fara atasamente**, prin garzile `poDate.eProforma = 0`
+ (`ofacturare.prg:1960,1996,2052,2063,2103`); raport propriu (`:1638-1643`, `COMUN\Rapoarte\proforma.fr2`);
+ relistarea pe cale separata (`ofacturare_comun.vc2:7230-7264`).
+- **Copierea foloseste deja acelasi formular, cu antetul editabil.** `do_copiaza` -> `copiere_factura`
+ -> `factureaza(tip, toFactura)` -> `frm_date_factura` precompletat de
+ `completeaza_setari_document(toFactura, .T.)` (`ofacturare_comun.prg:362-412`). Numar nou se aloca
+ **intotdeauna**, neconditionat de copiere (`ofacturare.prg:208,211`). Nimic din traseu nu blocheaza
+ controale de antet.
+- **Butonul de facturare din pagina de comenzi exista deja in ROAFACTURARE**: `ct_comenzi.do_factura`
+ (`ocomenzi.vc2:1580-1596`) face `SCATTER NAME goComanda MEMO` si cheama `facturare_comenzi` ->
+ `factureaza(3)`; butonul `But_factura1` (`ocomenzi.vc2:932-937`) e ascuns cand comanda e deja
+ facturata (`:2199-2203`), si e montat pe Page5 (`ofundal_facturare.vc2:604`, `Ferestre\fundal.sc2:206`).
+- **Precompletarea contractului vine din programul de contracte** (`ROACONTRACTE`):
+ `ferestre_contracte.vc2:1538-1549` si `:1605` -> `facturare_contracte` -> `factureaza(2/6/52)`,
+ cu contractul deja completat — exact ce cere decizia 12, si **functioneaza azi**. In ROAFACTURARE
+ exista, in plus, calea din meniu **fara** precompletare (`ofundal_facturare.vc2:886-897`), unde
+ utilizatorul alege contractul in formular. Cele doua coexista; #13 nu adauga o lista de contracte
+ in ROAFACTURARE si **nu depinde de #10**.
+- **Discountul pe articol are deja si procent, si valoare — dar intr-un dialog separat.** Vezi K.
+- **Deblocarea antetului exista deja**, dar sub forma a patru bife individuale in
+ `frm_modifica_factura`; in formularul unificat ele sunt inlocuite de un singur buton comutator.
+ Vezi I.
+- **Data cursului valutar nu e conditionata azi de valuta.** Vezi M.
+
+### Canalul de precompletare e un global, nu un parametru
+
+`factureaza(tnTip, toFactura)` (`ofacturare.prg:81-82`) nu are parametru pentru sursa: comanda si
+contractul se transmit prin globalele `goComanda` / `goContract`, citite in `oDateFactura.Init`
+(`ofacturare_comun.prg:301-328` comanda, `:261-297` contract). De aceea calea generica de comanda e
+obligata sa scrie explicit `goComanda = ''` inainte de apel (`ofundal_facturare.vc2:899-902`), altfel
+ar ramane precompletata cu ce era in sesiune. **Calea generica de contract nu face resetarea
+simetrica** (`:886-897`) — de verificat daca `goContract` poate ramane populat intr-o sesiune si
+precompleta tacit un document nou. Decizia 12 se implementeaza corect prin **parametru explicit**, nu
+prin inca un global.
+
+## Relatia cu #6 — transata: #13 incepe dupa #6
+
+`plan_06_editare_factura.md` rezolva **aceeasi problema de fond** (o factura emisa nu se poate
+corecta fara ca notele si rulajele sa ramana in urma) pe calea opusa: editare directa in
+`frm_modific2024`, cu `id_fact` pastrat. Planul #6 a respins explicit regenerarea, cu motivul ca
+*"emiterea face verificari de stoc si alte protectii dependente de tipul documentului; la
+regenerare acestea ar esua pe date care intre timp s-au schimbat"*.
+
+Argumentul acela **cade partial** daca stergerea si reemiterea se fac in aceeasi tranzactie, in
+ordinea corecta — vezi sectiunea "Stocul" mai jos. Dar nu cade complet: raman verificarile care nu
+tin de stoc (configurare politica / contract / cota TVA, vezi `adauga_articol_factura`).
+
+Cele doua nu se exclud tehnic, dar **se suprapun pe aceleasi fisiere** si, mai important, produc
+doua semantici diferite pentru "am corectat factura":
+
+| | #6 — editare directa | #13 — regenerare |
+|---|---|---|
+| Punct de intrare | registru jurnal + formular facturi | formularul de facturi |
+| Utilizator vizat | contabil | operatorul de facturare |
+| `ID_FACT` | pastrat prin constructie | **pastrat, prin cerinta** (vezi E) |
+| Serie, numar, data | neschimbate | neschimbate (cale proprie, vezi F) |
+| `COD`, `ID_VANZARE` | `COD` nou, `ID_VANZARE` pastrat | ambele noi |
+| Notele si rulajele | rescrise din formularul de note | **regenerate din articole**, ca la emitere |
+| Documentul sursa (comanda/aviz/contract) | neatins | **eliberat si reconsumat** |
+| Efort | mediu (in curs, S1–S3 livrate) | mare |
+
+**Decizia lui Marius (09.08.2026): coexista, cu roluri separate.** #6 ramane calea contabilului
+pentru corectii pe nota — si e singura cale posibila din registrul jurnal din ROACONT/ROAGEST, unde
+nu exista contextul de facturare (`poDate`, `crsfactura`, politici, serii). #13 devine calea
+operatorului de facturare: modific documentul, notele si rulajele se refac singure.
+
+**Coliziune de lucru: nu exista. DECIS (decizia 30): #13 incepe dupa ce #6 se termina.** Sesiunea de
+la #6 a atins `COMUN\clase\ofacturare_comun.vc2` (`do_editare_factura`, `:3715-3869`), a creat
+`COMUN\programe\ofacturare_editare.prg` si a adus `omodificari.vcx` in proiect (`97d1613`) — dar
+implementarea lui #13 nu porneste cat timp acestea sunt in lucru, deci **nu e nevoie nici de
+impartire de perimetru, nici de coordonare intre fire.** Cele doua buguri semnalate (L.0 si L.0-bis)
+raman semnalate catre #6, nu reparate din #13.
+Decizia 26 — analiticele read-only in #13 — era tinuta aici pe motiv semantic (#6 le editeaza la nivel
+de linie de nota, #13 le-ar scrie uniform pe tot documentul), nu de calendar. **Decizia 72 o rastoarna**:
+analiticele sunt editabile, iar scrierea uniforma pe document e acceptata ca efect al regenerarii.
+
+---
+
+## Ce s-a stabilit din cod
+
+### A. Formularul unificat exista deja ca prototip, oprit din 2017
+
+`frm_facturare_articole2` (`COMUN\clase\ofacturare.vc2:15741-19355`) **este** formularul cerut la
+punctul 13, la nivel de controale:
+
+- are deja campurile de antet mutate din `frm_date_factura`: `Clb_serie_act1`, `Clb_nract`,
+ `Clb_dataact`, `Clb_zi_curs`, `Clb_data_scadenta`, `Ct_clb_nume_client`, `Ct_clb_responsabil`,
+ `Ct_clb_sectie`, `Ct_clb_lucrare`, `Ct_clb_venchelt`, `Ct_clb_altele`, `Ct_clb_valuta`,
+ `clb_fdoc`, `Ed_tx_simplu1` (`:15744-15812`);
+- **nu** are `grd_articole`, `grd_contracte`, `cb_politici_preturi`, `cb_contracte`, casetele de
+ cautare `txtCodmat` / `txtArticole` — adica exact partea care azi consuma incarcarea in masa;
+- are grid editabil in linie, cu combouri `combosql` din `cautare.vcx` pe `cCodMat.cboCodmat`,
+ `cDenumire.cCboDenumire`, `cGestiune.cCboGestiune` (`:16751-16881`), plus `But_nou1`;
+- e lansat de `factureaza2` (`COMUN\programe\ofacturare.prg:590-1080`), care se cheama numai daca
+ `gnFacturareNou = 1` **si** utilizatorul raspunde DA la un `AMESSAGEBOX` (`:87-92`).
+
+**Cat de mort e prototipul.** In `factureaza2`, deschiderea formularului de date si incarcarea
+articolelor sunt inchise cu `If .F.`: `:707-711` (formularul de date), `:826-829` (executia
+cursorului de articole), `:838` (verificarea de "nu exista articole"), `:985-1008` (`crspolitici`
+si `crscontracte`). `Init`-ul lui `frm_facturare_articole2` are 92 de linii (`:18988-19080`) fata
+de 368 la `frm_facturare_articole` (`:14976-15344`) si **nu completeaza niciun camp de antet** —
+controalele sunt acolo, logica nu.
+
+**Drift-ul dintre `factureaza` si `factureaza2`** (fork din 08.06.2017, nesincronizat): lipsesc din
+`factureaza2` tipurile 51 si 52, ramura `llCopiere` / `toFactura`, completarea `codmatc` /
+`codnc8` / `codcpv`, `GetInstitutiePublica`, `GetSoldClient`, filtrul `RORTC` pe `jtva_coloane`,
+tratarea `eProforma`, `verifica_numar(16, ...)` pentru chitanta, `cursor_retur_document`,
+`cursor_avize` cu tip 23. **Concluzie: nu se continua cu doua proceduri.** Se merge pe una singura,
+cu un parametru de mod, altfel divergenta se reia imediat (exact tiparul care a produs problema
+reparata la #8).
+
+### B. Nu doua formulare, ci patru
+
+Fluxul de azi are **patru** ferestre. Runda 2 numarase trei; a patra, `frm_articol_factura`
+(`ofacturare.vc2:1108-2659`), se deschide **pentru fiecare articol adaugat**, din
+`do_adauga_articol` (`:12873`, `ofrmadarticol.Show(1)`, doar daca `!tlImplicit`) — si e locul in care
+se introduce azi discountul pe linie (vezi K). Formularul unificat o desfiinteaza, deci campurile ei
+trebuie sa aiba unde sa se mute.
+
+Celelalte trei:
+
+1. `frm_date_factura` (`ofacturare.vc2:8482-9869`) sau `frm_date_aviz` (`:6566-7618`) —
+ 17, respectiv 13 metode `do_cauta_*`, plus `do_schimba_tipdoc`, `inainte_de_do_termin` si un
+ `Init` de 234 / 247 de linii;
+2. `frm_facturare_articole` (`:10968-15739`) — compunerea;
+3. `frm_alte_date` (`COMUN\clase\ferestre_cere_date.vc2:2219-3353`) — **aratat dupa** confirmarea
+ articolelor, din `inainte_de_do_termin` (`ofacturare.vc2:14921-14941`): delegat, auto, agent,
+ adresa de facturare, incasare (numerar / chitanta / bon fiscal / POS), text aditional. Aloca si
+ numere proprii (bon fiscal, POS, chitanta).
+
+Punctul 13 vorbeste doar despre primele doua. **Decizia 7 le aduce pe toate trei**: `frm_alte_date`
+intra in formular, ca zona pliata. Recomandarea din runda 2 („ramane dialog in prima etapa”) e
+respinsa.
+
+Ce inseamna concret, din inventarul de controale: se muta patru grupuri — delegat si transport
+(`Ct_clb_delegat`, `Ct_clb_masina`, `Ct_clb_agent`, `Clb_dataora_exp`), incasare (radiogrupul
+`opt_incasat` cu patru optiuni, `Cb_casa`, `Clb_serie_chit`, `Clb_nrchit`, `Clb_incasat`,
+`cmdModificaBon`, `chkPOS`, `chkDetaliat`, `cboTipFactura`), adresa de facturare
+(`clb_adresa_facturare`) si textul aditional (`Ed_tx_simplu1`) —
+`ferestre_cere_date.vc2:2343-2638`. **Masina de stari se muta ca atare, nu se rescrie**:
+`actualizeaza_tipincasare` (`:2698-2856`) comuta vizibilitatea pe cele patru valori si aloca sau
+dezaloca numarul de chitanta (`:2783`), de bon fiscal (`:2807`) sau de POS (`:2844`). Riscul semnalat
+in runda 2 nu dispare, dar e localizat: **alocarea de numere trebuie sa ramana legata de aceleasi
+evenimente**, nu de deschiderea formularului.
+
+Peste ele coboara analiticele din antet (decizia 8): `Ct_clb_venchelt`, `Ct_clb_sectie`,
+`Ct_clb_responsabil`, `Ct_clb_lucrare`.
+
+### C. Incarcarea articolelor — de ce dureaza si ce inlocuieste
+
+`factureaza` executa, inainte de a deschide compunerea, **un singur apel** care aduce toate
+articolele disponibile: `pack_facturare.cursor_preturi` (`ofacturare.prg:281-286`, corp la
+`PACK_FACTURARE:2121+`), respectiv `cursor_contract` / `cursor_comanda` / `cursor_avize` /
+`cursor_gestiune` / `cursor_retur` dupa tip (`ofacturare.prg:265-311`). Rezultatul intra in
+`crsarticole` si tine gridul de sus.
+
+`cursor_preturi` **nu are filtru pe articol** — semnatura e
+`(V_DATA_CURS, V_TIP, V_ID_VALUTA, V_ID_GESTIUNE_INIT, V_LUNA, V_AN, V_ID_UTIL, V_ID_SUCURSALA)`
+(`PACK_FACTURARE:335-343`). De aici vin miile de randuri.
+
+Mecanismul de inlocuire **exista deja**, in prototip: `combosql` cauta pe server, incremental, cu
+`csourcesql = select codmat, denumire, um, grupa, subgrupa, codbare, id_articol from vnom_articole`
+si `csourcewhere = inactiv = 0` (`ofacturare.vc2:16751-16766`).
+
+**Dar `vnom_articole` e nomenclatorul, nu lista de preturi.** Nu are pret, nota contabila, cota TVA,
+valuta, `id_pol`, `gestionabil`, `pret_cu_tva` — toate vin azi din `cursor_preturi`. Deci partea
+Oracle a lucrarii e o **varianta filtrata pe articol** a cursoarelor de facturare, apelata la
+alegerea liniei, nu la deschiderea formularului. Nu e o simplificare: ramurile pe tip din
+`cursor_preturi` (restaurant, custodie, retur, contract, comanda) trebuie pastrate identic, altfel
+pretul difera intre cele doua cai.
+
+**Legatura cu #12.** Daca articolul poate purta el insusi pretul si nota contabila (varianta C din
+`plan_12`), cautarea in linie devine directa si nu mai are nevoie de o rezolvare separata a listei
+de preturi. #13 nu depinde de #12, dar cine face #12 dupa #13 va rescrie exact bucata asta.
+
+### D. Regenerarea — piesele exista, montajul nu
+
+**1. Stergerea elibereaza deja documentul sursa.** `pack_facturare.sterge_factura`
+(`PACK_FACTURARE:5415-5591`) face, pe langa `sters = 1` pe `VANZARI` si `VANZARI_DETALII`:
+
+- `FACTURAT = 0, ID_UTILFACT = NULL, DATA_FACTURAT = NULL` pe avizele facturate (tip 4 si 24);
+- `STERS = 1` pe `VANZARI_CANTITATI` (cantitatile consumate de pe avize);
+- `STERS = 1` pe `COMENZI_ELEMENTE` cu `CANTITATE < 0` (consumul din comanda);
+- `STERS = 1` pe `VANZARI_CORESP` si pe `CTR_RATE_FACTURI` (contracte in rate, tip 2/6/52).
+
+Adica **exact reversul consumului sursei** — conditia ca reemiterea sa poata reconsuma aceeasi
+comanda / acelasi aviz / aceeasi rata. Sunt si garzi: refuza stergerea daca s-au emis facturi sau
+avize de retur peste document (`:5432-5477`).
+
+**2. Calea VFP de stergere completa exista.** `frm_facturi.do_sterge`
+(`COMUN\clase\ofacturare_comun.vc2:4658-4874`): tranzactie manuala, `oscrie_in_fisiere`, apoi
+`pack_contafin.finalizeaza_stergere_nota` (care cheama `sterge_din_vanzari`). Rulajele si notele
+dispar pe aceasta cale, nu prin `sterge_factura`.
+
+**3. Reconstituirea liniilor exista.** `pack_facturare.cursor_retur_document(..., V_COPIERE = 1, ...)`
+(`PACK_FACTURARE:3932-4045`) reface liniile din `VANZARI_DETALII`, cu `explicatie`, `id_gestiune`,
+`pret_achizitie`, `pretd`, `id_jtva_coloana`, `id_jtva_coloana_ex`, `lot`, `serie`, `id_pol`,
+`pret_cu_tva`, plus `curs` / `multiplicator` din `VANZARI_CURSURI`. E deja folosita, exact asa, la
+copierea unei facturi.
+
+**4. "Redeschide formularul precompletat" exista.** `frm_facturi.do_copiaza`
+(`ofacturare_comun.vc2:3640-3713`) -> `copiere_factura` (`oproceduri_facturare.prg:150-153`) ->
+`factureaza(tip, toFactura)`, iar in `factureaza` ramura `llCopiere` (`ofacturare.prg:255-257`,
+`:458-473`) incarca liniile documentului si adauga peste ele lista de preturi, ca sa se poata
+adauga articole noi. `oDateFactura.completeaza_setari_document(toFactura, .T.)`
+(`COMUN\programe\ofacturare_comun.prg:362-412`) precompleteaza antetul.
+
+**Ce nu se poate refolosi ca atare:** `do_copiaza` **degradeaza intentionat tipul** — factura din
+contract / comanda / aviz devine `tip = 1`, avizele devin `22`, transferurile `10`
+(`ofacturare_comun.vc2:3696-3710`), cu comentariul *"nu are sens sa fie copiata, dar o tratez ca pe
+o factura din lista de preturi"*. La regenerare, degradarea e **exact ce nu trebuie sa se intample**:
+documentul nou trebuie sa ramana pe acelasi tip, ca sa reconsume sursa. Deci se cloneaza structura
+lui `do_copiaza`, nu comportamentul.
+
+### E. `ID_FACT` — cerinta si ce presupune ea
+
+**Cerinta (decizia 2):** documentul reemis pastreaza `ID_FACT`.
+
+**Starea de azi, verificata:** `ID_FACT` se genereaza cu secventa, neconditionat.
+`PACK_CONTAFIN.SET_IDFACT(V_GCS)` e `SELECT SEQ_IdFact.NEXTVAL`
+(`COMUN\docs\PACK_CONTAFIN.pck:3037-3040`), citit cu `get_idFact()` (`:725`), iar `DOCUMENTE`
+primeste rand nou cu acel `ID_DOC` (`:796-808`).
+
+**Dar intuitia „id_fact depinde de numar si data" e corecta istoric:** exista in pachet varianta
+`SET_IDFACT(tdDataAct, tcSerie_Act, tnNrAct, tnId_Ctr)` care cauta intai in `DOCUMENTE` dupa
+`NRACT` + `SERIE_ACT` + `DATAACT` + `ID_CTR` si ia secventa doar la `NO_DATA_FOUND`
+(`:3016-3035`) — **comentata**, deci inactiva.
+
+**Ce inseamna pentru #13** (de proiectat in S9, dupa verificarea din handoff):
+
+- fie se reactiveaza cautarea, sub un comutator folosit **numai** de regenerare — modificarea lui
+ `SET_IDFACT` fara comutator ar schimba comportamentul pentru toata suita, ceea ce nu se face;
+- fie se transmite `ID_FACT`-ul cunoscut, ca parametru, pe drumul de scriere;
+- **capcana de ordine**: cautarea filtreaza `STERS = 0`. Daca documentul vechi e marcat sters
+ inainte, cautarea nu-l mai gaseste si se genereaza id nou. Deci `ID_FACT`-ul se citeste **inainte**
+ de stergere, in aceeasi tranzactie.
+
+Cu `ID_FACT` pastrat, ce ramane de inventariat e mult mai putin decat in varianta cu id nou:
+`ATASAMENTE_VANZARI` si `marcheaza_facturat` merg pe `ID_VANZARE` (care **se schimba**),
+`ANAF_EFACTURA` e gol prin garda, iar `DOCUMENTE` / `ACT` / `RUL` / `JV2007` / `IREG_PARTENERI` merg
+pe `ID_FACT` (pastrat). **`ID_VANZARE` nou ramane singura discontinuitate reala** — de verificat
+daca `DOCUMENTE` primeste un al doilea rand pe acelasi `ID_DOC` sau il refoloseste.
+
+### F. Serie, numar, data — cale proprie, nu regenerare
+
+**Cerinta (deciziile 3 si 4):** toate datele se pastreaza, inclusiv numarul; iar antetul care intra
+in identitatea documentului se modifica pe cale proprie.
+
+Calea exista deja si e exact ce trebuie: `pack_facturare.modifica_date_factura`
+(`PACK_FACTURARE:14392-14463`) face `UPDATE` in loc si **propaga serie / numar / data / scadenta
+pe `VANZARI`, `DOCUMENTE`, `ACT`, `IREG_PARTENERI`, `JV2007`, `RUL`, dupa `ID_FACT`**
+(`:14427-14460`). Tot ea scrie delegat, agent, masina, adresa de facturare, text aditional,
+`dataora_exp`, `listare_detaliata`, `tip_saft`, `efactura`. E procedura din spatele actiunii de azi
+`frm_facturi.do_modifica` -> `frm_modifica_factura`.
+
+**Deci in formularul unificat:** campurile de antet se scriu prin `modifica_date_factura`, nu prin
+regenerare. Regenerarea porneste doar pentru ce atinge sumele. Vezi tabelul din G-bis.
+
+`oGeneratorNumere` (`COMUN\programe\oserii_numere.prg:227-233`) nu incurca: la modificare nu se
+aloca numar nou, deci nu e nimic de dezalocat. Intrebarea despre o eventuala constrangere de
+unicitate pe `VANZARI(SERIE_ACT, NUMAR_ACT)` **dispare** — nu mai exista doua documente nesterse cu
+acelasi numar, pentru ca numarul nu se realoca; ramane doar cazul „vechi sters + nou nesters", care
+e exact situatia de azi de la orice stergere si reintroducere.
+
+### G-bis. Cele trei modificari de azi, si ce se scrie la confirmare
+
+Pe `frm_facturi` exista azi trei actiuni care ating acelasi document, fiecare cu fereastra ei:
+
+| Actiune de azi | Formular | Ce atinge | Sursa |
+|---|---|---|---|
+| `do_modifica` | `frm_modifica_factura` | antet: ruta, delegat, agent, serie, numar, date | `ofacturare_comun.vc2:4538-4637` |
+| `do_modifica_explicatie` | `frm_modifica_articol_factura` | `explicatie` + `taxcode` pe o linie | `:4639-4656` |
+| `do_editare_factura` (#6) | `frm_modific2024` | nota contabila si rulajele | `:3715-3869` |
+| — | — | **cantitati, preturi, linii: nicaieri** | — |
+
+Decizia 6 le comaseaza in formularul unificat. Ruta de scriere se alege dupa ce s-a schimbat:
+
+| Ce s-a schimbat | Cum se scrie | Efect |
+|---|---|---|
+| Serie, numar, data, scadenta, delegat, auto, agent, adresa facturare, text aditional | pe loc, `modifica_date_factura` | propaga dupa `ID_FACT` |
+| Explicatia si `taxcode` pe o linie | pe loc, `modifica_explicatie_articol` (`PACK_FACTURARE:14464-14472`) | doua coloane, nicio suma |
+| Cantitati, preturi, linii adaugate/sterse, discount, gestiune, cota TVA | **regenerare** | vechiul `sters = 1`, documentul nou scris pe drumul de emitere, note si rulaje refacute |
+| Nimic | nimic | documentul nu se rescrie degeaba |
+
+Ultima linie nu e cosmetica: fara ea, orice deschidere a formularului ar produce un document nou si
+ar umple `VANZARI` cu randuri sterse.
+
+**Gol descoperit la S1 (runda 7): tabelul de mai sus nu acopera tot antetul.** Inventarul camp-cu-camp
+(`docs\S1_inventar_campuri_formular_unificat.md`) a gasit trei grupuri de campuri de antet care **nu
+sunt printre cei 14 parametri** ai lui `modifica_date_factura` si pentru care nu s-a gasit alta ruta:
+
+- **analiticele** — venit/cheltuiala, sectie, responsabil, lucrare (grupul „Pliat — analitice” din I);
+- **identitate/sursa, altele decat serie/numar/data/scadenta** — tip document, valuta, zi curs, client,
+ sursa/„altele”, gestiune sursa, politica de preturi;
+- **grupul de incasare** — mod incasare, casa, serie si numar de chitanta/bon, suma incasata, POS.
+
+**Verificat (runda 7): `docs\cercetare\rute_scriere_antet.md`.** Cautare exhaustiva in ambele straturi
+— Oracle (pachetul de facturare curent, plus `PACK_CONTAFIN`, `PACK_UPDATE`, `PACK_MIGRARE`; toate
+cele 13 aparitii de `UPDATE VANZARI` inspectate individual) si VFP (indexul complet: 316 fisiere,
+1128 clase, 9281 metode). Rezultatul e neuniform pe cele trei grupuri:
+
+| Grup | Verdict | Ce inseamna |
+|---|---|---|
+| **B** — tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi | **NU**, toate sapte | Controalele traiesc **exclusiv** in wizardul de emitere; nu exista niciun `UPDATE` care sa le atinga dupa emitere. Un „nu" verificabil, nu o absenta de cautare. |
+| **C** — mod incasare, casa, serie/nr chitanta, suma, POS | **NU direct** | Nu exista coloane proprii pe `VANZARI`: incasarea devine ea insasi **o linie de nota contabila** (`scrie_incasare2`). Nicio procedura de tip „modifica incasare". |
+| **A** — sectie, responsabil, lucrare | **DA** | Dar nu prin `modifica_date_factura`, ci prin **mecanismul lui #6**, aterizat chiar pe branch-ul asta (`97d1613`). Vezi mai jos. |
+| **A** — venit/cheltuiala (`ID_VENCHELT`) | **neconfirmat** | Gridul afiseaza coloana `dst_chlt`, dar `do_modifica` nu are caz pentru ea. |
+
+**Descoperirea care conteaza: analiticele sunt deja editabile, dar din #6.** `frm_facturi.do_editare_factura`
+(`ofacturare_comun.vc2:3690-3869`) e acum cablat la `frm_modific2024` (`omodificari.vc2`), incarca
+nota contabila a documentului emis si o rescrie prin `OSCRIE_IN_FISIERE` ->
+`pack_contafin.finalizeaza_modificare_nota`, care **resincronizeaza `VANZARI`**. `do_modifica`
+(`omodificari.vc2:13934-13943`) trateaza explicit `id_lucrare` si `id_responsabil`.
+
+**Doua nuante care schimba proiectarea, nu doar inventarul:**
+1. **Editarea e la nivel de LINIE de nota, nu de antet.** La emitere, cele patru analitice se scriu
+ uniform pe tot documentul, din variabilele de sesiune. Prin editorul lui #6, fiecare linie se poate
+ edita separat — deci un document poate ajunge cu **sectii diferite pe linii diferite**, stare
+ imposibila la emitere. Conteaza pentru orice raportare care presupune „un singur `ID_SECTIE` per
+ factura".
+2. **Bug suspectat pe `sectie`** (`omodificari.vc2:13941`): `replace ... id_valuta with
+ loCauta.id_sectie` — pare sa scrie in `id_valuta` in loc de `id_sectie`. Daca e real, textul afisat
+ se schimba dar coloana nu. **E in perimetrul lui #6** — se semnaleaza, nu se repara aici. Pana la
+ verificare, „DA" pentru `ID_SECTIE` e un da cu rezerva.
+
+**Consecinta pentru decizia 9**, acum pe fapte: `but_modifica` **poate salva pe loc doar cei 14
+parametri**. Pentru grupurile B si C nu exista alta cale decat **regenerarea**, care le rescrie oricum
+pe toate, fiind chiar drumul de emitere. Pentru grupul A exista o a treia cale, dar e a lui #6 si
+lucreaza pe alt nivel (linie de nota).
+
+**Tabelul de rutare, completat (deciziile 25 si 26):**
+
+| Ce s-a schimbat | Cum se scrie |
+|---|---|
+| cei **14 parametri** (serie, numar, data, scadenta, ruta, delegat, masina, agent, `dataora_exp`, adresa facturare, text aditional, `listare_detaliata`, `tip_saft`, `efactura`) | **pe loc**, `modifica_date_factura` |
+| explicatia si `taxcode` pe o linie | **pe loc**, `modifica_explicatie_articol` |
+| cantitati, preturi, linii, discount, gestiune, cota TVA | **regenerare** |
+| **grupul B** — tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi | **regenerare** (decizia 25); blocate in etapa I |
+| **grupul C** — incasare | **regenerare** (decizia 25); blocate in etapa I |
+| **grupul A** — venit/cheltuiala, sectie, responsabil, lucrare | **regenerare** — editabile si la introducere, si la reemitere (decizia 72, rastoarna 26) |
+| nimic | nimic |
+
+### G. Stocul — de ce argumentul lui #6 nu inchide subiectul
+
+Verificarea de stoc **nu** e in `adauga_articol_factura`: acolo erorile sunt de configurare
+("Nu a fost gasita cota de TVA", politica / contract lipsa — `PACK_FACTURARE:5125-5180`).
+Descarcarea efectiva de gestiune se face la emitere, in `contabilizeaza_articol` ->
+`descarca_gestiune` (`:7631+`). Plafonul pe cantitate pe care il vede utilizatorul azi vine din
+**cursorul client** `crsarticole` (`frm_facturare_articole.do_adauga_articol`,
+`ofacturare.vc2:12813-13086`) — cursor care in formularul unificat **nu mai exista**, pentru ca nu
+se mai incarca in masa.
+
+Deci, pe #13:
+
+- in timpul compunerii **nu exista plafon** — coincide cu decizia deja luata de Marius pe #6 la
+ 08.08.2026 ("editarea unei facturi emise nu are plafon si nu verifica stocul");
+- la finalizare, daca **stergerea ruleaza inaintea reemiterii, in aceeasi tranzactie**, stocul
+ consumat de documentul initial e deja eliberat cand se descarca gestiunea pentru documentul nou.
+
+**Aici e riscul tehnic principal.** Azi stergerea si emiterea deschid fiecare propria tranzactie
+(`do_deschide_tranzactie` / `do_inchide_tranzactie` in ambele cai). O tranzactie nu poate fi tinuta
+deschisa peste minutele in care utilizatorul editeaza formularul. Ordinea corecta e deci:
+**citire (fara tranzactie) -> editare -> o singura tranzactie la confirmare, care contine intai
+stergerea, apoi scrierea.** Asta cere mutarea apelului de stergere in interiorul tranzactiei
+deschise de `do_scrie_articole`, nu inaintea ei.
+
+Atentie si la `VANZARI_DETALII_TEMP`, care e GTT `ON COMMIT DELETE ROWS`: umplerea si consumul
+trebuie sa ramana in aceeasi tranzactie — ceea ce e compatibil cu schema de mai sus, dar interzice
+un `commit` intermediar dupa stergere.
+
+### H. Pretul rescris de server la reemitere
+
+`adauga_articol_factura` (`PACK_FACTURARE:4972-5268`) ramifica pe `V_OPT_FACTURARE` si, pe unele
+ramuri, **re-deriva pretul, cota TVA si valuta din documentul sursa** (ex. `V_OPT_FACTURARE = 3`,
+preturile de pe contract, `:5129-5168`), in timp ce pe ramura implicita valoarea venita din VFP
+castiga (`V_PRET := V_PRET_TEMP`, `:5183-5186`). Planul #6 semnalase deja acelasi lucru.
+
+**Consecinta pentru #13:** pe facturile din contract (si posibil pe alte ramuri), pretul editat de
+utilizator poate fi suprascris tacut la reemitere. De inventariat ramura cu ramura, si de decis daca
+regenerarea trece un flag "preturile vin din formular, nu se re-deriva". **Nu se porneste
+implementarea inainte de acest inventar** — e singurul punct din care poate iesi o factura reemisa
+cu alte sume decat cele confirmate pe ecran.
+
+### I. Asezarea antetului (deciziile 8 si 9)
+
+**Doua grupuri vizibile, restul pliat.** Grupurile si etichetele reale, din inventar:
+
+| Grup | Controale | Note |
+|---|---|---|
+| Identitatea documentului | `Ct_clb_fdoc` („Tip document”: FACTURA / PROFORMA / BON FISCAL), `Clb_serie_act`, `Clb_nract`, `Clb_dataact`, `Clb_data_scadenta`, `Clb_zi_curs`, `Ct_clb_valuta` | scadenta e **dezactivata**, nu eliminata, cand `gnScadentaAutomata = 1` (`ofacturare.vc2:9713-9715`); ziua de curs se elimina pe retur (`:9717-9722`, tipurile 8 si 9 — nu si 24); valuta se elimina cand `in_valuta = 0` (`:9725-9728`) |
+| Partener si sursa | `Ct_clb_nume_client`, `txtCodFiscal` + `But_verifica1` (ANAF), `txtSoldLei`, `Ct_clb_altele` (sursa), `Ct_clb_gestiune_init`, pe aviz `Ct_clb_politici_preturi` | codul fiscal si soldul sunt read-only si derivate |
+| **Pliat** — analitice | `Ct_clb_venchelt`, `Ct_clb_sectie`, `Ct_clb_responsabil`, `Ct_clb_lucrare` | responsabilul si gestiunea sursa se elimina azi cand `gnScadereStoc = 0` sau tipul e 4/7/8/9/48/49 (`ofacturare.vc2:9646-9707`) |
+| **Pliat** — alte date | cele patru grupuri din `frm_alte_date`, vezi B | |
+
+**Butonul de modificare a antetului (decizia 9).** Mecanismul **exista deja**, si e mai fin decat
+credeam: `frm_modifica_factura` (`ofacturare_comun.vc2:5262-5774`) are **patru bife individuale** —
+`chkSerieAct`, `chkNrAct`, `chkDataAct`, `chkDataScad` — fiecare deblocand exact textbox-ul ei
+(`thisform.txtDataAct.Enabled = this.Value`, `:5758-5772`), si toate patru sunt ele insele inactive
+daca documentul nu are numar (`this.chkSerieAct.Enabled = !EMPTY(NVL(poRec.numar_act,0))`,
+`:5736-5750`). **Restul campurilor de antet nu sunt blocate deloc** — delegat, agent, masina, ruta,
+adresa, dataora expediere, text aditional sunt mereu editabile.
+
+In formularul unificat (**decizia 9, forma finala — un singur buton comutator, fara nicio bifa**):
+
+- in bara panoului de antet sta **un singur `but_modifica`**; apasat, deblocheaza **tot antetul** —
+ si campurile „moi”, si cele patru de identitate — si **isi schimba imaginea in discheta lui
+ `but_salvare`**; documentul deschis pentru consultare ramane inert;
+- **cele patru bife individuale dispar.** Nu se transpun in formularul unificat sub nicio forma:
+ butonul e singurul control de protectie a antetului;
+- **si conditia lor se abandoneaza.** Azi bifele de serie si numar sunt ele insele inactive dupa
+ `!EMPTY(NVL(poRec.numar_act,0))` (`:5736-5750`); regula asta nu se mai transpune pe campuri.
+ Cu antetul deschis, **toate campurile de antet sunt editabile, fara exceptie si fara conditie de
+ stare**. E o pierdere deliberata de protectie, in schimbul unei singure reguli inteligibile:
+ antet blocat sau antet deschis, atat;
+- a doua apasare **salveaza doar antetul**. E posibil pentru ca
+ `do_modifica` cheama azi **exclusiv** `pack_facturare.modifica_date_factura`, cu 15 parametri toti
+ de antet, si niciun apel spre articole, note sau `oscrie_in_fisiere` (`ofacturare_comun.vc2:4587-4630`).
+ Acopera cazul „vreau sa corectez doar delegatul”.
+ **Precizare, ca sa nu se citeasca gresit:** „nu atinge notele si rulajele” e adevarat **la nivel de
+ apel VFP**, nu si in Oracle. Corpul procedurii propaga seria, numarul si datele in `JV2007` si `RUL`
+ (`PACK_FACTURARE.pck:14428-14459`) — coloane de **identitate**, nu sume: nicio valoare nu se
+ recalculeaza. Pentru celelalte zece campuri, scrierea e strict in `VANZARI`. Vezi I-bis.
+- **`Termina` ramane salvarea intregului document**, cu rutarea din G-bis.
+
+**Ce nu exista si trebuie scris:** containerele efectiv folosite in antet nu au un mecanism gata
+facut de blocare. `ct_clb_cautare` are `do_activeaza` / `do_dezactiveaza` (`caut_ora.vc2:780-806`),
+dar acestea doar ascund iconita de cautare, iar in `ofacturare_comun.vc2` nu sunt apelate nicaieri;
+`clb_tx_simplu` (`lb_tx.vc2:551-585`) si `clb_serie_act` (`serii_numere.vc2:7`) **nu au deloc**
+metode de activare. Singura reteta completa din biblioteca e `clb_tx_data.dezactiveaza()` /
+`reactiveaza()` (`lb_tx.vc2:521-538`: `ReadOnly` + `TabStop` + butonul de calendar) — se
+generalizeaza de la ea, nu se inventeaza alta.
+
+Decizia 5 ramane in picioare: **asezarea e identica** la introducere si la modificare; difera doar
+starea antetului.
+
+### I-bis. Contractul lui `modifica_date_factura` (decizia 19)
+
+Raport complet: `docs\cercetare\modifica_date_factura_parametri.md`. Spec `PACK_FACTURARE.pck:921-935`,
+corp `:14392-14462`, singurul apel VFP la `ofacturare_comun.vc2:4599-4614`.
+
+Procedura are **doua regimuri de scriere**, si diferenta dintre ele decide cum se cheama din
+formularul unificat:
+
+| Parametri | Regim | Unde ajung |
+|---|---|---|
+| `V_ID_VANZARE` | doar `WHERE` | identitatea randului; sursa lui `lnIdFact` (`:14424-14426`) |
+| `V_ID_RUTA`, `V_ID_DELEGAT`, `V_ID_AGENT`, `V_ID_MASINA`, `V_DATAORA_EXP`, `V_ID_FACTURARE`, `V_LISTARE_DETALIATA`, `V_TEXT_ADITIONAL`, `V_TIP_SAFT`, `V_EFACTURA` | **scrise neconditionat**, inclusiv cu `NULL` | `VANZARI`, randul curent (`:14414-14423`) |
+| `V_DATA_ACT`, `V_DATA_SCAD`, `V_NUMAR_ACT`, `V_SERIE_ACT` | scrise **doar daca** sunt `NOT NULL` **si** difera de valoarea curenta | `VANZARI` + propagare in `DOCUMENTE`, `ACT`, `IREG_PARTENERI`, `JV2007`, `RUL` (si `RUL.DATAOUT`), toate **dupa `ID_FACT`**, nu dupa `ID_VANZARE` (`:14428-14459`) |
+
+**Consecinta 1 — apelul trimite intotdeauna antetul intreg.** Cele zece campuri din regimul
+neconditionat se scriu cu ce primesc, deci un apel cu `poRec` completat partial **goleste** in baza
+campurile netrimise. Butonul de antet nu poate trimite „doar ce s-a schimbat”: incarca antetul
+curent, aplica modificarile peste el, trimite tot.
+
+**Consecinta 2 — cele patru campuri de identitate ating cinci tabele.** Propagarea dupa `ID_FACT`
+inseamna ca schimbarea seriei sau a numarului dintr-un document atinge toate randurile legate de
+acelasi `ID_FACT`. E acelasi mecanism pe care se sprijina S9 (reemiterea cu `ID_FACT` pastrat) si
+acelasi motiv pentru care ordinea operatiilor conteaza acolo.
+
+**Consecinta 3 — un camp nou.** `V_EFACTURA` se scrie neconditionat dar nu are niciun control in
+niciun formular; azi valoarea vine din `Scatter` sau e fortata `0` (`ofacturare_comun.vc2:4576`).
+In antetul unificat primeste control, langa `V_TIP_SAFT` (ambele tin de raportare, nu de document).
+
+**Unde stau cele 14 in formularul unificat** (raportat la gruparea din I): cele patru de identitate
+in antetul vizibil; ruta, delegatul, agentul, masina, `dataora_exp` si adresa de facturare in
+sectiunea pliata, la „delegat si transport” / „adresa de facturare”; `text_aditional` si
+`listare_detaliata` tot in pliat; `tip_saft` si `efactura` formeaza acolo un **grup nou, de
+raportare**. Niciunul dintre cei 14 nu vine azi din `frm_alte_date` — clasa aceea nu e implicata
+deloc in fluxul `do_modifica`, deci sectiunea B si I-bis nu se suprapun.
+
+### J. Butoanele de linie si adaugarea din sursa (decizia 13)
+
+**Cum sunt azi.** In `frm_facturare_articole` butoanele sunt imprastiate lateral, intre cele doua
+griduri, si sunt iconite de 30x27 fara text: `But_modifica1` / `But_sterge1` la 773/61 si 811/61,
+`But_reset1` la 303/295, `But_urmator1` la 343/348, `But_urmator_tot1` la 343/378, `But_retur` la
+343/407 (`ofacturare.vc2:11192-11257`). **`But_urmator_tot1` — „adauga tot” — nu are nici caption
+nici `ToolTipText`** (`:11257`); metoda lui, `do_adauga_tot` (`:13169-13198`), face SCAN peste
+`crsarticole` si cheama `do_adauga_articol(.T.)` pe fiecare linie.
+
+**In prototip sunt deja unde trebuie**: `But_nou1` si `But_sterge1` la `Top = 175`, gridul la
+`Top = 204` (`:15936`, `:15955`) — adica **deasupra tabelului**, exact cum cere decizia 13.
+`But_nou1.Click -> do_adauga` (`:17118-17122`) e `APPEND BLANK` + focus in grid.
+
+**Ce lipseste: contractele.** `But_urmator_tot1` e vizibil pe `eProforma = 1`, `lCopiere`, tip 3
+(comanda), tip 4 (din avize), 21/28/42/47, 25, 8/9, 24 (`:15113-15245`). **Tipurile de contract
+(2, 6, 26, 52) nu sunt in lista.** Deci „adauga tot” acopera deja avizele, dar nu contractele.
+
+**Alegerea selectiva — tiparul importului RORIS.** In ROAACNPRO, `cmdImport` („Import Roris &
+Contracte”, `oacnpro.vc2:6894-6905`) face exact ce s-a cerut aici, si merita copiat ca structura:
+
+1. **buton activ conditionat** de document editabil **si** tip care are sursa
+ (`llFacturaEditabila and llRorisSauContracte`, `oacnpro.vc2:8117-8145`);
+2. **o metoda unica de intrare** care ramifica pe tip (`do_executa` -> `factura_import`,
+ `proceduri_acnpro.prg:3151-3212`);
+3. **dialog modal de selectie** cu coloana de bifat si criterii de cautare (`frm_tranzit`, coloana
+ `cAles` legata de `crsConvoaie.ales`, `oacnpro.vc2:14500-14515`, `:14801`), urmat de un al doilea
+ nivel de calcul / confirmare;
+4. **populare aditiva** prin `INSERT INTO` in cursorul local de articole, fara nicio procedura Oracle
+ — pachetele intra abia la salvare (`proceduri_acnpro.prg:3331-3467`);
+5. **protectie minimala la dublu-import**: butonul se dezactiveaza dupa un import reusit
+ (`oacnpro.vc2:7827-7834`), plus avertisment neblocant daca sursa a mai fost folosita
+ (`:14915-14930`).
+
+Ce **nu** se copiaza: sursele de date si calculele ACN (`ips_*`, tarife, ecluzari), formularele lor,
+si valorile `poDate.cTip`. Ce trebuie facut mai bine: la zero rezultate, dialogul RORIS nu spune
+nimic — butonul pare ca nu face nimic (`oacnpro.vc2:14898-14943`).
+
+**Bara propusa, deasupra gridului (decizia 13):** linie noua · sterge linia · detalii linie ‖
+**un singur buton „Adauga articole”**, care deschide un `xmenu()` cu optiunile potrivite sursei —
+nu doua butoane separate. Tiparul e deja folosit in produs: `frm_facturi.but_modifica1` ->
+`inainte_de_do_modifica` -> `xmenu("Modificare date factura;Editare factura (articole, cantitati,
+preturi)")` (`ofacturare_comun.vc2:4925-4934`).
+
+| Sursa documentului | Optiunile din meniu |
+|---|---|
+| comanda | Adauga tot din comanda · Alege din comanda… · Cauta in lista de preturi… |
+| contract | Adauga tot din contract · **Alege ratele de facturat…** · Cauta in lista de preturi… |
+| avize | Adauga tot din avize · Alege avizele… · Alege liniile din avize… · Cauta in lista de preturi… |
+| lista de preturi | Cauta in lista de preturi… · Retur de articole… |
+| retur (tip 8, 9, 24) | Alege facturile de returnat… · Alege liniile de returnat… · Cauta in lista de preturi… |
+
+**Constanta meniului (deciziile 16 si 18): ultimele doua optiuni sunt aceleasi peste tot** —
+**„Cauta in lista de preturi…”** (cu pret din politici) si **„Alege din nomenclator…”** (cu pret
+tastat, ca „Alte servicii” din ROAAUTO, O-bis). Apar inclusiv pe documentele cu sursa, pe cele de
+retur si pe cele deja emise care se modifica. Sursa umple documentul, nu il inchide.
+
+**Decizia 20 (Marius, 09.08.2026): din nomenclator se pot alege si articole gestionabile, si
+negestionabile.** Nu se preia filtrul `in_stoc = 0` al lui ROAAUTO — acolo e o ocolire a subiectului
+gestiunii, nu o regula de produs. Consecinta directa: pe documentele auto vor putea aparea linii care
+descarca stoc langa linii care nu descarca, caz care azi nu exista nicaieri (O-bis, intrebarea 2).
+
+#### J-bis. Contul de venit al liniei — intrebarea lui Marius era corect pusa
+
+Doua cercetari, a doua o corecteaza pe prima. **Valabil e al doilea raport:**
+`docs\cercetare\cont_venit_corespondente.md`. Primul (`cont_venit_articol_fara_politica.md`) ramane
+util pentru contul de **gestiune**, dar concluzia lui pe venit e gresita si nu se citeaza.
+
+**Ce a gresit primul raport.** A cautat literalii `707` / `704` / `706` / `708` in `pack_facturare`,
+nu i-a gasit (corect — nu sunt hardcodati nicaieri) si a conchis ca **nu exista cont de venit pe
+linie**. Exista. E doar **indirect**, si sta chiar in `pack_facturare`, nu intr-un pachet de
+contabilitate separat.
+
+**Sunt doua conturi pe aceeasi linie de vanzare, cu surse complet diferite:**
+
+| | Contul de **gestiune** | Contul de **venit** |
+|---|---|---|
+| Unde ajunge | `VANZARI_DETALII.CONT` (`varchar(4)`) | `SCC` in randul de nota contabila |
+| De unde vine | `NOM_ARTICOLE.CONT` / `STOC.CONT` / `NOM_GESTIUNI.CONT` | `NOTE_CONTABILE.SCC` |
+| Prin ce | alegerea lotului (`do_alege_stoc`) | **politica de pret** a articolului |
+| Cine il consuma | `descarca_gestiune` (`ff_...:7485-7507`) | `scrie_nota` (`ff_...:7452-7476`) |
+
+Lantul care aduce venitul, in `pack_facturare.contabilizeaza_articol` (`ff_...:7182-7556`, cursorul
+`cursor_articol` la `:7227-7280`):
+
+**`CRM_POLITICI_PRET_ART` -> `CRM_POLITICI_PRETURI.ID_NOTA` -> `CRM_NOTE_VANZARI.ID_SET` ->
+`NOTE_CONTABILE.SCD` / `SCC`**
+
+Pentru o factura normala (`ntip <= 20`), `SCD` e contul debitor (creanta) si **`SCC` e contul de
+venit efectiv** al liniei (`ff_...:7407-7437`). Nu e derivat din nimic: perechea SCD/SCC e **scrisa
+manual de un contabil**, per sablon de nota, din ecranul „Configurare note contabile"
+(`COMUN\ferestre\frm_config_note_contabile[2007].sc2`, clasa `onote_contabile.vc2:2401-2435`,
+salvare la `:315-322`, `:486-493`).
+
+**Nu exista tabel de corespondenta 3xx -> 7xx.** Cautat in `SCRIPTURI_CLAR` sub toate numele
+plauzibile — negativ. Ipoteza lui Marius era corecta ca **intentie** (exista un mecanism care leaga
+articolul de contul de venit), dar mecanismul e **configurare manuala pe politica de pret**, nu
+derivare automata din contul de stoc.
+
+**Consecinta care conteaza pentru #13 — si care valideaza intrebarea initiala a lui Marius.** Daca
+contul de venit vine **prin politica de pret**, atunci un articol adaugat **direct din nomenclator,
+fara politica** (exact ce cere decizia 16 / 20) nu are `ID_POL`, deci cursorul de mai sus — filtrat
+`WHERE A.ID_POL = detalii_articol.id_pol` — nu intoarce niciun rand, si `SCD` / `SCC` raman `NULL`
+(sunt `LEFT JOIN`-uri). **Intrebarea „cu ce cont de venit intra un articol fara politica de pret" era
+deci exact intrebarea corecta.**
+
+#### J-ter. Raspunsul: nu „cu niciunul”, ci **eroare** — si nu exista precedent
+
+Verificat: `docs\cercetare\nota_contabila_fara_politica.md`. Doua rezultate, amandoua mai dure decat
+se anticipase.
+
+**1. Codul nu scrie tacut un cont gol — refuza documentul.** `contabilizeaza_articol` cauta politica
+articolului **inainte** de cursorul care aduce `SCC` (`ff_...:7286-7311`), si pe `NO_DATA_FOUND`
+ridica `RAISE_APPLICATION_ERROR` cu **`FACT-024`** („Articolul … nu este definit in politica de
+preturi …”). Cu `id_pol` `NULL`, `ID_POL = detalii_articol.id_pol` nu poate potrivi nimic, deci
+**mereu** se intra pe exceptie. Cursorul cu `SCC` nu se mai deschide. Nu exista ramura de default,
+nu exista fallback, si `scrie_nota` (`ff_...:12338-12570`) **nu are nicio validare pe cont** — dar
+nici nu ajunge sa fie chemat.
+Concluzie: o linie fara politica trecuta prin codul de azi **opreste tranzactia cu eroare**, nu produce
+o nota incompleta. Din perspectiva datelor e vestea buna; din perspectiva lui #13, e blocantul dur.
+
+**2. „Alte servicii" din ROAAUTO NU e precedent** — premisa pe care se sprijinea decizia 18 cade.
+Liniile acelea chiar ajung cu `id_pol` gol (confirmat: nici `crsalteserv`, nici `crsvanztemp`, nici
+semnatura lui `adauga_articol_factura_deviz` nu au `id_pol`, iar `INSERT`-ul in
+`VANZARI_DETALII_TEMP` nu include coloana). **Dar ele nu trec niciodata prin
+`contabilizeaza_articol`**: fluxul ROAAUTO cheama `initializeaza_date_factura` ->
+`adauga_articol_factura_deviz` -> `scrie_in_vanzari` -> `pack_auto.actualizeaza_deviz`
+(`oproceduri_devize.prg:1211-1310`), iar `scrie_in_vanzari` (`ff_...:13497-13962`, citit cap-coada)
+**nu genereaza nicio nota contabila de venit** — copiaza `ID_POL` (deci `NULL`) direct in
+`VANZARI_DETALII` si actualizeaza totalurile.
+Deci ROAAUTO nu demonstreaza ca articolele fara politica sunt tolerate; demonstreaza ca **exista o cale
+paralela de facturare care ocoleste contabilizarea de venit prin `pack_facturare`**. Unde capata acele
+documente contul de venit — daca il capata — **nu se vede in codul cercetat**; `actualizeaza_deviz`
+presupune deja existenta unui rand in `ACT`, a carui sursa nu a fost gasita.
+
+**3. Apelantii sunt trei, si acopera fluxul principal** (lasat neverificat de raportul 2):
+`scrie_factura2` (`ff_...:6150`) — factura normala si majoritatea tipurilor —, `scrie_factura_avize_retur`
+(`:6867`) si `scrie_aviz_retur` (`:7149`). Nu exista al patrulea.
+
+**4. `NOM_ARTICOLE.CONT` ca sursa de venit: NU.** Grep pe `NOM_ARTICOLE.CONT` in tot pachetul — zero
+potriviri. `V_SCC` vine exclusiv din `D.SCC` al lantului de politica. Varianta propusa de Marius nu
+exista nici macar ca ramura moarta.
+
+**Ce inseamna asta pentru perimetru.** „Alege din nomenclator…" nu mai e o adaugare de UI peste un
+mecanism existent: **cere modificare in `pack_facturare`**, adica in COMUN, cu impact peste toata
+suita — sau evitarea completa a lui `contabilizeaza_articol`, ca la ROAAUTO, ceea ce inseamna document
+fara nota de venit. **Aceasta e o schimbare de cost, nu un detaliu**, si se decide de Marius (vezi
+intrebarea deschisa de mai jos).
+
+**`NOM_ARTICOLE.CONT` nu e restrans la clasa 3** — confirmat: `verific_cont`
+(`COMUN\programe\oproceduri_comune.prg:2389-2415`) verifica doar ca acel cont exista in planul de
+conturi al anului (`vplcont_sintetic`), fara filtru de clasa; nu exista `CHECK CONSTRAINT` pe coloana
+si nici vreo ramificare pe `Left(cont,1)` aplicata articolelor. Deci un articol negestionabil **poate**
+purta legitim un cont 6xx / 7xx, cum a spus Marius. **Dar codul de azi nu-l foloseste asa**: acel camp
+merge in `VANZARI_DETALII.CONT` si de acolo la `descarca_gestiune`, niciodata la `SCC`. Ca sugestia lui
+Marius sa devina comportament, ar trebui **cod nou in `pack_facturare`** — adica in COMUN, cu impact
+peste toata suita. *Vezi intrebarea deschisa de mai jos.*
+
+**`ID_VENCHELT` / `NOM_VENIT_CHELTUIELI` nu e sursa contului.** Tabelul nu are coloana de cont;
+`ID_VENCHELT` se rezolva separat (`NVL(nid_venchelt, NVL(A.ID_VENCHELT, C.ID_VENCHELT))`,
+`ff_...:7205`) si pleaca la `scrie_nota` ca **parametru propriu**, alaturi de `SCD`/`SCC` — e o a
+treia dimensiune analitica (centru de venituri/cheltuieli, pentru raportare), nu contul insusi.
+Presupunerea din runda 7 ca „venitul vine din `Ct_clb_venchelt`" **se retrage**.
+
+De unde vine `CONT`, pe cele doua cai:
+
+| Cale | Sursa contului | Fallback |
+|---|---|---|
+| **gestionabil, cu stoc** — trece prin `do_alege_stoc` (`ofacturare.vc2:13239-13345`) | `STOC.CONT`, de pe lotul ales (`cursor_gestiuni_articol`) | **niciunul** — lot cu `CONT` gol ramane `NULL` |
+| **gestionabil, fara stoc** (`RF_FACTURARE_FARA_STOC = 1`) | `NOM_GESTIUNI.CONT` -> ultimul `STOC.CONT` -> `'371'` hardcodat (`cursor_gestiuni_articol_stoc0`) | singurul loc din pachet cu cascada si default |
+| **negestionabil** — `frm_articol_factura` direct (`:12871-12880`) | `NOM_ARTICOLE.CONT`, citit la cautarea articolului | **niciunul**; gol -> sentinela `'XXXX'` -> `NULL` la INSERT |
+
+`adauga_articol_factura` **nu recalculeaza** contul: il primeste ca parametru `V_CONT` si il scrie ca
+atare. **Nu exista nicio exceptie pe `CONT`** in tot pachetul — spre deosebire de cota de TVA, unde
+lipsa produce explicit `FACT-012` / `FACT-013` / `FACT-018`. O linie fara cont se scrie tacut.
+
+**Precedentul ROAAUTO nu ofera o regula, ci absenta ei.** „Alte servicii” (O-bis) trimite literal `''`
+catre `adauga_articol_factura_deviz` (`oproceduri_devize.prg:1256`), care ajunge `NULL` in Oracle,
+fara `NVL` si fara fallback. Liniile de articole reale din ROAAUTO **ajung deci cu `CONT = NULL`**.
+
+**Decizia 21 (Marius, 09.08.2026)** acopera **contul de gestiune**: cand `NOM_ARTICOLE.CONT` e gol pe
+un articol negestionabil ales din nomenclator, se aplica un **fallback la un cont implicit** — nu se
+accepta `NULL` ca la ROAAUTO, nu se refuza adaugarea. Precedentul de forma exista in pachet:
+`cursor_gestiuni_articol_stoc0` cade in cascada pana la `'371'` hardcodat. Contul anume ramane de ales
+la implementare. **Decizia 21 nu rezolva insa contul de venit** — sunt doua campuri diferite, cum arata
+tabelul de mai sus; la momentul cand a fost luata, distinctia nu era inca stabilita.
+
+~~**Decizia 24: articolul ales din nomenclator primeste `id_pol`-ul unei politici de pret
+implicite.**~~ **RETRASA in runda 8.** Argumentul ei — zero cod Oracle nou, COMUN neatins — ramane
+valabil ca argument, dar pretul lui era o intrebare de configurare cu contabilul (care politica, cu ce
+`SCC`, una sau mai multe) si un cont de venit uniform pentru orice articol adaugat asa. Marius a ales
+in loc derivarea contului. **Nu se reintroduce.** *Vezi J-quater.*
+
+Ramane valabil de aici, si e important: **alegerea politicii de catre operator** a fost si ea respinsa
+— muta costul pe fiecare adaugare si cere operatorului sa stie ce inseamna o nota contabila.
+
+**Ce se stie sigur pana atunci:** decizia 16 si decizia 20 **nu sunt anulate** de subiectul asta — pe
+articolele **cu** politica de pret (lista de preturi, comanda, contract, retur) contul de venit vine
+ca azi si nimic nu se schimba. Blocajul e strict pe ramura **„Alege din nomenclator…"**, adica pe
+partea din S4g care adauga articole fara politica.
+
+**Unde e efectiv de lucru pentru asta:** doar pe **comanda**. Verificat
+(`docs\cercetare\retur_si_lista_preturi.md`, B): pe contract, `crsarticole` contine deja lista de
+preturi intreaga, deci adaugarea libera **merge azi**; pe comanda, `cursor_comanda` umple `crsarticole`
+strict cu articolele comenzii (`ofacturare.prg:266-308`), deci nu merge. Restrictia **nu** e pe buton
+si nu e la validare — e in continutul cursorului. Se rezolva ca la copiere: `APPEND FROM` peste
+`crsarticole` cu rezultatul lui `cursor_preturi` (`ofacturare.prg:454-473`).
+
+#### J-quater. Deciziile 27 / 27-bis — contul de venit derivat, aplicat din VFP
+
+> **DEPASITA IN PARTE — de citit cu avertismentul asta in fata.** **Decizia 34** relaxeaza 27-bis
+> (`contabilizeaza_articol` primeste parametru de cont) si **decizia 35** cere ca `pack_facturare` sa fie
+> singurul cod de contare, si la emitere si la editare. Prin urmare:
+> - **punctul 1** (de ce ROAACNPRO si contractul nu sunt contraexemple) si **punctul 2** (derivarea
+> contului din `CORESP_CONT_VENCHELT` — regula deciziei 27) **raman valabile integral**;
+> - **punctul 3, „reteta in 4 pasi"** — politica tehnica per `SCC`, interogarea inversa,
+> `pack_preturi.adauga_politica_pret_art`, inserarea articolului in politica — e **ABANDONAT**. Se
+> pastreaza doar ca trasabilitate a rationamentului. **Nu se implementeaza si nu se reargumenteaza.**
+> - **cele trei variante** de la finalul sectiunii (reteta / nota pe antet / nota pe antet ca fallback)
+> sunt **caduce**: alegerea a fost facuta prin decizia 34.
+>
+> Proiectarea in vigoare e parametrul deciziei 34 — `docs\cercetare\parametru_cont_contabilizeaza_articol.md`.
+
+Raport: `docs\cercetare\coresp_cont_venchelt.md`. Trei lucruri s-au stabilit, in ordinea in care conteaza.
+
+**1. Intrebarea lui Marius („in ROAACNPRO si pe factura din comanda / contract se adauga articole fara
+politica — de ce nu si aici?") a primit raspuns: observatia e reala, dar niciunul din cele doua exemple
+nu e un contraexemplu.** `FACT-024` ramane blocantul.
+
+- **ROAACNPRO nu foloseste deloc `contabilizeaza_articol`.** Salvarea facturii ACN
+ (`proceduri_acnpro.prg:3331-3467`) merge pe `initializeaza_date_factura` ->
+ **`adauga_articol_factura_deviz`** -> **`scrie_in_vanzari`** -> **`pack_acn.salveaza_regdoc`**.
+ Cautare directa dupa `contabilizeaza_articol` in acel fisier: **zero rezultate**. Nota contabila o
+ scrie o procedura proprie ACN, care nici nu primeste `id_pol` printre parametri. Acelasi tipar ca
+ ROAAUTO „Alte servicii" (J-ter, punctul 2): **o cale de facturare paralela**, nu o dovada ca articolele
+ fara politica sunt tolerate.
+- **Pe contract, articolul „liber" nu e fara politica.** `crsarticole` e populat de
+ `pack_facturare.cursor_contract` / `cursor_preturi`, care **selecteaza explicit `A.ID_POL`**
+ (`ff_...:2162-2167`) si care ruleaza la fiecare apel `completare_politica_stoc` (`ff_...:2151`).
+ Deci fiecare rand din grila vine deja **cu o politica reala atasata**. „Adaugare libera pe contract"
+ inseamna „orice articol din lista de preturi, nu doar cele din contract" — nu „articol fara politica".
+
+ **Diferenta reala e cursorul-sursa al grilei, nu tipul de document:** `caut_articol`
+ (`COMUN\programe\ocautare.prg:1636-1735`, cautarea in nomenclator) **nu are coloana `id_pol` in nicio
+ ramura**; `cursor_preturi` / `cursor_contract` o au, pentru ca pleaca de la politica, nu de la
+ nomenclator. Povestea #13 cere exact ce nu exista azi nicaieri.
+- **Ce verifica de fapt `FACT-024`:** `SELECT COMPUS, ID_POL_ART FROM VCRM_POLITICI_PRET_ART WHERE
+ ID_ARTICOL = ... AND ID_POL = ...` (`ff_...:7278-7302`) — deci **apartenenta articolului la politica
+ de pe linie**. Ipoteza din runda 8 e **partial** confirmata: verificarea e de apartenenta, dar `id_pol`
+ **nu** vine din antet ca valoare unica — e parametru per linie, trimis de VFP. Doua cauze diferite
+ (`id_pol` gol; articol nemembru) produc aceeasi eroare, iar codul nu le distinge.
+
+**2. `CORESP_CONT_VENCHELT` exista, e populat si e folosit in productie — dar niciodata pentru
+`CONT_VENIT`.** Toti consumatorii gasiti (`pack_vin`, `pack_devize`, `gestiune_pack_gest_import`,
+rapoarte de gestiune) citesc `CONT_CHELT` sau `CONT_APROVIZIONARE`. Coloana `CONT_VENIT` **are date
+reale** dar **zero consumatori**, nici Oracle nici VFP. Cheia de join e stabila si testata: pe `CONT`, cu
+`STERS = 0`, prin `LEFT JOIN` — tiparul se copiaza identic. Deci regula lui Marius e implementabila; e
+insa **un consumator nou**, nu o reteta deja rulata.
+
+**Masurat pe baza vie (10.08.2026, `MARIUSM_AUTO`) — `docs\cercetare\verif_baza_vie_cont_venit.md`:**
+tabelul are **41 de randuri active**, din care exact **20 au `CONT_VENIT`** populat; restul 21 sunt
+conturile de ajustari (`391`…`398`, toate cu `CONT_CHELT = 681`), care nu poarta marfa. **Niciun `CONT`
+nu e duplicat**, deci pasul 1 al retetei e determinist — desi schema nu are unique pe `CONT`, doar `PK`
+pe `ID_CCV`. Si, decisiv: **zero articole active cad pe un rand cu `CONT_VENIT` gol**, deci ramura
+„cont derivat gol" se trateaza defensiv dar nu are cazuri reale. DDL-ul complet e in raport.
+
+**3. Calea VFP (decizia 27-bis) exista si e construita din piese functionale.** Patru pasi.
+
+> **Clarificare ceruta de Marius (10.08.2026) — de citit inainte de cei patru pasi.** Politica **nu e
+> necesara ca sa se afle contul.** Regula deciziei 27 il determina complet, in VFP: corespondentele pe
+> clasa 3, contul de pe articol daca e 6xx / 7xx, `704` altfel. Aia e **pasul 1**, si e verificata pe date.
+> Politica e necesara **doar ca canal de transport** catre Oracle: `contabilizeaza_articol` **nu are
+> parametru de cont de venit** — primeste `V_ID_POL` si deduce singura contul prin lantul politica → nota →
+> `NOTE_CONTABILE.SCC`. Deci **pasii 2-4 nu decid nimic**, doar convertesc un cont pe care VFP il stie deja
+> intr-o forma pe care pachetul o accepta. Indirectarea e consecinta deciziei **27-bis**, nu a regulii lui
+> Marius: daca pachetul ar putea fi modificat, un parametru de cont ar face pasii 2-4 sa dispara.
+> **INCHIS (runda 9 + decizia 35).** Cautarea canalului direct s-a terminat —
+> `docs\cercetare\canal_cont_venit_fara_politica.md`. Verdict: canalul **exista** (`actactan` / `tact` →
+> `oscrie_in_fisiere` → `pack_contafin.SCRIE_IN_ACT`), dar e cablat pe **editarea unei note deja scrise**,
+> nu pe emitere; emiterea trece exclusiv prin `scrie_factura2` → `contabilizeaza_articol`. Pistele
+> `V_CONT` (e contul de gestiune), setterele de sesiune, `ID_VENCHELT` si `GetAnaliticByGrupUtilizatori`
+> sunt **toate NU**.
+> **Si nu se foloseste oricum:** decizia 35 il respinge explicit in #13, ca sa nu existe doua coduri de
+> contare. Reteta in 4 pasi cade prin **decizia 34** (parametru de cont in pachet), nu prin canal.
+
+1. **VFP calculeaza `SCC`-ul** dupa regula deciziei 27: `CORESP_CONT_VENCHELT.CONT_VENIT` pe contul de
+ gestiune al liniei (articol gestionabil), `NOM_ARTICOLE.CONT` daca e 6xx / 7xx, altfel `'704'`.
+2. **VFP cauta o politica a carei nota are deja acel `SCC`** — interogarea inversa pe acelasi lant:
+ `CRM_POLITICI_PRETURI -> CRM_NOTE_VANZARI -> NOTE_CONTABILE`, `WHERE NC.SCC = :cont_calculat`.
+ Interogare **noua**, dar pe coloane si relatii deja confirmate.
+ **Corectat pe baza vie:** legatura nu e politica -> nota, ci politica -> **set de note** —
+ `CRM_POLITICI_PRETURI.ID_NOTA` -> `CRM_NOTE_VANZARI.ID_SET` -> `NOTE_CONTABILE.ID_SET`. Pe cele 7 note
+ de vanzari active fiecare set are **un** rand, dar in tabel exista seturi cu pana la **30** de randuri,
+ deci „nota politicii" e bine definita doar cat timp seturile de vanzari rămân cu un rand.
+ **Si mai important: filtrarea pe `SCC` singur nu e suficienta** — vezi „Ce nu e gratuit" mai jos.
+3. **VFP se asigura ca articolul e membru al acelei politici** — RPC **existent**
+ `pack_preturi.adauga_politica_pret_art`, deja folosit exact asa (verifica intai, insereaza daca
+ lipseste) in `ofacturare.vc2:15551-15587`, la modificarea listei de preturi de la NIR. **`pack_preturi`
+ nu e `pack_facturare`** — nu se atinge nimic din pachetul comun de facturare.
+4. **VFP trimite acel `id_pol`** in `adauga_articol_factura` (`V_ID_POL` e parametru de intrare explicit,
+ `ff_...:4989-5015`). `contabilizeaza_articol` ruleaza **neschimbata**.
+
+**Modelul „politica tehnica, configurata o data, populata automat" exista deja in pachet:**
+`completare_politica_stoc` (`ff_...:2093-2120`) face `MERGE` in `CRM_POLITICI_PRET_ART` pentru toate
+articolele `IN_STOC = 1` sub politica `pack_facturare.nid_politica_stoc`, alimentata din optiunea globala
+`gnId_pol_pret_stoc` (`ofacturare.vc2:21733-21753`). Nu e direct reutilizabila — are o singura nota
+pentru toate articolele, iar decizia 27 cere pana la sase conturi diferite — dar arata ca tiparul e
+acceptat in produs.
+
+**Calea VFP e mai completa decat modificarea pachetului**, nu doar mai ieftina: politica reala aduce si
+`CU_TVA`, `IN_VALUTA`, `EXPLICATIE`, `ASCD`, `ASCC` din nota configurata. Un fallback in
+`contabilizeaza_articol` ar da doar `SCC`; `CU_TVA` si `IN_VALUTA` **nu au nicio sursa alternativa** in
+afara lui `NOTE_CONTABILE`, deci ar trebui hardcodate — cu risc de calcul gresit al bazei si al TVA.
+
+**Ce nu e gratuit, si trebuie stiut inainte de S4g:**
+
+- **Pasul 2 depinde de configurarea fiecarui client — deci nu se poate proiecta pe acoperire.**
+ Decizia lui Marius, 10.08.2026: **datele din Dev nu sunt baza de proiectare.** Fiecare client isi
+ defineste propriile politici de pret, fiecare cu nota ei de vanzare salvata pe un `ID_SET`. Pe schema
+ de dezvoltare masurarea a dat `704` cu 19 politici valabile, `707` cu 4, `7015` cu 1, si zero pentru
+ `711` / `702` / `703` / `7018` — **dar aceste numere nu se folosesc ca argument**, pe o baza de client
+ distributia poate fi complet alta. Ce se pastreaza din masurare e strict **structural** (forma lantului,
+ absenta unique-ului pe `CONT`, bug-ul de set multi-rand) plus un fapt negativ: **afirmatia rundei 8 ca
+ „pentru `704` nu exista nicio nota configurata" nu se susține ca regula** — pe Dev exista patru, deci
+ pasul „se creeaza nota pentru 704" nu poate fi pus in plan ca obligatoriu.
+ **Consecinta de proiectare:** reteta nu are voie sa presupuna ca gaseste o politica pentru `SCC`-ul
+ calculat. Ori garanteaza singura existenta a ceea ce foloseste (politica tehnica creata de produs), ori
+ are o cale care **nu trece prin politica deloc** — vezi mai jos.
+- **`PTVA` de pe nota e inofensiv — verificat pe cod, nu presupus.** `cursor_articol`
+ (`PACK_FACTURARE:7218-7271`) **nu selecteaza `D.PTVA`**; cota folosita efectiv vine din
+ `detalii_articol.proc_tvav * 100 - 100` (`:7464`), adica din articol / document. Deci o nota cu
+ `PTVA = 5` pe un articol cu 21% **nu produce nimic** — coloana e moarta pentru aceasta procedura.
+ Ingrijorarea initiala („criteriul trebuie sa fie `(SCC, PTVA)`") **se retrage**.
+ `IN_VALUTA = 1` de pe nota pe un document in lei nu da nici eroare, nici suma greșita — doar populeaza
+ redundant `ACT_TEMP.SUMA_VAL` la curs 1 (`scrie_nota:12391-12404`, `:12492-12507`): inconsistenta
+ cosmetica, nu contabila. `ASCD` / `ASCC` nule au fallback automat prin
+ `GetAnaliticByGrupUtilizatori` (`:7409-7428`), iar `ID_PARTD` / `ID_PARTC` **nu se citesc de pe nota**
+ deloc — vin din contul si din contextul documentului (`:12510-12530`).
+- **In schimb, `ID_SET` cu mai multe randuri dubleaza venitul SI descarcarea de gestiune.** Asta e
+ riscul real, si e mai grav decat cel presupus. `cursor_articol` face `LEFT JOIN NOTE_CONTABILE D ON
+ C.ID_SET = D.ID_SET` **fara `ROWNUM`, fara agregare, fara filtru**, iar bucla care il consuma
+ (`:7393-7542`) executa `scrie_nota` **si** `descarca_gestiune` **o data pentru fiecare rand al
+ setului, cu aceeasi cantitate si acelasi pret intreg de fiecare data** — nu impartite. Nu exista
+ nicio logica de distributie: `ORDINE` nu apare in tot pachetul. Deci pasul 2 nu trebuie doar sa
+ gaseasca un rand cu `SCC`-ul potrivit, ci **sa garanteze ca setul ales are exact un rand**. Cele 7
+ note de vanzari active au, azi, exact un rand fiecare — dar 30 din cele 40 de seturi din baza au mai
+ multe, cu maxim 30. **Conditia care face reteta sigura e o coincidenta a datelor curente, nu o
+ garanție a codului.** Sursa: `docs\cercetare\s10_pret_rederivat.md`, „Completare: nota contabila a
+ politicii", punctul 1.
+- **Pasul 3 poluează o lista de preturi de producție.** Politica **este** lista de preturi: candidatele
+ reale contin `STOC PRODUSE` cu **6310** articole si `LISTA PRETURI LEI` cu **909**, plus liste cu nume de
+ client si de sezon (`CHIOSC`, `SERVICE AUTO`, `S7 CRACIUN`…). Un articol adaugat ad-hoc pe factura ar
+ aparea de acum in acea lista, cu pretul cu care a fost facturat o data. **Deci pasul 2 nu trebuie sa
+ caute orice politica potrivita, ci o politica tehnica dedicata, una per `SCC`** — modelul
+ `gnId_pol_pret_stoc` extins de la una la sapte. Cele **sase** politici cu 0 articole din baza vie arata
+ ca o politica goala e o stare acceptata de produs.
+- **Ambiguitatea celor 19 politici pe `704` e de lista de preturi, nu de rezultat contabil** — majoritatea
+ trimit la aceeasi `id_nota = 1`, deci toate dau `704` / `PTVA = 21` / lei. Cu atat mai mult, criteriul de
+ departajare corect e „care lista de preturi accept sa murdaresc", iar raspunsul e „niciuna dintre cele
+ existente".
+- **Politica tehnica devine vizibila utilizatorului** in `caut_politici_curente_util()` — aceeasi functie
+ ca la cautarea normala. Ori se filtreaza explicit (flag / prefix dedicat), ori se accepta riscul ca
+ cineva sa o aleaga din greseala pe o factura normala. **De decis in S4g.**
+- **`id_pol` devine populat** acolo unde azi ar fi gol. Nu s-a gasit cod care sa presupuna „`id_pol` gol =
+ articol fara politica", dar nici nu s-a cautat exhaustiv.
+- **Doua politici active nu au `ID_NOTA`** (`32 HOTEL TAXE`, `33 HOTEL CAZARE`) — `id_pol` valid, nota
+ absenta. Ce face `contabilizeaza_articol` in acest caz e intrebare deschisa, trimisa pe cod. E o gaura
+ care **exista deja azi**, independenta de #13.
+
+**RASPUNS LA DECIZIA 32 — reteta RAMANE. `docs\cercetare\idpol_comanda_contract.md`.**
+
+Intrebarea era: cum alege programul nota contabila la factura din comanda, care „nu are politica de pret"?
+**Raspuns: are. Structural nu poate sa nu aiba.** `COMENZI_ELEMENTE.ID_POL` e **`NOT NULL`** la nivel de
+schema (constrangerea `SYS_C0015376`, plus `FK_COMENZI_ELEMENTE_002`) — verificat direct: **0 din 7108
+randuri** au `ID_POL` nul sau zero, 9 politici distincte in uz, toate cu nota atasata. Deci nu exista nicio
+ruta alternativa catre nota, si **nu exista contradictie cu concluzia rundei 8**: pe comanda cazul „`id_pol`
+gol" e imposibil, nu doar neintalnit. Ce percepe operatorul ca „n-am ales nicio politica" e faptul ca
+politica se alege **o data pe comanda** — manual sau moștenita dintr-o optiune legata de tipul comenzii —
+si de atunci fiecare articol adaugat o primeste automat, din `com_vpreturi_utilizator`, view care filtreaza
+`id_pol IS NOT NULL` la sursa. Pe **contract** tiparul e acelasi, dar cheia stocata e
+`CTR_ARTICOLE.ID_POL_ART` — FK direct la randul din `CRM_POLITICI_PRET_ART`, **nullable**, cu cazuri reale.
+
+**De ce `FACT-024` nu se declanseaza pe comanda / contract:** nu pentru ca ar exista un fallback, ci pentru
+ca **articolul nu e ales niciodata din nomenclator** — e ales dintr-o lista deja filtrata pe politica, deci
+apartenenta e garantata **prin construcția listei**, nu prin validare. Exact aici e diferenta cu #13, unde
+`caut_articol` ofera nomenclatorul intreg.
+
+**Deci refolosirea nu simplifica nimic:** mecanismul de jos — RPC de inserare + apartenenta garantata — e
+**exact** ce propune reteta in 4 pasi. Ce ar simplifica cu adevarat („ia politica curenta fixa si pune
+articolul in ea") e **decizia 24, retrasa**, si motivul retragerii sta: o politica unica da **un singur**
+cont de venit oricarui articol, indiferent de natura lui — opusul deciziei 27. Comanda si contractul nu
+raspund niciodata la intrebarea „**care** politica pentru **acest** articol", pentru ca la ele politica vine
+gata aleasa, o data, de operator.
+
+**CORECTIE, a doua tura a aceluiasi agent — premisa lui Marius ERA corecta, dar pe contract, nu pe comanda.**
+Exista o ruta reala catre nota contabila **complet in afara lui `id_pol`**: la **contractele cu rate /
+scadentar** (`OPT_FACTURARE IN (1, 2)`), o functie separata — **`contabilizeaza_rata`** — scrie nota direct
+din **`CONTRACTE.ID_NOTA`**, fara sa treaca prin `CRM_POLITICI_PRETURI`. Confirmat pe cod de agent si pe o
+factura reala (`id_vanzare 360`: `SCD = 4111` / `SCC = 704` in `ACT`, pe o linie fara articol si fara
+politica). **Structura confirmata independent de sesiunea principala:** `CONTRACTE.ID_NOTA` exista, e
+nullable, si e **populat pe 19 din 242 de contracte**, rezolvand la note reale — `1 NOTA 1` → `SCC 704`
+(5 contracte), `2 DISCOUNT` → `SCC 4111` (5), `5 VANZARE MARFA` → `SCC 707` (1). Deci nota **pe antetul
+documentului** nu e o ipoteza, e un mecanism in uz.
+
+**Ce inseamna asta pentru #13, si de ce e o decizie de produs, nu una tehnica.** Tiparul „nota pe antet"
+ar fi **mai simplu decat reteta in 4 pasi**: n-ar mai fi nevoie nici de gasirea politicii, nici de
+inserarea articolului in ea, nici de politica tehnica — antetul ar purta nota, iar liniile ad-hoc ar
+moșteni-o. **Dar cere cod nou in `pack_facturare`**, pentru ca `contabilizeaza_rata` trateaza rate, nu
+articole de factura. Adica **incalca exact decizia 27-bis** („`pack_facturare` nu se atinge").
+**Deci alegerea e a lui Marius, intre trei variante:**
+
+1. **reteta in 4 pasi** (decizia 27-bis respectata, `pack_facturare` neatins, dar cere politica tehnica per
+ `SCC` si o interogare inversa noua);
+2. **nota pe antet ca la `contabilizeaza_rata`** (mult mai simplu si mai curat conceptual, dar **relaxeaza
+ decizia 27-bis** — cod nou in pachetul comun intregii suite);
+3. **nota pe antet doar ca fallback** pentru articolele fara politica, lasand restul neschimbat.
+
+**Nu se implementeaza nimic pana la aceasta alegere.** Detalii: `idpol_comanda_contract.md`, sectiunea E-bis.
+
+**Doua observatii din date, gasite la confirmarea verdictului:**
+
+- **Precedentul cerut de decizia 27 exista deja in producție, si e mai bun decat `gnId_pol_pret_stoc`.**
+ Politica `7 DISCOUNT` apare pe **870 de linii de comanda** si trimite la nota `2 DISCOUNT`
+ (`SCD = 667`, `SCC = 4111`). E o politica de pret folosita **exclusiv ca mecanism de rutare contabila**,
+ nu ca lista comerciala de preturi. Deci „politica tehnica, dedicata unui cont, populata automat" nu e o
+ invenție a lui #13 — **produsul o face deja**, pentru discount. Argument direct pentru politica tehnica
+ per `SCC`.
+- **Garantia prin construcția listei nu e etanșă in date: 37 de linii de comanda au un articol care NU e
+ membru al politicii de pe linie.** **VERIFICAT (runda 10)** —
+ `docs\cercetare\linii_comanda_articol_nemembru.md`. **Decizia 32 NU se redeschide in sensul periculos:
+ nu exista cale de cod care sa ocoleasca `FACT-024`.** Patru rezultate:
+ - **Cifra 37 se reconfirma, dar numitorul din plan era gresit** — `6868` era alt numitor; cel corect
+ pentru linii cu `ID_POL NOT NULL` e **7108**.
+ - **Premisa „37 de linii ar cadea la facturare" era partial gresita.** Un rand cu `CANTITATE < 0` **nu
+ dovedeste ca linia a fost facturata**: singurul loc care il insereaza e `inchide_comanda`
+ (`PACK_FACTURARE:5769-5820`), care scrie *diferenta ramasa* la **inchiderea** comenzii, chiar si cand
+ nimic nu s-a facturat pe acea linie. **34 din 35 de linii negative n-au nicio factura in spate, nici
+ macar stearsa** — comenzile au fost inchise, nu facturate.
+ - **Una singura chiar a ajuns intr-o factura emisa** — comanda `497`, articolul `4294507522`
+ („VOUCHER DISCOUNT") pe politica `7` („DISCOUNT"), in factura `ID_VANZARE = 1028`, `20.03.2026`. Si
+ codul **chiar a rulat** `contabilizeaza_articol` pentru ea: apelul e in ramura `ELSE` a lui
+ `CASE pack_facturare.ntip` din `scrie_factura2`, care exclude doar transferurile, avizele de custodie
+ si facturile cu rate — tipul 3 cade in `ELSE`. Deci **fie articolul era membru al politicii la
+ 20.03.2026 si a fost scos ulterior, fie verificarea a fost ocolita altfel; dovada pentru a doua
+ varianta nu exista.**
+ - **Cauza e NEDETERMINABILA DIN DATE, structural.** `CRM_POLITICI_PRET_ART` **n-are coloana `STERS`** si
+ n-are tabel de istoric — stergerile sunt **fizice, fara urma**, deci nu se poate reconstitui starea de
+ la 20.03.2026. Coloanele de audit ale facturii (`VANZARI.ID_UTILS` / `DATAORAS` si cele de pe cele
+ doua linii) sunt **toate NULL**, deci nici o editare ulterioara nu s-a inregistrat. Indiciu de tipar,
+ nu dovada: aceeasi pereche articol-politica apare pe **35 de comenzi diferite**, ceea ce sustine o
+ **curatare de catalog** mai degraba decat 35 de greseli independente de introducere.
+
+ **Ce ramane, si cum se formuleaza:** pentru celelalte 36 de linii, „zero facturi in date" **nu
+ demonstreaza ca nu se pot factura** — demonstreaza doar ca nu s-a intamplat. Iar cu starea de azi a lui
+ `CRM_POLITICI_PRET_ART`, toate cele 37 **ar** cadea cu `FACT-024` daca ar trece acum prin
+ `contabilizeaza_articol` (verificat pe view-ul `VCRM_POLITICI_PRET_ART`, care n-are filtru propriu, deci
+ vede exact aceleasi perechi ca tabelul). **Concluzia pentru #13 e neschimbata:** garantia prin
+ constructia listei e reala cat timp catalogul nu se editeaza sub documente deja emise.
+
+**Verificarile pe baza vie sunt facute** (10.08.2026) — `docs\cercetare\verif_baza_vie_cont_venit.md`:
+interogarea inversa pe fiecare `SCC` candidat, DDL-ul lui `CORESP_CONT_VENCHELT`, distributia articolelor
+pe ramurile deciziei 27 (6125 din 6430 pe ramura gestionabila), efectele colaterale ale pasului 3 si trei
+fragilitati de structura. **Rămâne deschisa doar partea de cod**, listata mai sus.
+
+### K. Discountul pe linie (decizia 14)
+
+Verificat de doua ori, pe formularul real si pe DDL. Raspunsul la intrebarea „e doar procentual?” e
+**nu, si nici doar valoric — sunt amandoua, dar in alta fereastra**.
+
+**Intrarea pentru operator exista deja, in dialogul de articol.** `frm_articol_factura`
+(`ofacturare.vc2:1108-2659`), deschis la fiecare adaugare de articol, are trei campuri legate:
+`Clb_procent_discount` (procent), `Clb_discount_unitar` (suma, in lei sau valuta) si
+`Clb_discountctva` (varianta cu TVA). Toate cheama
+`frm_articol_factura.do_calculeaza_discount(valoare, tip)` (`:1874-1976`) cu `tip = 1` procent,
+`tip = 2` lei, `tip = 3` valuta (`:2602-2649`) — tastezi in oricare, se recalculeaza celelalte.
+Rezultatul intra in `poArticol.discount_unitar` si variantele lui, apoi in `crsfactura` prin
+`Replace` (`:12956-12957`).
+
+**Se stocheaza o singura coloana, si e valoare.** `VANZARI_DETALII.DISCOUNT_UNITAR NUMBER(22,6)`
+(`ff_2024_06_13_02_COMUN_FACTURARE.sql:3`; simetric pe `VANZARI_DETALII_TEMP` la `:9` si pe
+`CRM_POLITICI_PRET_ART` la `:16` — **trei tabele diferite, nu aceeasi coloana de trei ori**).
+**Nu exista coloana de procent** pe `VANZARI_DETALII` — procentul e doar mod de introducere.
+Parametru Oracle: `V_DISCOUNT_UNITAR` in `adauga_articol_factura`
+(`ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql:4986`), scazut din pretul fara TVA inainte de TVA
+(`:15794-15847`).
+
+**In grid, azi, comportamentul e inconsecvent.** Pe factura in lei ramane `cDiscountCTva`, care e
+`ReadOnly = .T.` (`ofacturare.vc2:12311-12317`); pe factura in valuta ramane `cVdiscountftva`, care
+**e editabila** — dar nu are niciun `Valid` / `InteractiveChange`, deci o editare directa in celula
+schimba valoarea bruta fara sa refaca totalurile. Excluderea reciproca e la `:15269-15278`.
+
+**Corectie fata de runda 3:** afirmasem ca prototipul are deja procent pe linie, ca argument pentru
+pornirea de la el. **Fals.** `procdisc` apare o singura data in tot fisierul, ca `ControlSource` de
+coloana (`:16721`), fara niciun `Replace` care sa-l populeze si fara corespondent Oracle — e schela
+moarta. (Restul aparitiilor de „procdisc” sunt variabila de optiune `gnMemProcDisc`, altceva.)
+Argumentele pentru prototip raman celelalte doua: controalele de antet si butoanele deasupra gridului.
+
+**Ce ramane de facut:**
+
+- cele doua campuri din dialogul de articol devin **coloane in grid** — procent si valoare unitara —
+ cu **acelasi calcul reciproc** din `do_calculeaza_discount`, mutat pe evenimentele coloanelor;
+- se repara astfel si inconsecventa de mai sus: aceleasi validari in ambele monede;
+- se pastreaza excluderea pe `in_valuta`;
+- modelul de date **nu se atinge**;
+- **de verificat separat, blocant**: daca `discount_unitar` apare pe rapoartele `.frx` si daca e
+ transmis in eFactura (UBL) si SAF-T. Daca nu apare pe hartie, documentul tiparit nu explica totalul.
+
+#### K-bis. Discountul de DOCUMENT — cota, explicatia si atribuirea pe cote
+
+Cercetare terminata, verificata la sursa (doua runde, a doua a corectat concluzii ale primei —
+vezi rezervele de mai jos). Detaliu complet: `docs\cercetare\discount_document_cota_tva.md`.
+
+**Cota discountului de document = cota MAXIMA de pe factura, ca regula implicita.** Nimeni n-o
+alege: nu exista control in formular si nicio coloana pe `VANZARI` pentru ea.
+`Calculate Max(proc_tvav)` — `COMUN\programe\oproceduri_facturare.prg:1387`,
+`COMUN\clase\ofacturare_comun.vc2:4495` si `:7294`, `COMUN\programe\ofacturare_stoc.prg:582`.
+Discountul intra ca **pseudo-linie negativa** printr-un rand-sentinela `Replicate('Z',20)`
+(`COMUN\programe\ofacturare_comun.prg:1886-1897`), care devine linia „Discount NN.NN % Factura"
+(`:1273-1392`).
+
+**Explicatia nu exista ca notiune — e o constanta.** In XML, `AllowanceChargeReason="Discount"`
+si `ReasonCode="95"` sunt hardcodate (`COMUN\programe\xmlefactura.prg:774-776`), la fel
+`currencyID="RON"` (`:778`). Textul construit in VFP („Discount 10.00 % Factura") nu ajunge in
+XML.
+
+**Regula e implementata de doua ori, independent — nu intr-un singur loc.** In VFP (mai sus) si
+in PL/SQL: `PACK_FACTURARE.recalculeaza_totaluri_vanzari`,
+`MAX(ROUND(discount*(a1.proc_tvav-1),...)) as DISC_TVA_RON` —
+`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16081-16092`,
+scris in `VANZARI.DISCOUNT_TVA` si de acolo in `TOTAL_TVA` / `TOTAL_CU_TVA` (`:16214-16227`).
+**Pentru #13: doua locuri de schimbat, nu unul** — daca se schimba doar unul, `VANZARI.TOTAL_TVA`
+si TVA-ul din XML diverg pe facturile cu cote mixte.
+
+**Defectul dovedit e de atribuire fiscala, nu de validare.** Pe cote mixte, tot TVA-ul
+discountului se scade din cota maxima. Exemplu: 1000 lei la 21% + 1000 lei la 11%, discount de
+document 10% (200 lei) → se declara 10 lei TVA in minus, mereu in acelasi sens (TVA colectat
+subdeclarat). Aceeasi valoare gresita ajunge si in nota contabila si in jurnalul de TVA. Caz-limita
+real, masurat: daca liniile de la cota maxima sunt o mica parte din total, `TaxSubtotal` iese cu
+baza negativa (`TaxableAmount = -410.00`).
+
+**Ipoteza bazei negative — verdict nuantat, asa cum a iesit din verificare, nu simplificat.**
+Temerea: pseudo-linia, avand `id_jtva_coloana = 0`, iese din `LEFT JOIN` cu `coloana_jv` NULL si
+formeaza grup propriu in `C_TVA_FACTURA`. **Infirmata pe factura obisnuita** — masurat headless,
+`IIF()` din VFP intoarce ramura falsa, nu `.NULL.`, cand conditia e nula, deci pseudo-linia se
+contopeste corect. **Confirmata insa pe facturile scutite / taxare inversa / intracomunitare**,
+unde liniile reale au `scutit = 1` si `expltva` completat iar pseudo-linia are `0` si gol: apar
+doua grupuri, deci un `TaxSubtotal` in plus cu baza negativa si categoria `Z`, iar
+`agettipcota(1)` (`xmlefactura.prg:782-786`) devine ambiguu intre `E` si `Z`.
+
+**Nu blocheaza factura — validat, nu presupus.** Validat offline cu DUKIntegrator, 6 scenarii,
+inclusiv un control negativ care chiar iese cu erori (`BR-CO-13` + `BR-CO-15`) — deci cele „ok"
+inseamna ceva. Trece inclusiv un caz cu `TaxableAmount = -400.00`. Regulile pe categorii
+(`BR-S-08` / `BR-E-08` / `BR-Z-08`) se satisfac trivial: aritmetica inchide, modelarea fiscala e
+cea gresita, si asta niciun schematron nu prinde. **Rezerva de scris explicit:** validatorul local
+e din 2022; validatorul ANAF online n-a fost apelat (interdictie).
+
+**`currencyID="RON"` hardcodat e neconformitate reala si activa, dar fara dovada ca ar cauza
+respingere.** Dovedit pe fisier: XML-ul in EUR de la VENDING_MASTER e identic pe SHA256 cu cel din
+`TRIMISE` (deci exact ce a plecat la ANAF) si a fost acceptat. Respingerea din `ERORI` e a unei
+incarcari anterioare, pentru alte reguli.
+
+**Nu s-a putut proba pe date reale, si asta ramane netransat.** In baza accesibila sunt 3 facturi
+cu discount de document (toate cu o singura cota, anterioare eFacturii) si 34 cu cote mixte fara
+discount — intersectia e goala. Cele 4 XML-uri de productie cu alocare de document sunt, dupa trei
+indicii independente, discounturi pe linie, nu de document. Absenta din date nu e dovada (regula
+casei). Ramane nedovedit prin rulare: reproducerea end-to-end prin program a scenariului „factura
+scutita + discount de document".
+
+**Recomandarea cercetarii pentru #13:** repartizare proportionala automata pe cote, **nu se cere
+utilizatorului cota**. Discountul de document nu are o cota proprie de ales — natura lui de TVA e
+determinata de liniile pe care le reduce; a pune operatorul sa aleaga inseamna a-i cere o decizie
+fiscala pe care datele o dau deja. Pentru explicatie: un singur camp text optional pe document,
+folosit ca `AllowanceChargeReason` in locul constantei (`ReasonCode` ramane `95`).
+
+**Doua completari obligatorii daca se implementeaza, altfel reparatia e degeaba:**
+- bucatile de discount trebuie sa primeasca **`id_jtva_coloana` al grupului pe care il reduc**, nu
+ doar cota — cheia de grupare are cinci campuri si `expltva` se completeaza tot prin
+ `id_jtva_coloana`. O implementare care seteaza doar `proc_tva` lasa grupul orfan exact unde e azi;
+- **eFactura nu are nevoie de nicio modificare** — `xmlefactura.prg:758-792` grupeaza deja
+ `GROUP BY proc_tva` si emite cate un `AllowanceCharge` per cota.
+
+Doua consecinte vizibile daca se implementeaza: factura tiparita va arata N randuri „Discount X %
+Factura" in loc de unul, si nota contabila primeste TVA-ul discountului spart pe cote.
+
+**Decizia a fost luata — decizia 59 (runda 16): repartizare proportionala pe cote.** Vezi sectiunea
+„Decizia 59" de la deciziile rundei 16, cu toate consecintele de implementare.
+
+**Cele doua puncte ramase s-au inchis si ele, tot in runda 16.** Campul text optional de motiv —
+**decizia 61**: da, se adauga (`AllowanceChargeReason`, `ReasonCode` ramane `95`), cu stocare noua
+pe `VANZARI` si un control nou in formular. Asezarea lui s-a inchis in runda 17 — **decizia 66**: sta in banda de totaluri, langa discount. Retroactivi-
+tatea la relistare/retrimitere — **decizia 62**: restrictia de modificare e strict `EsteInEFactura`,
+fara legatura cu nicio data; ramane insa deschis, separat, cazul relistarii (nu editarii) unei
+facturi vechi deja trimise, vezi decizia 62.
+
+### M. Valuta si data cursului (decizia 15)
+
+**Cele doua concepte exista in cod, distinct** — decizia 15 nu introduce o distinctie noua, o face
+vizibila:
+
+- **(a) factura in valuta**: `poDate.in_valuta` / `Curs` / `multiplicator` / `id_valuta`, un singur
+ curs pentru tot documentul;
+- **(b) articol cu pret in valuta pe document in lei**: `poArticol.tip_valuta = 1`, proprietate a
+ politicii de pret, independenta de `in_valuta`. Conversia se face **in VFP**, cu cursul zilei:
+ `poArticol.pretftva = Round(poArticol.pretftva_val * poArticol.Curs / poArticol.multiplicator, gnPPretV)`
+ (`ofacturare.vc2:1989`, `:2017`, `:2953`). Cursurile zilei se incarca exact pe ramura „document in
+ lei”: `If poDate.in_valuta = 1 ... Else citeste_cursuri_zi(poDate.zi_curs)` (`ofacturare.prg:407-418`).
+
+**In baza, exact cum ai descris:** `VANZARI_DETALII` **nu are coloana `CURS`**; pastreaza `PRET` (in
+lei, valoarea de facturare) plus `PRETD` si `ID_VALUTAD` ca urma a pretului original in valuta.
+Cursurile ajung in `VANZARI_CURSURI`, scrise neconditionat la emitere pentru **orice** valuta straina
+aparuta pe linii — deci si pe o factura in lei
+(`PACK_FACTURARE.sql:14491-14501`, `scrie_cursuri`).
+
+**`in_valuta` nu e o alegere, e o proprietate a tipului de document.** Se seteaza o singura data, in
+`Init`: `If Inlist(tnIdSet,223,225,226,227,271) OR INLIST(m.tnTip, 5,6,7,9,10,52) -> .in_valuta = 1`
+(`ofacturare_comun.prg:248-250`), si nu se mai schimba. Selectorul de valuta e chiar eliminat din
+formular cand `in_valuta = 0` (`ofacturare.vc2:9725-9728`), deci operatorul nici nu-l poate alege.
+
+**Problema semnalata, confirmata:** `Clb_zi_curs` e eliminat **doar** pe retur (tip 8, 9), la
+`ofacturare.vc2:9717-9722` — si niciodata in functie de valuta, desi blocul imediat urmator,
+`:9725-9728`, face exact asta pentru selectorul de valuta. Deci **azi campul apare si pe facturi in
+lei**, unde de multe ori nu are ce cauta. Validarea e la randul ei asimetrica: `frm_date_factura`
+cere ziua cursului doar cand `in_valuta = 1` (`:9484`), dar `frm_date_aviz_lucrare` o cere
+**neconditionat** (`:8076`).
+
+**Regula propusa:** campul apare cand tipul nu e retur **si** (documentul e in valuta **sau** exista
+pe document macar un articol cu pret in valuta).
+
+**Unificarea face regula posibila.** Azi cazul (b) nu se poate sti la deschiderea antetului — se
+afla abia dupa incarcarea articolelor, cand antetul e deja inchis si eliberat (`Release
+ofrmceredate`, `ofacturare.prg:248`). In formularul unificat antetul si gridul sunt in aceeasi
+fereastra, deci campul poate aparea in clipa in care intra pe grid primul articol cu pret in valuta.
+**Din acelasi motiv dispare si mecanismul lui #16**: bug-ul de focus si de renumerotare apare la
+revenirea din `frm_curs` intr-un antet care tocmai s-a inchis — in formularul unificat nu mai exista
+un antet inchis la care sa te intorci. `frm_curs` e in `COMUN\clase\onom_curs.vc2:537`, deschis din
+`vizualizeaza_curs` (`oproceduri_curs.prg:8-42`) ca recuperare la eroarea Oracle 20005
+(`ofacturare.prg:313-317`).
+
+**Capcana:** `poDate.zi_curs` se trimite **neconditionat** ca prim parametru catre `cursor_preturi` /
+`cursor_articole_k` / `cursor_gestiune` / `cursor_lucrare` (`ofacturare.prg:272-303`), inclusiv pe
+tip 1. Ascunderea campului nu inseamna golirea valorii — valoarea implicita (data documentului)
+trebuie sa ramana. Iar pe avizul de lucrare, ascunderea fara repararea validarii de la `:8076` ar
+bloca finalizarea antetului cerand un camp care nu mai e pe ecran.
+
+### N. Returul din facturi anterioare (decizia 17)
+
+Rapoarte: `docs\cercetare\factura_retur_document.md` (mecanismul principal) si
+`retur_si_lista_preturi.md`, A (al doilea mecanism).
+
+**Sunt doua fluxuri de cod independente**, care ating aceeasi clasa de formular prin metode si
+proceduri Oracle diferite. Nu au niciun punct comun in afara conventiei de semn a cantitatii.
+
+#### N.1 Factura de retur ca document (tipurile 8, 9 — si avizul de retur, 24)
+
+**Asta e mecanismul pe care il descrie Marius, si functioneaza deja cap-coada.**
+
+- **Intrare:** tile-ul de pe ecranul de facturare (`ofundal_facturare.vc2:882-884`) -> `politica.mpr`
+ -> `factureaza(8)` / `factureaza(9)` (`Meniuri\politica.mn2:14-15, 45-46`).
+- **Alegerea facturilor, la nivel de document:** `frm_date_factura.do_cauta_facturi`
+ (`ofacturare.vc2:9173-9212`) cheama `caut_facturi_multiple_client`
+ (`oproceduri_facturare.prg:2091-2121`) — browse cu **selectie multipla**, titlu „Alegeti facturile
+ (mouse-click pe numar sau apasati SPACE)”. Filtrare pe **client** (obligatoriu ales inainte) si
+ **valuta**; sursele exclud tipurile de retur, deci nu se face retur dintr-un retur. Id-urile alese
+ se aduna intr-un CSV in `poDate.listaid`, numerele in `poDate.descriere`, iar antetul primeste
+ automat textul „RETUR FACTURA …”. Fara alegere nu se poate continua (`:9523-9526`).
+- **Popularea liniilor:** `pack_facturare.cursor_retur` -> `cursor_retur_document`
+ (`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:3943-3956`, `:3958-4071`) selecteaza direct din
+ `VANZARI_DETALII` liniile facturilor alese si le pune in acelasi `crsarticole` pe care celelalte
+ tipuri il umplu cu lista de preturi (`ofacturare.prg:306-311`). **Confirmat exact ce spunea Marius:**
+ `ID_GESTIUNE` vine din linia originala (`:4034`, `:4055`), `PRET_ACHIZITIE` la fel, **neschimbat**
+ (`:4035`, `:4056`), iar pretul de vanzare se recalculeaza pe curs doar daca moneda nu e nationala
+ (`:4016-4030`). `GESTIONABIL` e `NVL2(A1.ID_GESTIUNE,1,0)` — gestionabil doar daca originalul avea
+ gestiune.
+- **Ce se poate face manual:** **stergerea liniilor aduse merge** si cantitatea redevine disponibila
+ in cursorul sursa (`do_sterge`, `ofacturare.vc2:14608-14693`, ramura de retur la `:14658-14659`);
+ **returul partial merge** (`do_verifica_articol`, `:14743-14754`, fata de maximul calculat pe
+ server).
+- **Avizul de retur (24)** foloseste acelasi `cursor_retur` si aceleasi ramuri; difera doar antetul —
+ `nIdTipDoc = 6` si `frm_date_aviz` in loc de `frm_date_factura` (`ofacturare.prg:194-195`, `:225`).
+
+**Singurul gol real, si e acelasi ca la comanda:** pe un document de retur **nu se poate adauga o
+linie din afara facturilor sursa**, pentru ca `crsarticole` **este** rezultatul lui `cursor_retur`
+(`do_adauga_articol` ia articolul mereu din el, `ofacturare.vc2:12843-12851`). Nu e o interdictie
+explicita, e continutul cursorului — exact cauza de la comanda (J). Se rezolva la fel, prin
+`APPEND FROM`, si abia asta face reala decizia 16 pe documentele de retur.
+
+#### N.2 Retur de articole intr-o factura de vanzare normala (`But_retur`)
+
+Butonul (`cmd_butoane.vc2:324-338`, `caction = do_retur`) e vizibil **doar** pe tipurile 1, 5, 7, 10
+(`ofacturare.vc2:15122-15127`) — pe un document de retur nu exista deloc. Aici factura sursa se alege
+**per articol**, la fiecare linie: `caut_facturi_multiple_client_articol`
+(`oproceduri_facturare.prg:2124-2159`), filtrat suplimentar pe articolul curent. Perechile
+`ID_ARTICOL:ID_VANZARE` se acumuleaza in `thisform.cListaIdArticoleRetur` (`:12888`) si pleaca ca
+`poDate.listaid` (`:13977-13979`). Gestiunea se alege prin
+`pack_facturare.cursor_gestiuni_articol_retur`, nu vine din factura sursa — **diferenta de fond fata
+de N.1**.
+
+**Legatura linie-de-retur -> linie originala: neverificat** pe schema. In VFP nu exista coloana de
+linie sursa; la nivel de antet exista `poDate.nid_vanzare_retur` (`ofacturare.vc2:14448`, `:14509`).
+Conteaza doar pentru **afisare** — daca formularul poate arata din ce factura vine fiecare linie.
+
+#### N.3 Ce se schimba in formularul unificat
+
+- **N.1 se muta ca atare.** Alegerea facturilor devine o optiune in meniul butonului de adaugare
+ („Alege facturile de returnat…”), cu acelasi dialog, aceleasi filtre si aceeasi populare din
+ `cursor_retur`. **Nu se reproiecteaza nimic din ce merge**, si in special nu se atinge preluarea
+ gestiunii si a pretului de achizitie din facturile originale.
+- **N.2 capata si alegerea la nivel de document**, dupa modelul lui N.1, pastrand calea per-articol
+ pentru cazul cu un singur articol.
+- **Lista de preturi devine disponibila si pe documentele de retur** (decizia 16), prin acelasi
+ `APPEND FROM` ca la comanda. Consecinta de proiectat: pe acelasi document vor coexista linii
+ aduse din facturi sursa (cu gestiune si pret de achizitie mostenite) si linii libere, care nu au
+ factura sursa.
+ **Decizia 22 (Marius, 09.08.2026): linia de retur fara factura originala e permisa, ca pe orice alt
+ document.** Returul nu face exceptie de la regula deciziei 16 — sursa umple documentul, nu il
+ inchide, si nici nu apare doar „pentru corectii”. Consecintele de proiectat, acum ferme:
+ - **gestiunea si pretul de achizitie nu se pot mosteni** pe o linie libera, pentru ca nu exista linie
+ originala. Se aleg, ca la N.2 (`cursor_gestiuni_articol_retur`), nu se preiau ca la N.1;
+ - **maximul returnabil calculat pe server nu se aplica** unei linii fara factura sursa — nu exista
+ cantitate originala fata de care sa se limiteze;
+ - afisarea „din ce factura vine linia” trebuie sa suporte si valoarea goala (vezi mai sus, legatura
+ linie-de-retur -> linie originala, inca neverificata pe schema).
+
+*De pastrat cum e:* excluderea returului dintr-un retur, filtrarea pe client si valuta, maximul
+returnabil calculat pe server, si mostenirea gestiunii si a pretului de achizitie. Nu se ating.
+
+### O. Facturile din ROAAUTO (decizia 18)
+
+Raport: `docs\cercetare\roaauto_facturi.md`.
+
+> **Precizare la descrierea liniilor de mai jos.** „Liniile unei facturi ROAAUTO nu sunt articole” e
+> adevarat doar pentru liniile **generate din deviz**. Langa ele pot sta articole reale, adaugate
+> prin mecanismul **„Alte servicii”** — vezi O-bis, verificat pe cod
+> (`docs\cercetare\roaauto_articole_lista_preturi.md`). Restul sectiunii ramane valabil: tipul `-12`,
+> drumul comun prin `PACK_FACTURARE`, faptul ca editorul lui #6 le vede, si blocarea modificarii
+> dupa facturare — ultima **reconfirmata**.
+
+**Ce se confirma.** ROAAUTO nu are cale proprie spre baza: `factureaza_deviz`
+(`ROAAUTO\Programe\oproceduri_devize.prg:846`) cheama acelasi `PACK_FACTURARE` partajat —
+`initializeaza_date_factura` (`:1211`), `adauga_articol_factura_deviz` (`:1240`), `oscrie_in_fisiere`
+(`:1269`), `scrie_in_vanzari` (`:1302`) — deci liniile trec prin acelasi `VANZARI_DETALII_TEMP` si
+ajung in acelasi `VANZARI_DETALII` ca orice factura ROA. Tipul documentului e **`-12`**
+(`:922`). Editorul lui #6 le vede deja, fara cod de recunoastere a sursei, verificat pe date reale
+(`id_vanzare = 1047`). **Deci partea de „le vede” e gratuita.**
+
+**Ce nu se confirma — si asta schimba dimensiunea deciziei.** „Se pot modifica ulterior” **nu e
+adevarat azi, in niciun produs**:
+
+- in ROAAUTO, formularul de devize isi dezactiveaza butonul de modificare de indata ce comanda are
+ numar de factura (`oviz_devize.vc2:4536`); singura actiune post-facturare gasita e re-listarea
+ (`oproceduri_devize.prg:1516`), care nu scrie nimic. Niciun apel din ROAAUTO catre
+ `modifica_date_factura`;
+- in ROAFACTURARE, gridul de articole din editorul nou (`frm_modific2024`, `COMUN\clase\omodificari.vc2`)
+ e **read-only prin design**, la nivel de grid si pe fiecare `Text1`.
+
+Deci decizia 18 nu extinde o cale existenta, **creeaza o capacitate care nu exista nicaieri**.
+
+**Cum arata liniile.** `factureaza_deviz` agrega sumele devizului si insereaza cate o linie sintetica
+per categorie, cu `id_articol` **negativ**: `-100000` MANOPERA (`:965-967`), `-100003` MATERIALE
+(`:947-949`), `-100001` discount manopera, `-100005` / `-100006` avans si stornare avans,
+`-100007` / `-100008` inspectie tehnica si spalare (`:936-1027`). Optional, cu
+`gnAUTOIdArticolReparatii` setat, toate se cumuleaza intr-o singura linie cu un articol real
+(`:989-1004`). Langa ele pot sta **articole reale**, prin „Alte servicii” — vezi O-bis.
+
+### O-bis. „Alte servicii” — cum se adauga azi articole reale in ROAAUTO
+
+Raport: `docs\cercetare\roaauto_articole_lista_preturi.md`. **Asta e mecanismul de refolosit.**
+
+- **Unde:** formularul `frm_incasare_finala` (`ROAAUTO\Clase\oviz_devize.vc2:5435-7143`), aratat **la
+ emiterea facturii finale** (`do_factureaza_final`, `:2569`) — nu pe devizul propriu-zis.
+- **Sursa articolelor:** `cauta_nom_articole` pe `vnom_articole_toate`
+ (`COMUN\programe\ocautare.prg:1781-1823`), filtrat `in_stoc = 0 and in_crm = 1` si cu id-urile
+ sintetice excluse (`oviz_devize.vc2:6539-6580`). **Nomenclatorul brut, si numai articole fara
+ stoc** — nu lista de preturi, nu politici.
+- **Pretul se tasteaza manual.** `do_adauga` nu completeaza pretul si cantitatea; operatorul le pune
+ in grid, iar `do_modifica_alteserv` recalculeaza valoarea (`:6692-6698`, `:7064-7070`). Nu exista
+ preluare automata de pret pe calea asta.
+- **Liniile raman separate.** Cumularea in „REPARATII AUTO” include doar id-urile sintetice
+ (`oproceduri_devize.prg:999-1012`); randurile din `crsalteserv` se insereaza dupa, cu `id_articol`
+ real, si ajung ca atare in `VANZARI_DETALII_TEMP` (`:1036-1041`, `:1240-1257`).
+- **Gestiune: tot zero.** `id_gestiune` nu e completat de niciun `INSERT` si pleaca `0` spre Oracle
+ (`:1201-1206`, `:1255`) — consistent cu filtrul `in_stoc = 0`. Deci **nici articolele reale din
+ ROAAUTO nu descarca gestiune**. Diferenta fata de liniile sintetice e doar `id_articol`.
+- **Stergere si modificare:** exista, dar **doar cat timp formularul e deschis, inainte de emitere**
+ (`do_sterge`, `:6730-6741`).
+- **Contul pleaca gol.** `crsvanztemp` are coloana `Cont c(4)`, dar `INSERT`-ul care il umple nu o
+ include (`oproceduri_devize.prg:1190-1206`); apelul trimite literal `''` (`:1256`), care ajunge
+ `NULL` in `VANZARI_DETALII_TEMP.CONT`, fara `NVL` si fara fallback. Deci **liniile de articole reale
+ din ROAAUTO se scriu azi fara cont** de gestiune, tacut. Vezi J-bis.
+- **Si fara politica de pret — dar pe alta cale decat credeam.** `id_pol` lipseste peste tot pe firul
+ asta (nu e nici in `crsalteserv`, nici in `crsvanztemp`, nici in semnatura lui
+ `adauga_articol_factura_deviz`). **Motivul pentru care asta nu produce `FACT-024`** e ca fluxul
+ ROAAUTO **nu trece prin `contabilizeaza_articol`**: merge pe `scrie_in_vanzari`, care nu genereaza
+ nicio nota de venit. Vezi **J-ter**.
+
+> **Corectie importanta la temeiul deciziei 18.** Ideea ca „«Alte servicii» face deja jumatate din ce
+> cerem, deci se generalizeaza” **nu se sustine**. Mecanismul acela functioneaza tocmai pentru ca
+> ocoleste contabilizarea de venit; generalizat pe fluxul ROAFACTURARE, unde `contabilizeaza_articol`
+> **este** apelata (`scrie_factura2`, `ff_...:6150`), s-ar lovi de `FACT-024`. Ce ramane valabil din
+> O-bis e descrierea UI (articole reale langa linii sintetice, pret tastat, fara gestiune) — nu si
+> concluzia ca partea grea e deja rezolvata.
+
+**Ce inseamna asta pentru decizia 18.** Doua lucruri, in directii opuse:
+
+- **usureaza** partea de model: un articol real langa linii sintetice **nu e o noutate**, e deja
+ cazul normal al facturilor auto. Intrebarea „cum coexista” are deja un raspuns in produs;
+- **nu rezolva** cerinta: mecanismul traieste in formularul de emitere al ROAAUTO si moare odata cu
+ el. Ce cere Marius e aceeasi capacitate **la modificare**, care nu exista nici acolo, nici aici.
+
+**Intrebarile ramase, in ordinea in care blocheaza:**
+
+1. ~~**Ce se intampla cu totalul devizului**~~ — **RASPUNS (runda 7)**, raport
+ `docs\cercetare\pack_auto_actualizeaza_deviz.md`. Premisa intrebarii era gresita: **nu exista niciun
+ `SUM` peste `VANZARI_DETALII`, pentru ca `PACK_AUTO` nu citeste deloc `VANZARI` /
+ `VANZARI_DETALII`** — zero potriviri pe `VANZARI` in tot pachetul (1804 linii).
+ `actualizeaza_deviz` (`ff_2026_03_31_02_AUTO_PACK_AUTO.sql:692-733`) face trei lucruri, toate pe
+ structura proprie ROAAUTO: scrie cota TVA pe `DEV_ORDL`, stampileaza `ID_FACT` pe `RUL`, si — doar
+ pe anumite `id_set` — pe `NOM_LUCRARI`. E o legatura **deviz -> document**, nu un recalcul
+ **document -> total deviz**. Nu e nici macar specifica facturarii: aceleasi trei apeluri o
+ folosesc si la inchiderea de productie si de regie, care scriu note contabile, nu facturi.
+ **Deci o linie noua pe `tip = -12` nu poate dezechilibra nimic pe partea Oracle**, si nu e nevoie
+ de niciun apel suplimentar catre ROAAUTO. Precedentul „Alte servicii” confirma pe date live:
+ liniile reale coexista de mult cu cele sintetice, fara ca `actualizeaza_deviz` sa faca distinctie.
+ **Ce ramane, si e de alt fel:** o **desincronizare de afisare**. Totalul devizului aratat in
+ ROAAUTO se calculeaza din `RUL` si din cursoarele de facturare (`oviz_devize.vc2:7816-7823`),
+ **niciodata** din `VANZARI_DETALII` — deci nu va arata linia adaugata, nici azi, nici dupa #13.
+ In schimb **relistarea o va arata**: `relisteaza_factura_deviz` citeste `fact_vfacturi_detalii`
+ (`oproceduri_devize.prg:1564`), un view neconditionat peste `VANZARI_DETALII`
+ (`ff_2024_06_04_01_COMUN_FACTURARE.sql:8-94`). Factura retiparita si ecranul de deviz vor spune
+ lucruri diferite — **DECIS (decizia 28): e acceptabil.** Cerinta lui Marius e ca **MANOPERA si
+ MATERIALE sa fie conform devizului**; restul articolelor pot exista pe factura fara sa apara in
+ ecranul de deviz. Nu se cere cod nou in ROAAUTO si nu se mai pune intrebarea.
+2. **Gestiunea, pentru articole cu stoc. DECIS (decizia 20):** se admit si articolele gestionabile.
+ ROAAUTO ocoleste subiectul filtrand `in_stoc = 0`; filtrul acela **nu se preia**. Deci pe
+ documentele auto vor coexista linii care descarca stoc cu linii care nu descarca — caz nou, de
+ proiectat, nu de evitat.
+3. **Cine ramane proprietarul documentului** dupa ce ROAFACTURARE ii adauga o linie — mai poate
+ ROAAUTO sa-l relisteze corect (`relisteaza_factura_deviz` citeste din `fact_vfacturi`)?
+
+**Reconfirmat:** dupa emitere nu exista cale de intoarcere in ROAAUTO. `verifica_stornare`
+(`oviz_devize.vc2:4513-4514`) e o metoda **goala**; `do_storneaza_avans` priveste doar avansul.
+Singurul instrument gasit asupra unei facturi emise e stergerea totala (soft-delete) prin ecranul
+generic din COMUN — nu o editare.
+
+**Secventierea — reevaluata dupa raport (runda 7).** Marius a cerut ca `pack_auto` sa fie cercetat
+inainte de orice estimare (decizia 23), si a avut dreptate: raspunsul **rastoarna recomandarea
+initiala**. Motivul pentru care decizia 18 urma sa se livreze ultima era riscul tehnic de a scrie pe
+un produs pe care #13 nu-l controleaza. **Acel risc nu exista** — `PACK_AUTO` nu citeste `VANZARI` /
+`VANZARI_DETALII` deloc, deci nu are ce sa se dezechilibreze (vezi intrebarea 1 de mai sus).
+
+Ce ramane nu mai e risc tehnic, ci **o singura intrebare de produs**:
+1. ~~e acceptabil ca ecranul de deviz sa nu arate linia adaugata din #13~~ — **RASPUNS, decizia 28:
+ da, e acceptabil.** Conditia e alta: MANOPERA si MATERIALE conform devizului.
+2. cine ramane proprietarul documentului (intrebarea 3 de mai jos) — nu s-a schimbat.
+
+**Decizia 18 nu mai trebuie sa fie ultima din motive tehnice.** Ordinea de lucru din S4g ramane insa
+valabila din alt motiv, mai bun: se face intai pe documentele ROAFACTURARE, unde scrierea e a
+noastra, pentru ca acolo se aseaza mecanismul; `tip = -12` vine dupa, ca **aplicare**, nu ca risc.
+
+**Perimetru:** gridul read-only din `frm_modific2024` si `ofacturare_editare.prg` sunt ale lui **#6**.
+Deschiderea lui la scriere nu se face din #13 fara intelegere explicita — un singur scriitor pe fisier.
+
+### L. Observatii colaterale, gasite in timpul verificarii
+
+Nu fac parte din #13 si nu se repara aici — se semnaleaza ca sa nu se piarda.
+
+0-ter. **(runda 9) O nota de vanzari cu set multi-rand inregistreaza venitul si descarca gestiunea de N
+ ori.** In `pack_facturare.contabilizeaza_articol`, `cursor_articol` face `LEFT JOIN NOTE_CONTABILE D ON
+ C.ID_SET = D.ID_SET` **fara `ROWNUM`, fara agregare, fara filtru**
+ (`ff_2026_08_09_01_...:7218-7271`), iar bucla care il consuma (`:7393-7542`) executa `scrie_nota`
+ **si** `descarca_gestiune` **o data pentru fiecare rand al setului, cu aceeasi cantitate si acelasi
+ pret intreg** — nu impartite. Nu exista nicio logica de distributie: `ORDINE` nu apare in tot pachetul.
+ Azi nu se manifesta pentru ca toate cele 7 note de vanzari active au exact un rand pe set — dar **30
+ din cele 40 de seturi din baza au mai multe, cu maxim 30 de randuri**. Deci e o bomba armata de
+ configurare: cine ataseaza unei politici de pret o nota cu set multi-rand obtine **dublare de venit si
+ dublare de descarcare de gestiune**, silentios. **E in `PACK_FACTURARE`, adica in COMUN** — se
+ semnaleaza, nu se repara din #13. Conteaza direct pentru reteta din J-quater: vezi acolo.
+ Sursa: `docs\cercetare\s10_pret_rederivat.md`, „Completare", p. 1 + `verif_baza_vie_cont_venit.md` p. 6.
+0-quater. **(runda 9) Politica de pret fara `ID_NOTA` nu are nicio plasa de siguranta.** Spre deosebire de
+ articolul lipsa din politica (`FACT-024`), aici nu exista cod de eroare: lantul de `LEFT JOIN` din
+ `cursor_articol` supravietuieste inelului lipsa, cursorul intoarce **un rand cu totul `NULL`**, iar
+ `scrie_nota` insereaza in `ACT_TEMP` un rand cu conturile de debit si credit **nule**. Daca `ACT_TEMP`
+ are `NOT NULL` pe ele, iese un `ORA-01400` generic in loc de un mesaj `FACT-0xx` — **neverificat**,
+ DDL-ul lui `ACT_TEMP` nu e in export. Starea exista in baza vie **azi**: politicile active `32 HOTEL
+ TAXE` si `33 HOTEL CAZARE` n-au `ID_NOTA`. Independent de #13.
+0-bis. **(runda 7) `do_modifica` pare sa scrie `id_valuta` in loc de `id_sectie`.** In
+ `frm_modific2024.do_modifica` (`COMUN\clase\omodificari.vc2:13941`), ramura
+ `CASE m.lcControl = 'sectie'` face `replace sectie with loCauta.sectie, id_valuta with
+ loCauta.id_sectie`. Daca e ce pare, textul afisat al sectiei se schimba dar coloana `id_sectie`
+ nu — si, in plus, se strica `id_valuta`. **Necitit pe date, doar pe cod.** Fisierul e in
+ **perimetrul lui #6** (`omodificari.vcx` a intrat in proiect prin `97d1613`) — se semnaleaza acolo,
+ nu se repara de aici. Conteaza pentru #13 pentru ca sustine partial verdictul „`ID_SECTIE` e
+ editabil": teoretic da, practic poate nu.
+0. **(runda 7) Handler-ul lui `FACT-024` se auto-saboteaza cand `id_pol` e `NULL`.** In
+ `pack_facturare.contabilizeaza_articol` (`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:7286-7311`),
+ ramura `WHEN NO_DATA_FOUND` construieste mesajul cu inca doua `SELECT ... INTO`, dintre care al
+ doilea e `FROM CRM_POLITICI_PRETURI WHERE id_pol = detalii_articol.id_pol`. Cu `id_pol` `NULL`,
+ **si acel `SELECT` da `NO_DATA_FOUND`**, iar in handler nu exista al doilea nivel de tratare — deci
+ utilizatorul primeste un `ORA-01403` generic in loc de mesajul `FACT-024` formatat. Articolul
+ apucase sa fie rezolvat, deci informatia nu se pierde de tot, dar diagnosticul e mult mai prost.
+ **E in `PACK_FACTURARE`, adica in COMUN** — se semnaleaza, nu se repara din #13. Devine relevant
+ direct daca se alege varianta 3 din J-bis.
+1. **`do_copiaza`, ramura de avize: variabila gresita.** La `ofacturare_comun.vc2:3702-3703`, ramura
+ `CASE INLIST(loFactura.tip, T21, T24, T26, T30, ...)` scrie `lnTip = T22` in loc de
+ `loFactura.tip = T22`, deci degradarea de tip **nu se aplica** pe acea ramura. **Fisierul e in
+ perimetrul lui #6** — nu se atinge de aici; efectul nu a fost verificat pe date.
+2. **„Proforma -> factura” merge prin omisiune.** Copierea nu propaga `nIdTipDoc` pentru ca linia e
+ comentata (`ofacturare_comun.prg:370`), deci copia unei proforme porneste implicit pe FACTURA.
+ Functioneaza, dar ca efect secundar, nu ca ramura dedicata. Daca #13 atinge copierea, merita
+ transformat in intentie explicita.
+3. **Asimetria de resetare a globalelor** — vezi „Canalul de precompletare”, mai sus.
+4. **Modificarea in bloc pare sa goleasca campuri pe care nu le-ai atins.** Pe selectie multipla
+ (`lnNrInreg > 1`), `do_modifica` face `Scatter Name poRec Memo Blank` si reseteaza explicit ruta,
+ delegatul, agentul, masina, `dataora_exp`, `id_facturare`, `listare_detaliata`, `tip_saft`,
+ `text_aditional` si `efactura` (`ofacturare_comun.vc2:4565-4580`). Cum acesti zece parametri se
+ scriu **neconditionat** in `VANZARI` (I-bis), un `SCAN` peste facturile alese pare sa scrie valorile
+ goale pe **fiecare** dintre ele — deci schimbarea rutei pe trei facturi ar sterge delegatul si
+ textul aditional de pe toate trei. **De confirmat pe date inainte de a fi numit bug**: e posibil ca
+ fluxul sa presupuna ca operatorul completeaza tot ce vrea propagat. **Fisierul e in perimetrul lui
+ #6** — se semnaleaza, nu se repara de aici. Conteaza si pentru #13: formularul unificat lucreaza
+ pe un singur document si trebuie sa trimita antetul intreg (I-bis, consecinta 1), deci nu
+ mosteneste problema.
+
+**L.4 (runda 11). Numarul de POS nu se dezaloca la Renunt.** In `frm_alte_date`, la anulare se
+dezaloca numarul de chitanta (16) si cel de bon fiscal (3), dar **nu si cel de POS (26)** —
+`docs\cercetare\s3b_alte_date_analitice.md`, sectiunea 9. Bug preexistent, in productie, **nu introdus
+de #13**. Conteaza pentru S3b pentru ca „`actualizeaza_tipincasare` se muta ca atare" **l-ar propaga
+in formularul unificat**. Se repara in trecere sau se lasa ca azi si se preia separat — punct de decis,
+vezi lista de la finalul rundei 11.
+
+---
+
+## Stories
+
+Ordinea e strict pe risc: unificarea intai (livrabil de sine statator, util si fara regenerare),
+regenerarea peste ea.
+
+## Metoda de executie (Marius, runda 14) — obligatorie, nu recomandare
+
+**Planul asta e un document de proiectare, nu un plan de executie. La implementare se SPARGE PE
+STORIES, si fiecare story se executa ca livrare de sine statatoare.** Nu se porneste implementarea pe
+tot #13 deodata, nu se acumuleaza modificari nelivrate peste mai multe povesti, si nu se trece la
+povestea urmatoare cu cea precedenta netestata si nerevizuita.
+
+### Ce inseamna „spart pe stories"
+
+- **O story = o unitate de livrare.** Are perimetru propriu de fisiere, criteriu „gata cand" propriu
+ (fiecare story de mai jos il are deja scris) si se incheie cu diff + review + commit propriu.
+- **Inainte de prima linie de cod dintr-o story**, se scrie o **nota de executie** in `docs\` care
+ transpune proiectarea in pasi concreti: fisierele atinse, metodele atinse, ordinea editarilor, si ce
+ se testeaza dupa fiecare. Proiectarea spune *ce* si *de ce*; nota de executie spune *unde* si *in ce
+ ordine*. Rapoartele din `docs\cercetare\` sunt materia prima — nu se reface cercetarea.
+- **Povestile cu dependente declarate** (`*Depinde de:*`, la fiecare story) **nu se pornesc in paralel
+ cu cele de care depind.** Unde nu e dependenta, se pot rula in paralel de agenti diferiti — dar
+ **un singur scriitor pe fisier**, niciodata doi agenti pe aceeasi metoda.
+- **O story care se dovedeste prea mare la executie se sparge mai departe**, cu acordul lui Marius, si
+ se noteaza in plan. Mai bine cinci livrari mici decat una care nu se poate revizui.
+
+### Teste la fiecare pas — nu doar la S6 si S12
+
+`S6` si `S12` raman testele **pe flux real**, la capatul fiecarei etape. **Ele nu inlocuiesc testarea
+per story.** Fiecare story se incheie cu teste proprii, rulate si trecute, **inainte** de review:
+
+- **Harness headless** (`COMUN\docs\depanare_testare_vfp.md`) pentru logica — cazurile minime ale
+ povestii, plus **cel putin o proba de neregresie** pe calea veche, care trebuie sa ramana neatinsa.
+- **Harness UI vizibil** (`COMUN\docs\testare-ui-vfp.md`) unde povestea atinge formulare sau griduri —
+ coloanele de grid **nu se materializeaza headless**, deci acolo verificarea headless nu e concludenta.
+- **Rezultatul asteptat se declara INAINTE de rulare**, inclusiv pentru cazurile care trebuie sa dea
+ eroare. Un test scris dupa ce s-a vazut rezultatul nu dovedeste nimic.
+- **Un esec documentat e livrabil valid** — se raporteaza, nu se ascunde si nu se reia la nesfarsit.
+- Testele fiecarei povesti **se pastreaza**, si intra in suita rulata de S6 / S12. Nu se scriu de
+ unica folosinta.
+
+### Code review dupa implementare, inainte de commit — pentru fiecare story
+
+**Nicio story nu se comite fara review, si review-ul vine dupa implementare si dupa teste, nu in loc
+de ele.** Ordinea, fixa:
+
+1. **Implementare** (delegata unui subagent, conform modului de lucru din `CLAUDE.md`).
+2. **Teste** — rulate, trecute, cu rezultatele raportate.
+3. **Diff ca fisier in `docs\`** (`diff_s_.patch`), inclusiv partea din `COMUN`.
+4. **Code review pe diff**, de catre **un agent care nu a scris codul** — altfel isi revizuieste
+ propriile presupuneri. Review-ul verifica cel putin: regresia pe calea veche, conventiile per zona
+ atinsa (`COMUN\docs\reguli_lucru.md`, punctul 7 — encoding `cp1250` la `.vc2`/`.sc2`, `GO` pe
+ `Recno()`, `goExecutor` + `ALTER TABLE`, UX formulare/griduri), comentariile (istoric **numai** in
+ antetul fisierului, max o linie in cod), si ca write-back-ul text→binar e facut pentru fiecare
+ fisier atins.
+5. **Aprobarea lui Marius.**
+6. **Commit** — in **ambele** repo-uri unde e cazul (ROAFACTURARE si COMUN), cu changelog.
+
+**Afirmatiile review-ului se verifica, nu se cred.** Un review poate citi structura corect si presupune
+semantica gresit; cand semnaleaza un defect, se deschide codul citat inainte sa fie acceptat — la fel
+cum se procedeaza cu rapoartele de cercetare.
+
+**Ce NU face review-ul:** nu reargumenteaza deciziile luate (lista lor e in acest plan), nu extinde
+perimetrul povestii, si nu propune refactorizari colaterale. Ce gaseste in afara perimetrului se
+**raporteaza separat**, nu se repara in trecere — exact cum s-a procedat cu defectul `lnTip` din
+`do_copiaza`.
+
+### Etapa I — formularul unificat
+
+#### S1 — Inventarul de campuri si alegerea bazei
+Deciziile de perimetru sunt luate (vezi listele de la inceput). Ramane: **se porneste de la prototipul
+`frm_facturare_articole2` sau de la `frm_facturare_articole` extins?**
+Recomandare: **de la prototip**, si acum cu trei argumente in plus fata de runda 2 — are deja
+controalele de antet, are butoanele **deasupra** gridului (decizia 13), si are coloanele de discount
+editabile plus procentul pe linie (decizia 14). Partea grea de layout e deja acolo; logica lipsa se
+porteaza in el.
+Livrabil: tabel camp-cu-camp `frm_date_factura` / `frm_date_aviz` / `frm_modifica_factura` /
+`frm_alte_date` -> formular unificat, cu ce se pastreaza, **in ce grup din cele patru intra** (I),
+ce se pliaza, ce dispare, si **cu ruta de scriere a fiecarui camp** (pe loc sau prin regenerare —
+vezi G-bis). Baza de pornire: `docs\cercetare\inventar_controale_formulare.md`, care are deja
+etichetele reale si conditiile de vizibilitate.
+**Livrat (runda 7): `docs\S1_inventar_campuri_formular_unificat.md`** — 30 de campuri de antet, cu
+grupul din I, conditiile de vizibilitate si ruta de scriere pentru fiecare, plus randul dedicat lui
+`V_EFACTURA` (singurul camp fara control azi, nicaieri) si cele patru bife marcate ca disparute.
+Tabelul a scos la iveala **golul de rute de scriere** din G-bis — vezi acolo. Are si o sectiune
+„Neclarificate" cu opt puncte, dintre care doua ambiguitati de nume (`chkDetaliat`, `cboTipFactura`
+apar in doua formulare si nu s-a confirmat pe cod ca scriu acelasi camp).
+**Coloana „ruta de scriere" e completa acum** — `rute_scriere_antet.md` a inchis cele trei grupuri
+lasate neclarificate, iar deciziile 25 si 26 le-au dat ruta. Tabelul se citeste **impreuna cu tabelul
+de rutare din G-bis**, care e sursa de adevar pentru ruta fiecarui camp; sectiunea „Neclarificate" din
+S1 ramane valabila doar pentru punctele **4, 5, 7 si 8** (ambiguitatile `chkDetaliat` / `cboTipFactura`,
+liniile exacte de definire a controalelor, si dependenta de drepturi).
+*Gata cand:* tabelul e aprobat. **APROBAT de Marius, 09.08.2026 — S1 e incheiata.** Tabelul devine
+referinta pentru S3 si S3b; modificarile ulterioare se fac in el, nu se rescrie de la zero.
+
+**ASEZAREA ZONEI DE JOS — INCHISA prin decizia 57 (Marius, runda 15): VARIANTA D.**
+Cerinta initiala (runda 14), formulata de el: *„totalurile de jos sa fie mai compacte, si sa includa
+si discount-ul; formularul trebuie sa fie compact si aerisit; incasarea si alte date jos de tot,
+eventual 2 butoane pe acelasi rand — vezi modelul Saga; in centrul atentiei sa fie datele facturii"*.
+Referinta vizuala: `{06D747B8-0824-488C-8832-DEB9AE661974}.png`.
+Rundele 14-15 au dat patru variante (A / B / C, apoi D). **Aleasa: D.** Vezi „Decizia 57" la
+deciziile rundei 15, care are enuntul complet, cele patru consecinte de implementare si punctul lasat
+deschis. Ce e de retinut aici, pentru executia lui S1:
+
+- **Antetul se strange la doua randuri**, fara titluri de grup — campurile se recunosc dupa eticheta.
+- **Panoul separat „Discount pe document" dispare**; discountul devine rand editabil in banda de
+ totaluri, cu procentul pe loc.
+- **Banda de totaluri** e pe toata latimea, lipita de grid: baza, discount articole, discount document
+ cu procentul, TVA — desfacute pe un rand — si totalul mare singur la dreapta.
+- **Incasare si Alte date NU sunt dialoguri** — sunt doua sectiuni colapsabile in formular, **una
+ langa alta pe acelasi rand**, sub totaluri, fiecare cu rezumatul continutului pe randul inchis.
+- **Bara de comenzi de jos nu exista**: `but_renunt` / `but_termin` raman in banda de titlu.
+
+**Cota de TVA a discountului de document s-a decis — decizia 59, runda 16** (vezi sectiunea K-bis):
+repartizare proportionala automata pe cote, discountul **NU cere cota de la utilizator**, deci **nu
+e nevoie de o a treia sectiune pentru cota**. Ce mai cere UI e **un camp text optional de motiv**
+(pentru `AllowanceChargeReason`), mult mai mic decat o sectiune. **Decizia 61 (runda 16) l-a
+materializat: Marius vrea campul. Asezarea lui s-a inchis definitiv abia in runda 17 — decizia 64
+(a treia sectiune jos) a fost **rasturnata de decizia 66: motivul sta in banda de totaluri, langa
+suma pe care o explica**, iar randul de jos ramane cu **doua** sectiuni, ca la decizia 57. Varianta
+grea (cota + explicatie proprii) ramane exclusa, ca mai sus.
+
+**Cele doua pagini online ale lui #13 — nu se confunda:**
+- **mockup-ul formularului** (fisier pe disc, `docs\mockup_13_formular_unificat.html`, **v9** din runda
+ 17, cu asezarea D si motivul discountului in banda de totaluri):
+ **https://claude.ai/code/artifact/e9d73e86-7518-4f50-a998-43c49e083142**.
+ Are copie pe disc, si ea e sursa de adevar; artifactul se republica din ea (`WebFetch` pe URL intai,
+ apoi `Artifact` cu `url`). Decizia 33 e consumata — URL-ul e la zi.
+- **pagina cu variantele de asezare** (A/B/C/D), **fara copie pe disc**, deci artifactul **e** sursa de
+ adevar:
+
+Pagina cu variantele: **https://claude.ai/code/artifact/dfc70d38-856f-48fd-b6af-3da78e9da4f7**
+— **nu mai are copie pe disc** (cerinta lui Marius, runda 15: „doar online, ca sa nu mai intretii 2
+variante"). Procedura de modificare: `WebFetch` pe URL → fisier de lucru **in scratchpad, nu in
+`docs\`** → `Artifact` cu `url` = link-ul de mai sus.
+
+#### S2 — O singura procedura `factureaza`
+Se elimina `factureaza2` ca procedura paralela; `factureaza` primeste un mod. Se pastreaza
+integral ramurile care lipsesc azi din `factureaza2` (lista din A).
+
+**ACTUALIZAT dupa decizia 67 (Marius, 20.08.2026) — comutatorul `gnFacturareNou` cu dialog e
+INLOCUIT.** Proiectarea initiala (mai jos) alesese sa mute verificarea `gnFacturareNou` la punctul
+de alegere a lui `lcObject`, in interiorul lui `factureaza` — implementata asa intr-o prima trecere.
+Marius a respins comutatorul global cu dialog: vrea acces simultan la ambele fluxuri, nu un
+`AMESSAGEBOX` care alege intre ele. Mecanismul final: `plFacturareNoua`, variabila **Private**
+declarata de apelant (nu comutator persistent), plus o **intrare noua de meniu** ("Facturare (nou)",
+buton `Cw10` in `Clase\ofundal_facturare.vc2`) care o seteaza inainte de a apela `factureaza(N)`.
+Detalii complete la **Decizia 67**, mai jos in acest document (dupa Decizia 66).
+
+**PROIECTAT (runda 9) — `docs\cercetare\s2_factureaza_unificare.md`.**
+**S2 e mult mai ieftina decat arata planul.** `factureaza2` nu e a doua implementare functionala care
+cere fuziune atenta — e un fork din 08.06.2017 la care **executia interogarii de articole e dezactivata**
+(`lnSucces = 1` hardcodat, `goExecutor.oExecute` niciodata apelat) si mai multe blocuri intregi sunt
+inchise cu `If .F.`. Are **exact un apelant** in tot codul — `ofacturare.prg:90`, din interiorul lui
+`factureaza`, in spatele unui `AMESSAGEBOX` de confirmare — deci **zero utilizatori reali**. Ambele sunt
+proceduri globale in `COMUN\programe\ofacturare.prg` (`:81-577` si `:583-1081`, ~500 de linii fiecare),
+fara omonime. Singura diferenta functionala care justifica existenta lui `factureaza2` e formularul de
+articole (`frm_facturare_articole2` vs `frm_facturare_articole`).
+**Obstacolul nu e tehnic:** formularul spre care duce e tot un prototip neterminat, deci unificarea
+procedurilor **nu** face formularul nou utilizabil — doar elimina duplicarea. Aia rămâne treaba lui S3.
+**Trei corectii la lista din sectiunea A:** `verifica_numar(16, ...)` pentru chitanta **nu lipseste** din
+`factureaza2` (e identic, `:502-504` vs `:1018-1020`) — planul greseste; „`cursor_avize` cu tip 23" e
+imprecis — tipul 23 nu lipseste, e **rutat diferit** (`cursor_preturi` in `factureaza` vs
+`cursor_gestiune` in `factureaza2`), ceea ce e mai grav decat o omisiune; si lipsesc din plan **tipul 52**
+pe ramura de contract si **tipul 24** pe ramura de retur. Semnatura propusa, ramificarea interna, ordinea
+in care se face fara sa strice suita si criteriul de „gata" verificabil sunt in raport, sectiunile 5-7.
+**`ofacturare.prg` e cod comun al intregii suite** (copie in fiecare produs ROA, sincronizata manual) —
+la fel ca S3c, nu se face impreuna cu alta modificare. Butonul de meniu (`Clase\ofundal_facturare.vc2`)
+e specific ROAFACTURARE, nu e cod comun.
+*Gata cand (rescris dupa decizia 67 + completare + corectie review):* `factureaza2` nu mai exista;
+`ofacturare.prg` nu mai contine `gnFacturareNou`; are exact o aparitie a lui `plFacturareNoua`
+(variabila Private a apelantului), la punctul de alegere a lui `lcObject`; meniul „Facturare" (`Page2`)
+are o intrare noua „Facturare (nou)" (`Cw10`) cu **primele patru** optiuni ale paginii (`Cw1..Cw4` -
+lista de preturi, contract, comanda, aviz - singurele care trec prin `factureaza`; `Cw5..Cw9` ruteaza
+prin `initializeaza_vanzare_din_stoc()`, un flux separat, in afara perimetrului), meniul „Avize"
+(`Page3`) are o intrare noua „Avize (nou)" (`Cw5`) cu toate cele patru optiuni ale paginii (toate
+verificate ca trec prin `factureaza`) — ambele seteaza `plFacturareNoua` si deschid
+`frm_facturare_articole2` prin `Cw.do_actiune()`, fara sa afecteze
+butoanele existente.
+*Depinde de:* S1.
+
+#### S3 — Portarea logicii de antet in formularul unificat
+Cele 17 + 13 metode `do_cauta_*`, `do_schimba_tipdoc`, validarile din `inainte_de_do_termin`
+(`ofacturare.vc2:9455-9561` si `:7277-7352`) si `Init`-urile. Se porteaza **o singura data**, cu
+ramificare pe factura / aviz in interior, nu doua copii.
+Punct de atentie cunoscut: **#16 din `todos.txt`** — la revenirea din formularul de curs valutar,
+focusul sare pe tip document si iesirea din serie regenereaza numarul actului.
+
+**PROIECTAT (runda 9) — `docs\cercetare\s3_portare_antet.md`.** Doua rezultate schimba povestea:
+
+- **Portarea „o singura data cu ramificare" nu e posibila ca atare.** `Init`, `inainte_de_do_termin` si
+ partial `do_cauta_fdoc` sunt **omonime cu semantica total diferita pe toate cele patru formulare-sursa**
+ (antet vs. articole vs. alte-date). Deci nu e o metoda cu ramificare interna, sunt **patru fuziuni de
+ metoda**. Obstacolul principal al lui S3 nu e codul de validare — majoritatea e `Do Case` / `amessagebox`
+ mecanic — ci **reconcilierea a patru cicluri de viata `Init` / `inainte_de_do_termin` independente
+ intr-unul singur**, cu ordinea de dependente din sectiunea 5 a raportului. Numarul real de `do_cauta_*`
+ e **29, nu 30**. Lista completa a omonimelor e la sectiunea 2 — **se citeste inainte de orice editare**,
+ altfel portarea le confunda (capcana deja platita o data cu `do_calculeaza_discount`).
+- **#16 nu e un bug de focus, si nu e in perimetrul in care il caută planul.** Reprodus pe cod pana la
+ linia exacta: bucla de reincercare din `factureaza` / `factureaza2` (`ofacturare.prg:174-571`) trateaza
+ **orice esec SQL** — nu doar cursul valutar lipsa — ca pe un „DA, continui cu alt document", si
+ redeschide formularul de antet de la zero. Deci **unificarea nu-l reproduce automat**; poate chiar sa-l
+ elimine ca efect secundar, daca antetul nu se mai reconstruieste din `Init` dupa un esec Oracle in pasul
+ urmator. **Cade premisa „ori se rezolva #16 aici, ori se reproduce bug-ul".** Si leaga #16 de **S2**, nu
+ de S3 — bucla e in procedura, nu in formular.
+
+*Gata cand:* un document se emite integral din formularul unificat, pe tip 1 (lista de preturi), cu
+acelasi rezultat in `vanzari` / `act` / `rul` ca pe calea veche — criteriul rescris verificabil e la
+sectiunea 7 a raportului, iar ce **nu** se poate testa headless la sectiunea 8.
+*Depinde de:* S2.
+
+#### S3b — Sectiunea pliata: alte date + analitice
+Deciziile 7 si 8. Se muta in formular cele patru grupuri din `frm_alte_date` (B) si coboara acolo
+analiticele din antet. `actualizeaza_tipincasare` se muta ca atare; **alocarea si dezalocarea
+numerelor** de chitanta / bon fiscal / POS raman legate de aceleasi evenimente ca azi, nu de
+deschiderea formularului. `frm_alte_date` nu se sterge cat timp calea veche mai e in uz.
+**Doua precizari din runda 7, amandoua restrang povestea:**
+- **analiticele coborau ca AFISARE, nu ca editare** (decizia 26) — **CADUC: decizia 72 le face
+ editabile**, si la introducere, si la reemitere. Nu se scrie `ReadOnly` pe ele si nu mai e nevoie de
+ tooltipul explicativ; editorul de nota al lui **#6** ramane singurul loc care le trateaza pe linie;
+- **pe un document deja emis, grupul de incasare e blocat in etapa I** (decizia 25) — nu are ruta de
+ scriere pe loc, iar regenerarea nu exista inca. La emitere se comporta ca azi.
+
+ **AMANAT LA S8c (23.08.2026), decis de Marius.** Blocarea nu are azi nicio stare pe care sa se
+ declanseze: pe `frm_facturare_articole2` nu exista notiunea de „document deja emis" — zero
+ `numar_act`, `Init` are un singur parametru (`toFactura`, doar pentru copiere), `oDateFactura`
+ n-are `numar_act`, iar `lcopiere` / `lArticoleIncarcate` inseamna altceva. Singura blocare
+ conditionata din toata clasa e pe **tipul** documentului (aviz), nu pe stare. In plus,
+ `but_modifica` — de care depinde criteriul „ambele stari ale antetului" — **e S8c**, nu exista
+ inca. O garda scrisa impotriva unei stari care nu poate aparea nu se poate testa, deci **decizia
+ 25 iese din criteriul de „gata" al S3b si trece in S8c**, impreuna cu notiunea de document emis.
+ Cercetarea completa, inclusiv ce inseamna „blocat" pe fiecare tip de control din grup:
+ `docs\cercetare\s3b_decizia25_document_emis.md`. Confirmat acolo si ca **nu exista ruta de
+ reemitere**, nici in VFP, nici in Oracle (`PACK_FACTURARE.scrie_incasari` are doi apelanti, ambii
+ interni fluxului de emitere; zero apeluri din VFP).
+**PROIECTAT (runda 11) — `docs\cercetare\s3b_alte_date_analitice.md`.** S3b nu e o mutare de controale.
+Trei rezultate schimba povestea:
+
+- **Riscul din criteriul de „gata" e real, si are mecanism.** Alocarea numarului de chitanta nu porneste
+ din clicul utilizatorului, ci din **orice atribuire programatica** a lui `.Value`:
+ `opt_incasat.ProgrammaticChange` (`ferestre_cere_date.vc2:3351-3352`) cheama acelasi
+ `actualizeaza_tipincasare()` ca `.Click` (`:3250-3251`). Consecinta neasteptata: **azi, deja**,
+ `Init` (`:3150`) seteaza singur `opt_incasat.Value = 2` cand documentul soseste cu `poDate.incasat<>0`
+ (cazul copierii), deci deschiderea dialogului aloca un numar fara ca cineva sa atinga ceva. Intr-un
+ formular unde zona se plieaza si se deplieaza repetat pe acelasi `poDate` persistent, o repopulare
+ naiva a starii ar aloca si dezaloca **la fiecare toggle**. Solutia proiectata: populare **o singura
+ data**, iar plierea strict pe `Visible`/`Height` — niciodata pe reasignare de `.Value`. Criteriul de
+ non-alocare e formulat ca **assert headless pe `poGeneratorNumere`**, pe doua scenarii de start
+ (document nou **si** document copiat cu incasare presetata — al doilea e cel care azi chiar aloca).
+- **Nu exista mecanism de pliere de refolosit.** Cautare exhaustiva in `ofacturare.vc2`: zero potriviri
+ in prototipul `frm_facturare_articole2`. Cel mai apropiat tipar din suita e
+ `frm_modific2024.afiseaza_rulaje` (`omodificari.vc2:13169-13199`, perimetrul #6 — **citit, neatins**),
+ acelasi idiom sus/jos validat deja pentru `but_modifica`/`but_salveaza` la decizia 9. Deci **cod nou**,
+ dupa un tipar existent, nu o clasa reutilizabila.
+- **Decizia 26 cerea mai mult decat mecanismul existent** — `ct_clb_cautare.do_dezactiveaza()`
+ (`caut_ora.vc2:800-806`) ascunde **doar lupa de cautare**, textbox-ul ramane tastabil, deci read-only
+ real ar fi cerut `ReadOnly` explicit pe langa el. **CADUC odata cu decizia 72**: analiticele raman
+ editabile, deci nu se scrie nimic. Constatarea despre `do_dezactiveaza()` ramane valabila pentru
+ oricare alt camp care ar avea nevoie de blocare reala.
+
+**Bug preexistent, gasit in trecere:** la Renunt se dezaloca chitanta (16) si bonul fiscal (3), dar
+**nu si POS (26)**. Nu e introdus de S3b, dar „`actualizeaza_tipincasare` se muta ca atare" **l-ar
+propaga**. **Decizia 40: se repara aici, in trecere** — deci diff-ul lui S3b nu mai e o mutare pur
+mecanica, si testarea acopera si dezalocarea POS pe calea veche.
+
+**Decizia 41 fixeaza granularitatea plierii: doua comutatoare.** Grupul de **incasare** are comutator
+propriu — e singurul cu efecte laterale (alocare/dezalocare) si singurul blocat pe document emis prin
+decizia 25 — iar delegat/transport, adresa, text aditional si analiticele stau impreuna sub al doilea.
+Garda de non-alocare la toggle se scrie si se testeaza astfel **intr-un singur loc**.
+
+*Gata cand:* criteriul rescris verificabil e la sectiunea 10 a raportului, in cinci puncte — mai strans
+decat formularea de mai jos pe trei dintre ele: paritatea de emitere se cere pe **toate patru** tipurile
+de incasare (nu doar bon fiscal), non-alocarea la toggle se cere pe **ambele** scenarii de start, iar
+iar blocarea grupului de incasare — **amanata la S8c, vezi mai sus** — se cerea pe **ambele stari ale antetului** (inainte si dupa
+`but_modifica`), nu doar la deschidere. **Punctul care cerea read-only-ul analiticelor pe ambele stari
+cade odata cu decizia 72** — analiticele sunt editabile, si la introducere, si la reemitere, deci
+criteriul devine invers: pe un document emis analiticele **se pot alege**. Formularea initiala,
+pastrata ca rezumat: un document cu incasare prin bon fiscal emis din formularul unificat produce
+aceleasi randuri si acelasi numar de bon ca pe calea veche, iar deschiderea si inchiderea formularului
+fara a atinge zona de incasare **nu aloca si nu dezaloca niciun numar**.
+*Depinde de:* S3.
+
+#### S3c — Sursa ca parametru, nu ca global
+Decizia 12. Punctele de intrare exista deja (comanda: `ocomenzi.vc2:1580-1596`; contract: din
+ROACONTRACTE), dar transmit prin globalele `goComanda` / `goContract`. Se adauga parametru explicit
+pe `factureaza` si pe `oDateFactura`, cu globalele pastrate ca sursa de rezerva pana se convertesc
+toti apelantii (inclusiv cei din ROACONTRACTE si ROAGEST — e cod comun). Se verifica intai asimetria
+de resetare semnalata la L.3.
+**PROIECTAT (runda 11) — `docs\cercetare\s3c_sursa_ca_parametru.md`.** Se poate face, e o interventie
+mica — dar **planul supraestimeaza cat de „globala" e problema azi**, si in doua sensuri opuse:
+
+- **`goContract` nu e scris nicaieri in ROAFACTURARE** — nici in codul produsului, nici in `COMUN`-ul
+ lui. Deci ramura de precompletare din contract (`ofacturare_comun.prg:261-297`) e **cod mort in acest
+ produs**, iar **asimetria de resetare de la L.3** (`ofundal_facturare.vc2:886-902`) exista textual dar
+ e **inerta**: n-are ce sa lase nereseta, pentru ca n-are scriitor. Devine risc real abia daca cineva
+ adauga in viitor un scriitor in ROAFACTURARE — moment in care lipsa resetarii s-ar activa **tacut**.
+- **`goComanda` chiar e viu, si are DOI scriitori**, nu unul: clicul pe „Factureaza"
+ (`ocomenzi.vc2:1583`) **si** navigarea in grid (`:2199`, doar ca sa decida vizibilitatea unui buton).
+ Al doilea n-are nicio legatura cu facturarea si **ramane si dupa conversie** — deci globala nu dispare.
+- **Criteriul „pana se convertesc toti apelantii" nu se poate citi ca „pana dispare globala".** In
+ ROACONTRACTE, `goContract` e **bufferul de editare al intregului ecran de contracte** (peste 100 de
+ `ControlSource` legate de el), populat de navigarea in grid, independent de facturare. Nu dispare la
+ aceasta poveste si nici la vreuna rezonabila urmatoare; S3c schimba **doar canalul** prin care valoarea
+ ajunge la `oDateFactura.Init`.
+
+**Suprafata de regresie, masurata:** doi scriitori de convertit (`ocomenzi.vc2:1580-1596`;
+`ferestre_contracte.vc2:1538-1549` + `:1598-1606` in ROACONTRACTE), **trei** fisiere comune atinse o
+singura data fiecare (`ofacturare.prg`, `oproceduri_facturare.prg`, `ofacturare_comun.prg`), si **zero
+schimbari** la celelalte ~31 de puncte de intrare din inventarul S2 — toate cheama `factureaza(N)` cu un
+singur argument. Cele cinci fisiere sunt **identice pe MD5** in cele sapte produse, cu o singura exceptie:
+**ROAIMOB**, o linie lipsa in `ofacturare_comun.prg` — acolo diff-ul se aplica **manual**, nu prin copiere
+mecanica.
+
+**Semnatura propusa:** `factureaza(tnTip, toFactura, toSursa)` si `oDateFactura::Init(tnIdSet, tnTip,
+toSursa)` — parametru nou la coada, cu implicit, fallback pe global cand lipseste.
+**Capcana de limbaj, semnalata explicit:** garda se scrie `Type('toSursa') = 'O'`, **nu**
+`Type('toSursa') <> 'U'`. Un parametru VFP nepasat **nu** e `'U'` (aia e pentru variabile nedeclarate),
+ci `'L'` cu `.F.` — o garda `<> 'U'` ar trece mereu adevarat si ar incerca sa citeasca `.id_part` de pe
+`.F.`, eroare la primul apel neconvertit. Raportul cere verificarea comportamentului `Type()` pe un
+`.prg` de proba **inainte** de a atinge fisierele reale.
+
+*Gata cand:* criteriul rescris e la sectiunea 10 punctul 4 al raportului, pe patru probe — una
+structurala (parametrul prezent cu semnatura identica in toate cele trei fisiere comune, in toate cele
+sapte produse) si trei comportamentale: **calea convertita** cu globala deliberat „murdara" dintr-o
+navigare anterioara produce documentul dat prin parametru, nu pe cel din globala; **calea neconvertita**
+(oricare din cele ~31 de apeluri cu un singur argument) produce acelasi document ca inainte; iar
+**ROACONTRACTE** da aceeasi precompletare ca azi, verificat manual pe build separat.
+*Depinde de:* S2. **Atinge cod comun intregii suite** — nu se face impreuna cu alta modificare.
+
+#### S4 — Cautarea articolelor pe server, in linie
+Partea Oracle: variante filtrate pe articol ale cursoarelor de facturare, cu aceleasi ramuri pe tip
+ca `cursor_preturi` / `cursor_contract` / `cursor_comanda` / `cursor_avize` / `cursor_gestiune`.
+Partea VFP: `combosql` pe cod si pe denumire completeaza linia cu pret, cota TVA, valuta, `id_pol`,
+`gestionabil`, `pret_cu_tva`; `crsarticole` nu se mai incarca in masa.
+Se pastreaza "adauga tot" pentru tipurile care au document sursa (comanda, aviz, contract) — acolo
+setul e marginit si incarcarea lui e legitima.
+**PROIECTAT (runda 11) — `docs\cercetare\s4_cautare_articole_server.md`. Criteriul de mai jos nu e
+atingibil ca atare, si motivul nu e UX.**
+
+- **`crsarticole` nu e doar sursa de populare a gridului — e un registru al cantitatii ramase de
+ facturat.** E citit **si scris** de `do_adauga_tot`, `do_sterge` si `do_scrie_factura` pentru toate
+ tipurile cu document sursa: stergerea unei linii **reface** cantitatea in `crsarticole`
+ (`ofacturare.vc2:14640-14669`), iar la scriere se face `Calculate Sum(cantitate) To lnCantitateRamasa`
+ peste el ca sa se decida daca se inchide automat comanda / avizul (`:14303-14311`, `:14334-14338`).
+ Deci pe **comanda, aviz si contract** incarcarea in masa **nu poate disparea**, indiferent de decizia
+ de UX privind „adauga tot" — bookkeeping-ul e cablat pe cursorul incarcat. **S4 se aplica curat doar
+ pe ramurile de lista de preturi** (`cursor_preturi`, plus jumatate din `cursor_contract` si
+ `cursor_gestiune`).
+ **DEPASIT de proiectarea punctului 2 (runda 12)** — se citeste doar ca istoric al deciziei 39.
+ Concluzia „incarcarea in masa nu poate disparea" cadea pentru ca `crsarticole` era tratat ca un
+ registru omogen; sunt de fapt **doua mecanisme distincte** (Rol A / Rol B), si niciunul nu cere
+ cursorul incarcat. Vezi mai jos.
+- **`combosql` e un prototip la jumatate, si e singura lui utilizare din suita.**
+ `grd_factura.cCodMat.cboCodmat` / `cCboDenumire` (`ofacturare.vc2:16751-16797`, wiring la
+ `:19288-19334`) chiar cauta pe server, dar scrie **doar** `codmat` / `denumire` / `id_articol`, pentru
+ ca sursa lui (`vnom_articole`) n-are pret, TVA, valuta, `id_pol`, `gestionabil`. Cautare in
+ `COMUNROA` si `ROAGEST`: **zero alte utilizari** — nu exista de unde copia un exemplu complet.
+ Confirma insa exact punctul C: de facut e **varianta filtrata pe articol a celor cinci cursoare**, nu
+ o cautare noua.
+- **`cursor_contract` produce deja doua cursoare** — `V_CURSOR` (`crsarticole`, prin delegare la
+ `cursor_preturi`) si `V_CURSOR2` (`crsarticole1`, articole **sau** rate). Filtrarea se aplica curat
+ doar pe jumatatea `crsarticole`; **randurile de rata n-au `id_articol`** si raman needitate.
+- **Vizibilitatea de azi a butonului „adauga tot" coincide aproape exact cu impartirea utila pentru S4**
+ (`ofacturare.vc2:15108-15248`: ascuns pe lista de preturi, vizibil pe comanda / aviz / retur) —
+ confirmare pe cod, nu presupunere.
+- **Legatura cu S10, confirmata:** pretul se cauta **o singura data**, la alegerea liniei, si se
+ transmite mai departe neschimbat — exact ce face azi `adauga_articol_factura`, care il primeste ca
+ parametru in loc sa-l re-derive.
+- **Efect secundar al filtrarii, rezolvat prin decizia 42:** `verifica_cursuri_valute` e azi
+ neconditionata in procedura, deci pe varianta filtrata s-ar declansa la **fiecare** cautare de articol
+ in loc de o data la deschidere — cu `-20005` posibil pe o valuta pe care operatorul n-o foloseste,
+ inainte sa vada vreun rand. Se **restrange la valuta articolului cautat**.
+- **Cele doua puncte „de inchis inainte de implementare" sunt INCHISE (runda 12)** —
+ `docs\cercetare\s4_puncte_deschise.md`. Raspunsul de baza e la amandoua „filtrarea nu schimba nimic",
+ dar **fiecare lasa in urma o cerinta de implementare, nu doar o bifa**:
+ - **`id_jtva_coloana` chiar lipseste** din `cursor_preturi`, din `cursor_gestiune` si din `V_CURSOR2`
+ al lui `cursor_contract`, pe toate ramurile — confirmat pe SQL. **Nu e bug:** `do_initializeaza_articol`
+ pune `0`, iar `frm_articol_factura.Init` (mostenit si de `frm_articol_gest_factura`) **il rederiva
+ mereu** din `proc_tvav` via `jtva_coloane`, pe orice linie adaugata prin `do_adauga_articol`.
+ **Cerinta care rezulta pentru S4:** derivarea tine **numai** daca linia trece prin
+ `do_adauga_articol`. `combosql`-ul prototip de azi (`ofacturare.vc2:19288-19306`) face `REPLACE`
+ direct in `crsfactura` si **ocoleste toata derivarea**; daca S4 extinde acel `REPLACE` fara sa treaca
+ prin `do_adauga_articol`, `id_jtva_coloana` ramane nederivat si Oracle
+ (`adauga_articol_factura`, ramura `ELSE`) arunca **`-20000 FACT-013`** sau scrie cota gresita.
+ **Bug nou posibil, introdus de S4** — intra ca cerinta explicita in proiectare, nu ca observatie.
+ - **`but_urmator_tot1` are `Visible = .F.` la design** (`ofacturare.vc2:11265`); tipurile 23 si 41 au
+ `Case` propriu, dar **niciunul nu-l face vizibil** — confirmat, nu presupus. Nu exista alt mecanism
+ de „adauga tot"; exista insa `but_urmator1` (adaugare rand-cu-rand), **neconditionat de tip**, care
+ merge prin acelasi `do_adauga_articol` — deci dupa S4 **nu se pierde nimic** pe aceste tipuri.
+ - **Corectie de rutare fata de ce presupunea planul:** pe formularul **standard** (`factureaza`,
+ `ofacturare.prg:266-308`) doar **tipul 41** cheama `cursor_gestiune`; **tipul 23 cheama de fapt
+ `cursor_preturi`** (grupat cu lista de preturi). Tipurile **45, 48, 49 nu ating deloc**
+ `cursor_gestiune` (45 → `cursor_preturi`, 48/49 → `cursor_articole_k`, alta procedura). Doar pe
+ **prototip** (`factureaza2`, opt-in `gnFacturareNou`) 23 si 41 merg impreuna pe `cursor_gestiune` —
+ **divergenta reala intre cele doua formulare**, semnalata, neatinsa, in afara perimetrului S4.
+
+**Decizia 39 largeste povestea peste ce propunea raportul.** Raportul recomanda restrangerea la lista de
+preturi, tocmai pentru ca registrul de cantitate ramasa blocheaza restul; Marius a ales sa se desfaca si
+registrul. Deci S4 are de acum **doua bucati, nu una**:
+1. **varianta filtrata a cursoarelor** + completarea liniei din `combosql` (partea proiectata in raport);
+2. **decuplarea bookkeeping-ului de cantitate ramasa** de cursorul incarcat in masa — sursa unica, nu o a
+ doua copie tinuta in pas cu prima. Atinge `do_adauga_tot`, `do_sterge`, `do_scrie_factura` si
+ **inchiderea automata** a comenzii / avizului.
+
+**Punctul 2 — PROIECTAT (runda 12): `docs\cercetare\s4_punct2_registru_cantitate_ramasa.md`.** Iese mult
+mai ieftin decat parea, pentru un motiv care nu se vedea din raportul punctului 1.
+
+- **`crsarticole.cantitate` are DOUA roluri, nu unul** — si numai unul e „registrul" temut.
+ **Rol A — cantitate ramasa de facturat dintr-un document sursa** (comanda `3,21,25,28,42,47`; avize
+ `4`). **Rol B — plafon de cantitate in sesiune** (lista de preturi gestionabila `1,22,29` si jumatatea
+ de contract, transfer `23,41`, retur `8,9,24`): impiedica operatorul sa adauge mai mult decat vede pe
+ ecran. **Rol B nu alimenteaza nicio decizie Oracle** — e plafon de UI, nu registru de business.
+- **Pe Rolul A, cursorul VFP e o copie redundanta a unui calcul pe care Oracle il repeta oricum.**
+ `do_scrie_factura` sumeaza `crsarticole` doar ca sa decida ce trimite in `pnParametruAditional`, iar
+ Oracle **recalculeaza independent, din tabele reale**, in `inchide_comanda()` / `marcheaza_facturat()`,
+ chiar in procedura care scrie factura.
+- **Nu exista coloana `INCHISA`.** Cautare in tot pachetul: **zero potriviri** (verificat separat de
+ sesiunea principala). „Comanda inchisa" e o stare **derivata** din `COMENZI_ELEMENTE` vs
+ `VANZARI_DETALII`; `inchide_comanda()` insereaza un **rand compensator**, nu seteaza un flag. Pe
+ comanda, `pnParametruAditional` e strict **binar** — „s-a cerut fortarea inchiderii?" —, iar cantitatea
+ trimisa de VFP **nu participa** la calculul Oracle.
+- **Pe avize e altfel, si aici sta subtilitatea:** `VANZARI.FACTURAT` **e** un flag persistat, iar
+ `V_VERIFICARE` (= `pnParametruAditional`) alege intre „**increde-te in VFP** si marcheaza toate avizele
+ referite" (`0`) si „**recalculeaza per-aviz** din tabele reale si marcheaza doar cele cu `ramas = 0`"
+ (`1`). Deci pe aviz suma din VFP schimba semantica, nu doar declanseaza o actiune.
+- **Un bug preexistent, de REPRODUS identic, nu de reparat in trecere:** cand un `crsarticole` agrega mai
+ multe avize, suma globala poate da `0` desi un aviz are ramas si altul are exces care-l compenseaza —
+ caz in care toate se marcheaza facturate, inclusiv cel cu ramas real. Varianta noua pastreaza aceeasi
+ conditie de declansare (suma globala pe tranzactie, nu per document).
+- **`23` si `41` nu apar deloc in `CASE`-ul de finalizare** — cad pe `ELSE`, fara nicio inchidere:
+ transferul n-are document sursa de inchis, doar plafon (Rol B). Contractul (`2,6,52`) intra pe
+ `scrie_rate_factura`, care **nu e o inchidere**, e alta operatie.
+- **Recomandarea: (b) pentru Rolul A, (c) pentru Rolul B.**
+ **(b)** cele doua `Calculate Sum` din `do_scrie_factura` se inlocuiesc cu un apel Oracle facut **dupa**
+ `do_scrie_articole()` (cand `VANZARI_DETALII_TEMP` contine exact liniile pe cale sa fie scrise) si
+ **inainte** de `Do Case`-ul care alege procedura de scriere. Cele doua functii Oracle noi sunt o
+ **extragere** a interogarii pe care `inchide_comanda` / `marcheaza_facturat` o ruleaza oricum, nu logica
+ noua. Efect secundar gratuit: dispare si un bug latent de concurenta — cursorul local nu vede azi ce a
+ facturat intre timp alt operator din aceeasi comanda.
+ **(c)** plafonul Rol B se cere pe server **la fiecare adaugare/editare**, minus ce e deja in
+ `crsfactura` — deci nu mai exista a doua copie de tinut in sincron.
+ Varianta cu un cursor propriu, minimal, a fost **respinsa motivat**: ramane tot o a doua copie manuala,
+ doar mai ingusta. Nu e „sursa unica".
+- **Cazul limita cerut in plan** (adauga si sterge inainte de salvare) devine **trivial**, nu doar
+ acoperit: liniile adaugate-si-sterse nu ajung niciodata in `VANZARI_DETALII_TEMP`, deci nu influenteaza
+ calculul, fara nicio actiune de refacere.
+- **CORECTIE asupra punctului 1:** pasul lui 5 (`s4_cautare_articole_server.md:417-424`) opreste
+ incarcarea in masa si pe `23,41`, presupunand ca n-au bookkeeping — **au Rol B**, confirmat pe cod.
+ Punctul 1 **nu se poate aplica pe `23,41`** inainte ca punctul 2 sa acopere Rolul B pe ele.
+
+**Toate trei sunt INCHISE (runda 13). Nu se mai reiau.**
+1. ~~**Asimetria din `do_modifica`**~~ — azi, pe grupul `1,22,29` + contract-lista, plafonul **nu** se
+ ajusteaza la editarea cantitatii unei linii deja adaugate. E preexistenta. **INCHIS — decizia 45
+ (runda 13, pe recomandare):** se lasa sa se **corecteze de la sine** prin recalculul la cerere, cost
+ zero, dar corectia se **declara explicit in changelog** — S4 schimba atunci un comportament punctual,
+ nu doar „decupleaza".
+2. ~~**Corectia pe `23,41`**~~ — **INCHIS — decizia 46 (Marius, runda 13): asteapta punctul 2.**
+ Punctul 1 **nu se redeschide** acum; aplicarea lui pe `23,41` vine odata cu recalculul pe server, care
+ acopera Rolul B. Nu se pierde nimic: ordinea de implementare oricum le pune dupa.
+3. ~~**Contract `26,52`**: nu s-a gasit dovada nici de prezenta, nici de absenta a Rolului B.~~
+ **INCHIS de proiectarea S5** (`docs\cercetare\s5_acoperire_tipuri.md`): `26` si `52` **n-au niciun
+ bookkeeping**, nici Rol A, nici Rol B — excluderea e totala, pe `Do Case` exhaustiv fara ramura
+ implicita. Deci „dovedit absent", nu „nepresupus". Nu mai e o decizie de luat.
+
+**Cerinta de revizuire**: cele doua functii Oracle noi sunt o extragere din proceduri existente, dar
+raman **PL/SQL nou in `PACK_FACTURARE`**, cu `JOIN`-urile reproduse **din citire, nu din executie**. Se
+verifica pe Oracle inainte de a continua — e primul pas al implementarii, nu o formalitate.
+
+**Nota de executie (decizia 60):** pe documentele de tip **48/49** (custodie), cautarea pe server in
+linie ramane restransa la articole `IN_STOC = 0` — nu se ofera articole gestionabile pe aceste tipuri.
+Siguranta regenerarii la editarea custodiei (decizia 60,
+`docs\cercetare\custodie_48_49_stergere_reemitere.md`) atarna de acest invariant.
+
+*Gata cand:* patru probe, nu una. **(a)** Deschiderea formularului nu mai executa niciun cursor de
+articole, **pe niciun tip** — nu doar pe lista de preturi. **(b)** Alegerea unei linii produce aceleasi
+valori ca randul corespunzator din `crsarticole` de azi, pe fiecare tip; maparea camp-cu-camp e la
+sectiunea 6 a raportului, cu coloanele semnalate explicit acolo unde varianta filtrata **nu** poate
+produce aceeasi valoare. **(c)** **Paritate pe inchiderea automata** (decizia 39): acelasi document
+sursa, aceleasi linii facturate partial, **aceeasi stare finala** — pe comanda, acelasi rand compensator
+in `COMENZI_ELEMENTE` (nu exista flag `INCHISA` de comparat); pe aviz, exact aceleasi `VANZARI.FACTURAT`
+marcate, inclusiv in cazul in care avizele agregate se compenseaza intre ele — pe fiecare tip cu document
+sursa —
+inclusiv cazul in care operatorul adauga si apoi sterge linii inainte de a salva, care azi trece prin
+refacerea cantitatii in `crsarticole`. **(d)** O linie adaugata prin cautarea in grid ajunge in
+`crsfactura` cu **`id_jtva_coloana` derivat** — adica trece prin `do_adauga_articol`, nu prin `REPLACE`
+direct ca prototipul de azi; proba e ca documentul se scrie fara `FACT-013` si cu aceeasi cota ca pe
+calea veche. **(e)** Pe un document de tip 48/49, cautarea pe server nu ofera si nu permite adaugarea
+unui articol cu `IN_STOC <> 0` (decizia 60).
+*Depinde de:* S3. **Punctul 2 nu e proiectat** — se proiecteaza separat inainte de implementare.
+
+#### S4b — Bara de butoane si meniul de adaugare
+Decizia 13, proiectata in J. Trei bucati:
+1. **Butoanele de linie deasupra gridului**, cu eticheta, nu iconite mute: linie noua (`but_nou`),
+ sterge linia (`but_sterge`), detalii linie.
+2. **Un singur buton „Adauga articole” cu `xmenu()`**, cu optiunile din tabelul din J. Inlocuieste
+ `But_urmator_tot1` (azi fara caption si fara `ToolTipText`) si butonul separat de alegere.
+ **Acopera si contractele** — tipurile 2, 6, 26, 52 lipsesc azi din conditiile de vizibilitate
+ (`ofacturare.vc2:15113-15245`), desi avizele sunt acolo.
+3. **Alegerea selectiva**, dupa tiparul RORIS: dialog modal cu coloana de bifat si criterii de
+ cautare, populare aditiva in cursorul local, nicio scriere in baza pana la salvare. Pe contract,
+ unitatea de selectie e **rata** — cazul explicit cerut. Spre deosebire de modelul RORIS, la zero
+ rezultate se spune de ce, nu se inchide in tacere.
+**PROIECTAT (runda 11) — `docs\cercetare\s4b_bara_butoane_meniu.md`.** Implementabila fara cod nou major,
+cu **patru corectii** fata de textul de mai sus:
+
+- **Golul de contract e mai mare decat „lipseste `but_urmator_tot1.Visible`".** Pe **tipul 52**
+ formularul nu intra in **niciun** `Case` al `Do Case`-ului (`ofacturare.vc2:15109-15248`) — deci pierde
+ si titlul, si eliminarea coloanei `cSerie`, nu doar butonul „tot".
+- **Nu se porneste de la tiparul RORIS.** `frm_tranzit` e specific ROAACNPRO si ar insemna formular nou;
+ ROAFACTURARE are deja `cauta_alfa(..., tnTipReturn=1)` — mecanism **generic** de selectie multipla cu
+ bifare, criterii de cautare si populare aditiva, folosit **chiar in acest formular** pentru returul
+ multi-factura (`do_cauta_facturi`). Mai ieftin, si deja dovedit in productie.
+- **„Unitatea de selectie e rata" e adevarat doar pe jumatate.** `crsarticole1` are **doua ramuri
+ disjuncte** in SQL — `OPT_FACTURARE = 3` (articole reale) si `OPT_FACTURARE IN (1,2)` (rate de
+ scadentar) — iar un contract e mereu pe una singura, niciodata pe amandoua. Eticheta „Alege ratele de
+ facturat…" e corecta doar pe a doua ramura; **contractul are deci doua meniuri, nu unul**.
+- **Un gol de cod, nu doar de vizibilitate:** `do_adauga_tot` parcurge azi **exclusiv `crsarticole`,
+ niciodata `crsarticole1`**. Fara extindere, „adauga tot" pe contract fie n-ar face nimic, fie ar aduce
+ liniile gresite — deci pe contract butonul trebuie **scris**, nu doar facut vizibil.
+
+**Echivalenta „tot" = „alege total"** tine azi prin constructie, pe o singura rutina comuna de adaugare
+pe rand (`do_adauga_articol`) — se pastreaza asa, iar pe contract devine adevarata abia dupa extinderea
+de mai sus.
+
+*Gata cand:* pe fiecare sursa (comanda, contract, avize, document returnat) meniul ofera si „tot" si
+„alege", iar rezultatul in `crsfactura` e identic pe cele doua cai cand selectia e totala — **inclusiv
+pe contract**, unde azi „tot" nu parcurge cursorul potrivit, si **inclusiv pe tipul 52**, care azi nu
+intra in nicio ramura. Pasii cu criterii verificabile sunt la sectiunea 7 a raportului; ce nu se poate
+testa headless, la sectiunea 8.
+*Depinde de:* S4.
+
+#### S4c — Discountul pe linie, mutat din dialog in grid
+Decizia 14, proiectata in K. Dialogul de articol dispare odata cu unificarea, deci cele doua campuri
+de discount ale lui — **procent** si **valoare unitara** — devin coloane in grid, cu acelasi calcul
+reciproc din `frm_articol_factura.do_calculeaza_discount` mutat pe evenimentele coloanelor. Se repara
+in acelasi timp inconsecventa de azi (read-only in lei, editabil fara recalcul in valuta). Se
+pastreaza excluderea pe `in_valuta`. Modelul de date **nu se atinge** — se stocheaza tot valoarea.
+**VERIFICAT — S4c e deblocata, dar capcana e alta decat se credea.** Raport:
+`docs\cercetare\discount_in_rapoarte_si_efactura.md`.
+
+- **Niciun raport de factura nu tipareste discountul pe linie** — nici valoare, nici procent. Cautare
+ in toate `.fr2` de factura / proforma / invoice din `COMUN\Rapoarte`: **zero potriviri** pe „disc".
+ Singurele doua `.fr2` cu „DISCOUNT" sunt de NIR, nu de facturi emise. Se tipareste `pretftva` si
+ `valftva`, **deja nete de discount** (`prelucreaza_factura`, `ofacturare_comun.prg:1055-1059`,
+ `:1156-1248`, in cursorul `crsfacttemp`).
+- **eFactura foloseste exact acelasi cursor** (`xmlefactura.prg`) — `LineExtensionAmount` si
+ `PriceAmount` sunt aceleasi valori nete, cu optiunea (dezactivata implicit) de a adauga si un
+ `cac:AllowanceCharge` informativ pe linie.
+- **SAF-T (D406) nu exista in ROAFACTURARE** — doar tabele de nomenclator cu prefix `saft_` (coduri
+ TVA / plata), pe partea de achizitii, fara legatura cu `DISCOUNT_UNITAR`.
+- **Deci ingrijorarea initiala („utilizatorul schimba totalul fara sa se vada pe hartie") era gresit
+ tintita:** discountul nu se vede pe hartie **prin design**, iar totalul se vede corect pentru ca
+ pretul tiparit e deja net.
+
+**PROIECTAT (runda 12) — `docs\cercetare\s4c_discount_in_grid.md`.** Implementabila, cu **capcana
+retintita**: formularea de mai jos, din rundele anterioare, era in acelasi timp prea alarmista si prea
+vaga.
+
+- **Baza de date nu e in pericol.** `do_scrie_articole` trimite spre Oracle **direct** din
+ `discountftva` / `discountctva` / `vdiscountftva` / `vdiscountctva` (`ofacturare.vc2:14081-14083`,
+ ales pe `cu_tva` si `tip_valuta`) — verificat pe cod, nu presupus. Deci
+ `VANZARI_DETALII.DISCOUNT_UNITAR` iese **mereu corect**, indiferent de starea campurilor agregate.
+- **Riscul e strict local, si e o inconsistenta, nu o valoare veche.** `valdiminuatftva` /
+ `valdiminuatctva` sunt agregate citite de `prelucreaza_factura` **din acelasi `crsfactura` din
+ memorie**, nereincarcat din Oracle. Netratate, factura tiparita poate iesi cu `pretftva` corect si
+ `valftva` inconsistent — **pret x cantitate diferit de valoare**, ceea ce se vede pe hartie.
+- **Exista deja azi calea care demonstreaza gaura:** editarea `vdiscountftva` in grid, pe factura in
+ valuta, **nu declanseaza recalculul** agregatelor (`discount_verificare2.md`, punctul 3).
+- **Calculul e deja generic si refolosibil**, nu trebuie rescris: `do_calculeaza_discount`
+ (`ofacturare.vc2:1874-1976`) plus `calculeaza_totaluri()` (`oproceduri_facturare.prg:2258-2381`),
+ care ruleaza pe `Scatter Name`, **fara dialog**.
+- **Evenimentul recomandat pe coloanele noi e `Text1.LostFocus`**, nu `InteractiveChange` sau `Valid` —
+ tiparul e deja folosit in acelasi fisier, pe `frm_avizare_lucrare.grd_articole.cCantitate` /
+ `cPret` (`:6549-6562`).
+- **Punctul deschis din S1 e inchis in trecere:** `_checkbox1` si `chkDetaliat` sunt **doua controale
+ distincte** in `frm_alte_date`, nu o duplicare — subiectul nu are legatura cu S4c.
+
+*Gata cand:* tastarea in oricare din cele doua coloane produce aceleasi valori in `crsfactura` ca
+dialogul de azi, pe ambele monede; totalurile se refac imediat; discountul venit din politica de pret
+se comporta ca azi; **si `valdiminuatftva` / `valdiminuatctva` se recalculeaza la fiecare editare**,
+astfel incat pe factura tiparita `pret x cantitate` sa dea exact valoarea — verificat prin retiparire
+si prin XML-ul de eFactura, nu doar pe ecran. Pasii cu criterii verificabile sunt la sectiunea 7 a
+raportului; ce nu se poate testa headless, la sectiunea 9.
+*Depinde de:* S4.
+
+#### S4d — Data cursului valutar, numai cand are sens
+Decizia 15, proiectata in M. Campul apare cand tipul nu e retur **si** (documentul e in valuta **sau**
+a intrat pe grid macar un articol cu pret in valuta) — evaluat reactiv, ceea ce devine posibil abia
+in formularul unificat.
+**VERIFICAT — S4d e deblocata.** Raport: `docs\cercetare\zi_curs_validare.md`. Ascunderea selectorului
+**nu** poate lasa documentul fara curs, cu o conditie deja indeplinita de cod:
+
+- **Implicitul exista si e neconditionat.** `poDate.zi_curs` primeste data documentului chiar in
+ `oDateFactura.Init` / `Reset` (`COMUN\programe\ofacturare_comun.prg:247`, `:496`), **inainte** ca
+ formularul sa decida ce ascunde. **Nicaieri codul nu goleste `zi_curs` cand controlul e ascuns.**
+ Deci „valoarea implicita ramane" nu e ceva de construit — e comportamentul actual, de **nestricat**.
+- **Precedentul cerut exista deja**, in alt formular: `frm_date_factura`, tipurile 8 / 9 (retur), unde
+ `clb_zi_curs` se elimina **neconditionat** si documentul se salveaza corect — in principal pentru ca
+ `cursor_retur` nici nu foloseste `poDate.zi_curs`.
+- **Linia `:8076` nu e in formularul de factura.** Apartine lui `frm_date_aviz_lucrare`
+ (`inainte_de_do_termin`, `ofacturare.vc2:8054-8119`), un formular restrans pentru **aviz pe lucrare /
+ aviz pe NIR** (tipurile 27 si 30), care nici nu are control de valuta. Valideaza `zi_curs` pentru ca
+ tipul 27 are nevoie de curs pentru articolele din comanda, **independent de `poDate.in_valuta`** —
+ deci nu e o inconsecventa de reparat orbeste, are un motiv. Se aliniaza doar daca formularul unificat
+ preia si tipurile 27 / 30.
+
+**Riscul real e in alta parte, si nu tine de vizibilitatea campului:**
+`pack_facturare.verifica_cursuri_valute` (chemata din `cursor_preturi`) ruleaza **neconditionat de
+`in_valuta`** si exclude doar moneda nationala. Deci un `zi_curs` implicit (azi) fara curs setat in
+`CURS` pentru o valuta prezenta in listele de preturi ale utilizatorului **poate pica oricum**
+(`-20005`, „Nu este setat cursul…"), indiferent daca selectorul e vizibil sau nu. **Ascunderea nu
+introduce riscul asta si nici nu-l rezolva** — dar il face mai greu de inteles pentru operator, care nu
+mai vede campul din cauza caruia primeste eroarea. De tratat in mesajul de eroare, nu in vizibilitate.
+
+**PROIECTAT (runda 12) — `docs\cercetare\s4d_zi_curs_reactiv.md`.** Nu se inventeaza nimic; se
+reevalueaza vizibilitatea unui control care exista deja.
+
+- **Cheia reactivitatii e un camp deja prezent in cursorul gridului: `crsfactura.tip_valuta`**,
+ interogabil cu **exact tiparul deja folosit in cod** (`ofacturare.prg:1656`, `:1730`:
+ `Select Distinct ... From crsfactura Where tip_valuta = 1`). Nu e nevoie de o structura noua.
+- **Prototipul are deja `Clb_zi_curs` propriu, editabil, legat la `poDate.zi_curs`**
+ (`ofacturare.vc2:16285-16305`) — se schimba doar **cand** e vizibil.
+- **Mesajul `-20005` contine DEJA data si numele valutei lipsa** (`STRINGAGG` peste toate valutele fara
+ curs) — deci partea de „sa spuna care valuta si ce zi" nu e de construit. **Decizia 42 nu schimba
+ continutul mesajului, ii schimba domeniul**: il restrange la valuta articolului cautat, dar **numai pe
+ varianta filtrata** (S4 punctul 1); pe caile cu document sursa incarcarea in masa ramane
+ neconditionata, deci acolo eroarea poate inca numi o valuta straina de documentul curent.
+- **Ce lipseste cu adevarat, si intra ca pas de implementare, nu ca optiune:** sectiunea M cere ca la
+ aceasta eroare campul sa **revina vizibil** — altfel operatorul primeste o eroare despre un camp pe
+ care nu-l vede.
+- **#16 nu e in perimetrul S4d.** E legat de S2 (bucla de reincercare din `ofacturare.prg`), cu verdict
+ separat in `s3_portare_antet.md`. S4d doar **confirma** ca antetul persistent ii inlatura mecanismul,
+ cu conditia ca S2/S3 sa nu recreeze formularul la eroare.
+- ~~**De confirmat cu Marius (mic, de UX):** ce se intampla cand se sterge **ultimul** articol in
+ valuta?~~ **INCHIS — decizia 47 (Marius, runda 13): simetrie.** Campul **se ascunde la loc** cand
+ dispare ultimul articol in valuta, pe tiparul `lb_cursuri`. „Clipitul" la adaugari/stergeri repetate
+ e acceptat ca pret al unei reguli unice: aparitia si disparitia urmeaza aceeasi conditie, nu doua.
+
+*Gata cand:* o factura in lei fara articole in valuta nu arata campul si se emite corect; aceeasi
+factura, dupa adaugarea unui articol cu pret in valuta, arata campul cu data implicita completata;
+factura in valuta se comporta ca azi; iar la `-20005` **campul redevine vizibil**, cu mesajul de azi
+(care deja numeste valuta si ziua). Pasii cu criterii verificabile sunt la sectiunea 7 a raportului; ce
+nu se poate testa headless, la sectiunea 9.
+*Depinde de:* S4. **#16 se urmareste in S2/S3, nu aici** — vezi M.
+
+#### S4e — Lista de preturi disponibila si pe factura din comanda
+Decizia 16, proiectata in J. Singurul gol real: pe contract merge deja, pe comanda nu, pentru ca
+`cursor_comanda` umple `crsarticole` doar cu articolele comenzii. Se adauga lista de preturi peste
+cursorul sursei, exact ca la copiere (`ofacturare.prg:454-473`), si optiunea „Cauta in lista de
+preturi…” intra in meniu pe toate sursele.
+**Si stergerea intra aici**, nu doar adaugarea: cazul cerut e „clientul mai vrea ceva sau vrea sa
+schimbe”, deci o linie adaugata trebuie sa poata fi si scoasa.
+**DECIS (decizia 29): stergerea unei linii venite din comanda ramane fara protectie.** Se sterge ca
+oricare alta; comanda ramane cu cantitatea nefacturata si va aparea **facturata partial**, ceea ce e
+si starea corecta. Nu se cere confirmare, nu se marcheaza „refuzat", nu se ajusteaza numararea
+acoperirii.
+Ramane un singur efect lateral de tratat, si e pe **adaugare**, nu pe stergere: capul de coloana
+„Cantitate comandata” si mesajul „A fost facturata intreaga cantitate comandata”
+(`ofacturare.vc2:15144-15150`) nu sunt adevarate pentru liniile libere adaugate langa cele din
+comanda.
+**PROIECTAT (runda 12) — `docs\cercetare\s4e_lista_preturi_pe_sursa.md`. Reteta din decizia 16 NU se
+generalizeaza literal** — si asta e rezultatul principal al proiectarii.
+
+- **`APPEND FROM` peste cursorul sursei ar strica doua lucruri pe comanda**, ambele tacut:
+ **(1)** `id_c` e `ROWNUM` per executie Oracle, deci randurile din lista de preturi ar **coliziona** cu
+ cele ale comenzii, iar `do_sterge` ajusteaza cantitatea `For id_c = poArticol.id_c` (`:14652-14655`) —
+ ar atinge randul gresit; **(2)** `do_scrie_factura` face `Sum(cantitate)` peste `crsarticole` pe exact
+ aceste tipuri (`:14332-14338`), iar in `cursor_preturi` **`cantitate` inseamna STOC**, nu „ramas de
+ facturat" — suma care decide inchiderea comenzii ar fi poluata.
+- **De ce merge totusi pe contract azi**, verificat: lista de preturi si articolele contractului sunt
+ **doua cursoare separate** de la bun inceput (`crsarticole` / `crsarticole1`), iar `cursor_contract`
+ emite `id_c` ca **`rownum - 10000`** (`PACK_FACTURARE:2722` — confirmat direct pe export de sesiunea
+ principala), adica autorii au tratat coliziunea de `id_c` ca risc real. In plus, tipurile de contract
+ **nu au deloc** ramura cu `Sum(cantitate)` in `do_scrie_factura` — cad pe `Otherwise`. Nu e un tipar
+ de copiat, e o coincidenta favorabila.
+- **Solutia curata, verificata fezabila pe cod: liniile libere NU intra deloc in `crsarticole`.** Se
+ adauga direct in `crsfactura` prin `APPEND BLANK` + `combosql` — tipar **deja existent** in
+ `frm_facturare_articole2.do_adauga` si pe linia de discount (`ofacturare.vc2:14531`). Atunci `id_c`
+ ramane `0` implicit, si **`do_sterge` devine no-op prin constructie**, fara nicio modificare de cod.
+- **Se aplica identic pe AVIZE (tip 4), nu doar pe comanda** — `cursor_avize` are aceeasi semantica
+ „ramas de facturat" si aceeasi ramura de `Sum`. Titlul povestii spune „din comanda", perimetrul real
+ e „orice sursa cu registru".
+- **Avertisment care traverseaza in S4f:** pe returul ca document (`8,9,24`) riscul de coliziune `id_c`
+ **ramane** (`do_sterge` ajusteaza cu semn opus, urmarind maximul returnabil), desi **fara** poluarea
+ sumei de inchidere. Deci S4f foloseste acelasi mecanism, nu `APPEND FROM`.
+- **Validarea de cantitate pe liniile din comanda e satisfacuta prin constructie** — drumul
+ `do_adauga_articol` → `do_verifica_articol` nu e atins, fiindca liniile libere nu modifica `crsarticole`.
+- **Gol real ramas, neacoperit de S4 si S4b:** nu exista mecanism de validare a cantitatii/stocului
+ pentru un rand ales prin `combosql` — ambele rapoarte se opresc la maparea campurilor. `do_verifica_articol`
+ nu se poate refolosi ca atare (cere un `poArticol` scatter-uit dintr-un cursor sursa incarcat).
+ **DECIS — decizia 44 (Marius, runda 13): `poArticol` devine parametru explicit.** Se pastreaza un
+ **singur loc de validare**: `do_verifica_articol` primeste `poArticol` ca **parametru**, in loc sa
+ citeasca variabila `Private` populata de apelant. Schimbarea de contract a metodei e **aprobata ca
+ atare**; consecinta obligatorie e actualizarea **tuturor apelantilor existenti**, inventariati inainte
+ de prima editare. Aceeasi decizie acopera si `do_alege_stoc` / `frm_articol_gest_factura` din S4f (R7)
+ — o singura solutie pentru amandoua, cum cerea raportul.
+
+*Gata cand:* pe o factura la comanda **si pe una din avize** se poate adauga un articol care nu e in
+sursa, cu pretul din lista de preturi, si se poate sterge o linie adaugata, fara ca liniile din sursa
+sa-si piarda validarea de cantitate **si fara ca suma care decide inchiderea automata sa se schimbe** —
+proba directa: aceeasi comanda, cu si fara linii libere adaugate, produce acelasi rezultat de inchidere.
+*Depinde de:* S2. **Interactioneaza cu S4 punctul 2** (registrul) si **avertizeaza S4f**.
+
+#### S4f — Returul in formularul unificat
+Decizia 17, proiectata in N. **Partea grea nu e ce credeam.** Factura de retur ca document (tipurile
+8, 9, 24) functioneaza deja cap-coada: alegere multipla a facturilor sursa, populare din
+`cursor_retur`, gestiune si pret de achizitie mostenite din liniile originale, stergere si retur
+partial. Munca e:
+
+1. **mutarea lui N.1 ca sursa in meniul de adaugare**, fara sa se atinga popularea — acelasi dialog,
+ aceleasi filtre, acelasi `cursor_retur`;
+2. **ridicarea lui N.2 (`But_retur`) la nivel de document**, dupa modelul lui N.1, cu calea
+ per-articol pastrata;
+3. **lista de preturi pe documentele de retur**, prin acelasi `APPEND FROM` ca la S4e.
+
+Nu se ating: excluderea returului dintr-un retur, filtrarea pe client si valuta, maximul returnabil
+calculat pe server, mostenirea gestiunii si a pretului de achizitie.
+**DECIS (decizia 22):** linia de retur care nu vine din nicio factura originala **e permisa**, ca pe
+orice alt document. Deci punctul 3 nu mai are conditie de intrare. Ce trebuie proiectat in schimb, pe
+liniile libere: gestiunea si pretul de achizitie **se aleg** (ca la N.2), nu se mostenesc, iar maximul
+returnabil calculat pe server **nu se aplica** — nu exista cantitate originala.
+**Afisarea provenientei — VERIFICAT, si raspunsul e „nu la nivel de linie".** Raport:
+`docs\cercetare\legatura_linie_retur.md`. Deci **S4f se livreaza fara coloana de provenienta pe linie**;
+nu se inventeaza. Ce s-a stabilit, ca sa nu se reia:
+
+- **Legatura se pierde chiar in cursorul care aduce datele.** `cursor_retur_document`
+ (`ff_...:3949-4062`) foloseste `V_LISTAID` **doar ca filtru** (`WHERE A1.ID_VANZARE IN (...)`,
+ `:4054-4055`); in lista de coloane a `SELECT`-ului extern (`:3965-4028`) **nu apar nici
+ `ID_VANZARE`, nici `ID_VANZARE_DET`**. `crsarticole` nu are de unde sti din ce factura vine randul.
+- **`INSERT`-ul in `VANZARI_DETALII` nu are nicio coloana de sursa.**
+- **Exista insa o legatura la nivel de DOCUMENT, si nu era cunoscuta in plan: `VANZARI_CORESP`.**
+ `scrie_corespondente_vanzari(3)` (`ff_...:14834-14836`, din `finalizeaza_factura`) scrie
+ `(ID_VANZARE_FACT = documentul de retur, ID_VANZARE_AVIZ = fiecare factura sursa, TIP = 3)`
+ (`:15481-15516`) — **cate un rand per factura sursa aleasa**, nu per linie. Numele coloanei e generic,
+ reutilizat si pentru perechi aviz-factura (`TIP = 1/2`).
+- **Consecinta pentru UI:** cand s-a ales **o singura** factura sursa, se poate afisa corect „documentul
+ asta de retur provine din factura Y" — la nivel de antet, nu de linie. Cand s-au ales **mai multe**
+ (selectie multipla, suportata explicit de dialog), `VANZARI_CORESP` da **multimea** de facturi
+ posibile, deci nici macar antetul nu poate arata o sursa unica. **De asezat in UI ca informatie de
+ document, niciodata ca proprietate de linie.**
+- **N.2 (`But_retur`) nu scrie nicio legatura.** `listaid` (perechi `ID_ARTICOL:ID_VANZARE`) e folosit
+ in `pack_facturare` (`ff_...:8142-8212`) exclusiv ca filtru pe `RUL`, ca sa calculeze cantitatea inca
+ disponibila din acea vanzare. Sursa nu ramane atribut al liniei noi.
+**PROIECTAT (runda 12) — `docs\cercetare\s4f_retur_formular_unificat.md`**, cu **trei corectii** fata de
+textul de mai sus:
+
+- **Punctul 1 se restrange.** Alegerea facturilor sursa **nu se muta** in bara de butoane — ramane la
+ antet / in sectiunea pliata (confirmat impotriva `s4b_bara_butoane_meniu.md` §9.3 si a tabelului de
+ meniu de acolo). Ce se muta in meniul de adaugare e doar **„adauga tot din facturile alese"** si
+ **„alege liniile"**.
+- **Un risc concret, netratat nicaieri pana acum (R1):** `frm_articol_gest_factura`
+ (`ofacturare.vc2:4094-4103`) face, sub `If Thisform.lRetur`, `poArticol.pretftva = pretv` — adica
+ **suprascrie pretul de vanzare cu pretul din stoc pe ORICE linie de retur** (verificat direct de
+ sesiunea principala). Corect pentru liniile **mostenite** dintr-o factura sursa; **gresit pentru
+ liniile libere** permise de decizia 22, care trebuie sa pastreze pretul din lista de preturi.
+ Raportul propune fixul.
+- **Distinctia „linie libera" vs. „linie mostenita" nu cere camp nou: `crsfactura.id_c = 0`.** Oracle nu
+ produce niciodata `id_c = 0` din `ROWNUM`, deci valoarea implicita e ea insasi semnalul. Vine din
+ mecanismul impus de S4e: liniile libere intra direct in `crsfactura` (`APPEND BLANK` + `combosql`),
+ **nu** in `crsarticole` — asa ca ajustarea din `do_sterge` (care pe retur urmareste maximul returnabil)
+ devine **no-op prin constructie**. Acelasi semnal dezactiveaza si suprascrierea de pret de mai sus.
+- **Gol nou (R7), pe care S4e nu-l are** (comanda si avizele n-au dialog de gestiune): azi se intra in
+ `do_alege_stoc` / `frm_articol_gest_factura` **doar** dintr-un `poArticol` scatter-uit din
+ `crsarticole`. O linie libera din `crsfactura` nu are asa ceva, iar decizia 22 cere ca gestiunea **sa
+ se aleaga**. Deci trebuie un **punct de intrare nou** in dialog. **Se unifica cu golul echivalent din
+ S4e** (validarea cantitatii, `do_verifica_articol`): e aceeasi problema structurala — dialogurile sunt
+ cuplate de `crsarticole` —, deci merita **o singura solutie**, nu doua.
+ **INCHIS prin decizia 44** (runda 13): `poArticol` devine **parametru explicit** si aici, nu variabila
+ `Private` populata de apelant — aceeasi solutie ca in S4e, cum cerea raportul.
+- **R4 e inchis** (verificare independenta): `scrie_corespondente_vanzari(3)` e gatata pe `ntip IN (8,9)`,
+ nu pe `listaid`.
+- **`VANZARI_CORESP` nu e afectata de liniile libere** — se scrie din `poDate.listaid`, fixat la antet.
+ **De confirmat (R4):** pentru `But_retur` ridicat la nivel de document, raspunsul pare a fi „fara
+ corespondenta persistata", pentru ca scrierea e gatata pe `ntip IN (8,9)`, nu pe `listaid`.
+
+*Gata cand:* un document de retur deschis in formularul unificat aduce liniile facturilor alese cu
+aceleasi valori ca azi — inclusiv gestiunea si pretul de achizitie —, permite stergere si cantitate
+partiala, iar pe o factura normala se poate face retur alegand facturile o singura data. **In plus: o
+linie libera pe un document de retur isi pastreaza pretul din lista de preturi**, adica nu trece prin
+suprascrierea de la `:4094-4103`. Pasii cu criterii verificabile sunt la sectiunea 9 a raportului; ce nu
+se poate testa headless, la sectiunea 11; riscurile R1-R6, la sectiunea 12.
+*Depinde de:* S2, S4e.
+
+#### S4g — Adaugarea de articole la modificarea oricarui document, inclusiv auto
+Decizia 18, proiectata in O si O-bis. **Nu se porneste de la zero:** „Alte servicii” din ROAAUTO
+face deja jumatate — articole reale langa linii sintetice, cu pret tastat, fara gestiune — doar ca
+traieste in formularul de emitere si moare odata cu el. Se generalizeaza in formularul unificat, ca
+a doua sursa din meniu („Alege din nomenclator…”), disponibila **si la modificare**, pe orice tip de
+document, nu doar pe cele auto.
+**Ordinea in care se lucreaza**, ca sa nu se blocheze tot: intai pe documentele ROAFACTURARE, unde
+scrierea e a noastra; abia apoi pe `tip = -12`.
+**Decizia 20 se aplica aici:** din nomenclator se ofera **si articole gestionabile, si
+negestionabile** — nu se copiaza filtrul `in_stoc = 0` al lui ROAAUTO.
+**Blocantul real e contul de venit, si el priveste doar ramura „Alege din nomenclator…”** (J-bis,
+J-ter). Contul de venit vine din `NOTE_CONTABILE.SCC` **prin politica de pret**; un articol fara
+`ID_POL` nu ajunge la cont gol, ci **la eroare** — `contabilizeaza_articol` ridica `FACT-024` si
+opreste tranzactia. Pe ramura „Cauta in lista de preturi…” nu se schimba nimic: acolo politica exista.
+**Premisa de la care pornea povestea asta a cazut:** „Alte servicii” din ROAAUTO **nu face deja
+jumatate** din treaba — acele linii ocolesc complet `contabilizeaza_articol`, printr-o cale de
+facturare paralela care nu genereaza nota de venit. Nu e un mecanism de generalizat, e o exceptie.
+**DECIS (decizia 27, care inlocuieste 24):** contul de venit se **deriva**, nu se ia prin politica —
+din `CORESP_CONT_VENCHELT` pentru articolele gestionabile (pe contul de gestiune al liniei), din
+`NOM_ARTICOLE.CONT` daca e 6xx / 7xx pentru cele negestionabile, altfel **704**. **Derivarea se face
+in VFP**, dar **transportul s-a schimbat la decizia 34**: contul calculat se trimite **direct, ca
+parametru nou al lui `contabilizeaza_articol`**. Ocolul prin `id_pol` cu nota potrivita — politica
+tehnica, interogarea inversa pe `SCC`, `pack_preturi.adauga_politica_pret_art` — e **abandonat**;
+J-quater punctul 3 se citeste doar ca trasabilitate. **Decizia 35** adauga ca acelasi drum serveste si
+editarea prin regenerare, deci nu se proiecteaza aici o a doua ruta de contare.
+~~**De decis in aceasta poveste, nu inainte:** ce se intampla cand linia are **si** politica, **si**
+cont trimis din VFP — cine castiga.~~ **PROIECTAT (runda 13) —
+`docs\cercetare\s4g_adaugare_articole_modificare.md`.** Intrebarile despre politica tehnica in ecranul
+de cautare a politicilor **au disparut** odata cu reteta.
+
+**Raspunsul: niciuna dintre cele trei variante pure — parametrul castiga, dar combinatia ambigua e
+oprita explicit, nu rezolvata tacit.**
+- **Combinatia nu poate aparea in fluxul normal, si asta e dovedit, nu presupus.** `crsfactura.id_pol`
+ e `N(20) Null` (`COMUN\programe\ofacturare_comun.prg`, `creeaza_facturacrs` — **verificat direct**),
+ deci la `APPEND BLANK` ramane `.NULL.`, si ajunge la Oracle ca literalul `NULL`
+ (`ofacturare.vc2:14072`). Cursorul de cautare din nomenclator **n-are deloc coloana `id_pol`**, deci
+ nu exista punct in care o linie „din nomenclator" sa-l poata popula.
+- **Singurul scenariu real de ambiguitate e regenerarea** (decizia 35): daca derivarea contului ar rula
+ **necondiționat** pe toate liniile documentului, si nu doar pe cele fara `id_pol`, o linie cu politica
+ reala ar primi si cont derivat. **E un risc de implementare VFP, nu Oracle** — dar proiectarea Oracle
+ nu trebuie sa-l faca invizibil.
+- **Deci: `cont_venit IS NOT NULL` intra pe ramura noua; daca in acel moment `id_pol` e si el populat,
+ se ridica eroare** (cod nou, distinct de `FACT-024`, care ramane pentru cazul „nici politica, nici
+ cont"). Variantele „politica castiga" si „fallback la `NO_DATA_FOUND`" au fost respinse motivat:
+ prima defineste castigatorul pe **prezenta** campului, nu pe rezolvarea lui, si ar reintroduce
+ `FACT-024` acolo unde VFP a oferit deja o solutie; a doua e semantic cea mai curata, dar cere
+ **restructurarea interna** a functiei (un flag propagat din `EXCEPTION` pana la punctul de decizie),
+ fata de un singur `IF` la intrarea in ramura deja proiectata. **Ambele ascund o eroare de date in loc
+ s-o semnaleze.**
+- **Regresie zero pe apelantii de azi**, prin constructie: cand `cont_venit` e `NULL` — adica toti
+ apelantii existenti, care nu cunosc parametrul —, executia intra direct pe `ELSE`, garda nu se
+ evalueaza niciodata, comportamentul e identic cu cel de azi.
+- **De ales de Marius:** numarul concret al codului de eroare nou (`FACT-0xx`).
+Separat, contul de **gestiune** e rezolvat ca regula (decizia 21): fallback, nu `NULL`, nu refuz.
+**`pack_auto` nu mai e blocant** — `PACK_AUTO` nu citeste `VANZARI` / `VANZARI_DETALII` deloc (O,
+intrebarea 1). Desincronizarea de afisare e **acceptata** (decizia 28); conditia e MANOPERA si
+MATERIALE conform devizului.
+**Blocantul netehnic a cazut si el:** gridul read-only din `frm_modific2024` e al lui #6, dar #13
+incepe dupa ce #6 se termina (decizia 30).
+**Restul proiectarii S4g, pe scurt** (detaliile in raport):
+- **Suprafata pe Oracle**: `contabilizeaza_articol` primeste contul prin `VANZARI_DETALII_TEMP%ROWTYPE`
+ (`cont_venit`), deci semnatura functiei ramane aceeasi — se extinde **tipul de rand**. Consecinta de
+ livrare: **DB inainte de EXE**.
+- **Derivarea in VFP** urmeaza fix decizia 27: `CORESP_CONT_VENCHELT` pentru gestionabile (pe contul de
+ gestiune al liniei), `NOM_ARTICOLE.CONT` daca e 6xx/7xx pentru negestionabile, altfel **704**. Ruleaza
+ **doar pe liniile fara `id_pol`** — vezi garda de mai sus; aici se leaga cele doua.
+- **Fluxul in formular** refoloseste exact mecanismul lui S4e: linia „din nomenclator" intra prin
+ `APPEND BLANK` + `combosql` **direct in `crsfactura`**, niciodata in `crsarticole`.
+- **Ramane deschis, mostenit din S4e:** validarea de cantitate/stoc pentru linia libera — se rezolva
+ prin decizia 44 (`poArticol` ca parametru explicit), aceeasi solutie pe ambele surse.
+- **De re-rulat inainte de implementare, nu de presupus incheiat:** cautarea apelantilor lui
+ `adauga_articol_factura` in restul suitei (ROAGEST, ROAAUTO, ROAACNPRO, ROAIMOB). Risc asteptat zero
+ — folosesc proceduri separate sau alt pachet —, dar cautarea **nu s-a terminat in nicio runda**.
+- **Trei hardcodari raman de confirmat de Marius, nu de presupus inofensive:** `CU_TVA = 1` (are efect
+ masurat prin `nproc_tva_max`, pe linie scutita + discount global), numele cheii de optiune de firma
+ pentru `SCD` (decizia 36) si domeniul ei `PROGRAME`, si trasabilitatea `CONT_VENIT` pe
+ `VANZARI_DETALII` (optionala pentru functionare, dar fara ea coloana nu se pastreaza dupa fapt).
+
+**Nota de executie (decizia 60):** pe documentele de tip **48/49** (custodie), „Alege din
+nomenclator…" ramane restrans la articole `IN_STOC = 0`, la fel ca ramura „Cauta in lista de
+preturi…" (S4) — decizia 20 (si articole gestionabile, si negestionabile) **nu se aplica** pe
+tipurile 48/49. Altfel se rupe invariantul pe care se sprijina siguranta regenerarii la editarea
+custodiei (decizia 60, `docs\cercetare\custodie_48_49_stergere_reemitere.md`).
+
+*Gata cand:* pe un document deja emis se poate adauga o linie noua, din lista de preturi sau din
+nomenclator, si documentul se salveaza consistent — pe fluxurile ROAFACTURARE, cu partea auto
+livrata separat, dupa (1). Pe un document 48/49, „Alege din nomenclator…" nu ofera si nu permite
+adaugarea unui articol cu `IN_STOC <> 0`.
+*Depinde de:* S4e, si de deciziile de mai sus. **Nu blocheaza etapa I.**
+
+#### S5 — Acoperirea tuturor tipurilor
+`frm_facturare_articole.Init` are 20 de ramuri pe `poDate.tip` (`:15107-15250`) care schimba titlul,
+capul coloanei de cantitate, mesajul de stoc, vizibilitatea discountului, prezenta seriei. Toate
+trebuie sa existe si in formularul unificat. Tipurile speciale raman pe calea lor:
+`tip = 27` (`frm_avizare_lucrare`), `tip = 30` (aviz din NIR, formular nevizibil).
+**PROIECTAT (runda 12) — `docs\cercetare\s5_acoperire_tipuri.md`. Povestea e mult mai mare decat
+„porteaza cele 20 de ramuri", si motivul e ca baza de pornire aleasa nu are aproape nimic de portat.**
+
+- **`Do Case`-ul de azi acopera 21 de valori de `tip`** (in 14 ramuri). **Patru tipuri reale,
+ reachable prin `factureaza()`, nu intra in niciun `Case`: `45` (factura restaurant), `48` / `49`
+ (custodie), `52` (contract, factura fiscala valuta)** — pierd titlu, cap de coloana, mesaj de stoc,
+ vizibilitatea discountului si eliminarea coloanei `cSerie`. **Nu doar `52`**, cum semnalase S4b.
+ Rutarea cursorului le recunoaste (`ofacturare.prg:271-282`); doar `Init` nu le-a „prins" niciodata.
+ **Nota de executie (decizia 60):** randul de configurare pentru `48`/`49` trebuie sa pastreze
+ restrictia la articole `IN_STOC = 0` mostenita de la sursa lor de azi (`cursor_articole_k`,
+ `PACK:3595-3701`, `:3695`) — vezi notele echivalente la S4 si S4g; e conditia de siguranta pentru
+ regenerarea la editarea custodiei (decizia 60,
+ `docs\cercetare\custodie_48_49_stergere_reemitere.md`).
+- **Cinci tipuri (`43,44,46,50,51`) nu ajung deloc la acest formular** — zero potriviri in tot arborele
+ `D:\ROA`. `50` e marcat „in lucru" in sursa. Se declara explicit ramase in afara.
+- **Descoperirea care schimba estimarea: prototipul nu e o versiune partiala a `Do Case`-ului — e
+ aproape gol.** `frm_facturare_articole2.Init` (`:18988-19080`) alege pe tip **doar** cuvantul
+ „factura"/„aviz", pe o lista mai scurta (lipseste `24`). Nu seteaza titlu (nu exista
+ `lb_titlu_alb_b121` in tot prototipul), nu schimba capul coloanei, nu schimba mesajul de stoc, nu
+ ascunde discountul, si **n-are deloc conceptul de coloana `cSerie`**. Daca formularul unificat porneste
+ de la prototip — cum decide S1 —, **toata diferentierea pe tip se reconstruieste de la zero**, nu se
+ completeaza. Asta e cel mai mare cost ascuns al etapei I descoperit pana acum.
+- **Rutarea cursorului diverge pe TREI tipuri, nu unul:** pe prototip, ramura de contract e
+ `Inlist(tnTip, 2, 26, 6)` (`ofacturare.prg:762`) fata de `Inlist(tnTip, 2, 26, 6, 52)` pe standard
+ (`:283`) — **verificat direct de sesiunea principala** —, iar ramura de retur omite `24`. Pe aceste
+ tipuri, prin prototip, `lcSqlCursor` ar ramane **nedefinit**: eroare, nu doar comportament diferit.
+- **Punctul lasat deschis de S4 punctul 2 se inchide aici:** tipurile **`26` si `52` n-au niciun
+ bookkeeping** `crsarticole` — nici Rol A, nici Rol B. Excluderea e totala, pe `Do Case` exhaustiv fara
+ ramura implicita, deci e „dovedit absent", nu „neconfirmat".
+- **`30` nu e un formular separat**, cum spunea planul: e **acelasi `frm_facturare_articole`**, trecut
+ prin acelasi `Init`, dar niciodata aratat (`ofacturare.prg:444-453` — calculeaza totalurile, apasa
+ programatic `but_termin1.Click()`, apoi `Release()`, fara `Show()`). Deci **e afectat de golurile din
+ `Do Case`** ca oricare alt tip; doar ca defectele nu se vad pe ecran. `27` chiar ramane pe calea lui.
+- **Alegerea de proiectare centrala, recomandata: tabel de configurare per tip**, un rand per `tip`, cu
+ exact proprietatile pe care le seteaza azi `Do Case`-ul (titlu, cap cantitate, mesaj stoc, discount
+ vizibil, are serie, tip doc, butoane, grup-sursa pentru meniul S4b). Motivul nu e estetic: **un
+ `Do Case` fara `Otherwise` nu semnaleaza niciodata un tip lipsa** — exact mecanismul care a lasat
+ patru tipuri pierdute ani la rand. Cu tabel, un tip necunoscut devine **eroare la deschidere**, iar
+ completitudinea se verifica **mecanic**, cu un `SELECT` fata de `tipuri_documente_facturare.md`, fara
+ sa porneasca formularul. Variantele „completeaza `Do Case`-ul" si „metoda per grup" au fost respinse
+ motivat: amandoua raman implicite, deci nu adauga detectie.
+- **DECIS — decizia 48 (Marius, runda 13): tabelul e un CURSOR GENERAT IN COD la pornire**, nu `DBF`
+ static (recomandarea raportului) si nu tabela pe Oracle. Ambele au fost puse pe masa cu argumentele
+ lor si respinse: `DBF`-ul adauga un fisier de intretinut, de livrat la fiecare update si de tinut
+ sincron intre produsele ROA; tabela Oracle ar cere script de migrare si o citire in plus la
+ deschiderea formularului. **Ce NU se pierde prin alegerea asta:** detectia ramane intacta — tip
+ necunoscut = **eroare la deschidere**, exact castigul pentru care exista propunerea —, iar proba
+ mecanica de completitudine ramane posibila, doar ca ruleaza **din aplicatie**, nu cu un `SELECT`
+ din afara. **Ce se accepta:** orice tip nou de document cere **recompilare si versiune noua de exe**,
+ ca azi. Forma concreta: un `.prg` cu `CREATE CURSOR` + `INSERT`-uri, un rand per tip, incarcat o
+ singura data si citit de `Init` prin `SEEK` pe `tip`.
+
+*Gata cand:* fiecare tip din `COMUN\docs\tipuri_documente_facturare.md` fie e acoperit, fie e
+declarat explicit ramas pe calea veche — **verificat prin proba mecanica de la sectiunea 8 a raportului**,
+nu prin citire. Include cele patru tipuri lipsa azi (`45,48,49,52`) si alinierea rutarii de cursor intre
+standard si prototip. Pe `48`/`49`, in plus: restrictia `IN_STOC = 0` mostenita ramane activa (decizia
+60) — nu se poate adauga un articol gestionabil.
+*Depinde de:* S4.
+
+#### S5b — Proforma si copierea pe formularul unificat
+Deciziile 10 si 11. Amandoua vin **aproape gratuit**, pentru ca folosesc deja acest drum: proforma e
+o valoare in combo-ul de tip document, copierea e `factureaza(tip, toFactura)` cu antetul
+precompletat. De facut, concret:
+- combo-ul `Ct_clb_fdoc` ramane in antetul unificat, cu realocarea de serie si numar la comutare;
+- garzile `eProforma = 0` de pe notele contabile si atasamente raman intacte, iar raportul propriu de
+ proforma continua sa fie ales;
+- copierea deschide formularul in starea „document nou”, cu antetul editabil (comportamentul de azi);
+- **degradarea de tip din `do_copiaza` ramane pentru copiere si nu se aplica la regenerare** (D) —
+ sunt doua moduri distincte ale aceluiasi formular, nu acelasi comportament.
+*Gata cand:* o proforma emisa din formularul unificat nu produce nota contabila si se listeaza pe
+raportul ei; o copie produce un document nou cu numar nou si acelasi continut.
+**VERIFICAT (runda 9) — `docs\cercetare\s5b_proforma_descarcare_gestiune.md`. Verificarea 4 e inchisa.**
+**NU, gestiunea nu se descarca pe proforma** — pentru niciun articol, indiferent daca e gestionabil in
+nomenclator. Si nu e un efect colateral al ascunderii stocului, e **prin design**: VFP marcheaza toate
+liniile proformei negestionabile inainte de compunerea documentului, ceea ce le trimite cu sentinela
+`id_gestiune = -1000`, iar pe Oracle `contabilizeaza_articol` sare apelul catre `descarca_gestiune`
+exact pe acest sentinel. Intentia e explicita in changelog (12.03.2021 / 2.7.x): *„Articolele din
+proforma sunt marcate 'negestionabile', astfel incat nu mai este necesara existenta articolelor in stoc
+pentru a genera proforma."* — deci cerinta a fost „proforma trebuie sa mearga si fara stoc", nu „nu arata
+plafonul". **Se corecteaza presupunerea din plan** ca zeroizarea `gestionabil` ar fi doar cosmetica.
+Consecinta pentru S5b: sentinela `-1000` e contractul care trebuie pastrat — vezi sectiunile 6 si 7 ale
+raportului pentru constrangerile de proiectare si ce lipseste la copiere.
+
+**PROIECTAT (runda 12) — `docs\cercetare\s5b_proiectare_proforma_copiere.md`. „Aproape gratuit" nu mai
+tine: proiectarea a scos la iveala un risc de date care nu era semnalat nicaieri.**
+
+- **Mecanismul real care tine proforma curata nu e sentinela, ci routing-ul.** In `do_scrie_factura`
+ (`ofacturare.vc2:14282-14300`), `eProforma = 1` alege `scrie_proforma`, care **nu cheama niciodata**
+ `contabilizeaza_articol` — comentariul din cod o spune direct: *„salveaza doar in vanzari, nu si in
+ contabilitate"* (verificat de sesiunea principala). Sentinela `-1000` e al doilea strat, nu primul.
+- **RISCUL CENTRAL — „drumul invers", nesemnalat pana acum si cu consecinta pe date.** Operatorul
+ adauga linii cu documentul pe **Proforma** (deci marcate `gestionabil = 0` / `id_gestiune = -1000`),
+ apoi comuta combo-ul inapoi pe **Factura** inainte de „Termina". Atunci routing-ul alege
+ `scrie_factura2`, care **chiar** cheama `contabilizeaza_articol` — dar acesta sare `descarca_gestiune`
+ exact pe sentinela `-1000` (`PACK:7472-7476`). Rezultatul: **o factura reala iese cu stocul
+ nedescarcat, silentios** — `-1000` e o valoare valida, nu ridica nicio exceptie. **Azi nu exista
+ nicio plasa pentru acest caz**, si nici nu putea exista: combo-ul traieste in dialogul separat
+ `frm_date_factura`, inchis **inainte** sa existe vreo linie. Riscul se naste **din unificare**.
+- **De aici si de ce marcarea negestionabila nu mai poate fi un singur `UPDATE` de masa:** in
+ formularul unificat trebuie extrasa intr-o metoda refolosita din **trei** puncte — la incarcare, la
+ adaugarea unei linii, si la comutarea tipului cu linii deja prezente.
+- **`id_c` la copiere: SIGUR, cu dovada.** `do_copiaza` degradeaza tipul spre grupul-tinta
+ **`{1,5,7,10,22,23}`**, care nu intra niciodata in ramurile Rol A din `do_scrie_factura` / `do_sterge`.
+ Coliziunea tehnica exista in date, dar **n-are efect observabil**. (Intrebarea venea din corectia lui
+ S4e — vezi acolo.)
+ > **CORECTIE (runda 13, verificata direct pe cod).** Grupul-tinta scris pana acum in plan
+ > (`{1,5,10,22}`) era **gresit**, si la fel era si `{1,5,7,10}` din raportul S5c. Setul real e cel de
+ > mai sus, citit din primul `CASE` al lui `frm_facturi.do_copiaza`
+ > (`COMUN\clase\ofacturare_comun.vc2:3693-3694`), care lasa neatinse exact `T1,T5,T7,T10,T22,T23`.
+ > Concluzia „copierea e sigura" **nu se schimba** — `7` si `23` nu au bookkeeping Rol A —, dar cifrele
+ > se corecteaza peste tot unde apar. Aceeasi corectie se aplica lui
+ > `s5b_proiectare_proforma_copiere.md` §2.1 / §7.
+- **DEFECT PREEXISTENT, gasit in trecere la verificarea de mai sus — de raportat, NU de reparat acum.**
+ In `frm_facturi.do_copiaza`, ramura de avize scrie `lnTip = T22`
+ (`COMUN\clase\ofacturare_comun.vc2:3703`) in loc de `loFactura.tip = T22` — **singura ramura din tot
+ `Do Case`-ul care nu atribuie in obiect**; toate celelalte cinci scriu `loFactura.tip`. Consecinta:
+ la copierea unui aviz (`21,24,26,30,-7,-9,-10,-13,28,29,42`) **degradarea nu se produce**, iar
+ `copiere_factura` cheama `factureaza(toFactura.Tip, ...)`
+ (`COMUN\programe\oproceduri_facturare.prg:150-152`) cu tipul **original** — deci copia unui „aviz pe
+ baza de comanda" reintra pe ruta de comanda, nu pe cea de lista de preturi. **Verificat ca `factureaza`
+ nu citeste un `lnTip` privat** (`ofacturare.prg:101` declara `lnTipTemp`, nu `lnTip`), deci
+ atribuirea chiar se pierde; in plus `lnTip` e nedeclarat in metoda, deci poate suprascrie un `lnTip`
+ al apelantului. **Fisierul e in perimetrul interzis (#6) — se raporteaza, nu se atinge.**
+
+**VERIFICAT (runda 12, la cererea lui Marius) — `docs\cercetare\verif_proforma_alegere_stoc.md`.
+Pe proforma NU se alege stoc azi, si asta e deliberat.**
+
+- **Un singur mecanism activ, si e in VFP, la incarcare:** `ofacturare.prg:333-336` face
+ `UPDATE (lcCursor) SET gestionabil = 0` cand `eProforma = 1`, **inainte** sa se deschida gridul.
+ Comentariul din cod spune intentia direct: *„Daca este o proforma, consider toate articolele
+ negestionabile, **pentru a nu mai alege din stoc**"* (12.03.2021). Deci `Do Case`-ul de la
+ `ofacturare.vc2:13803` vede mereu `gestionabil = 0` → **`do_alege_stoc` nu ruleaza niciodata**.
+ Valabil pe **toate** cursoarele de creare directa a unei proforme; **niciunul** n-are parametru
+ `V_PROFORMA` (verificat pe ~9 proceduri `cursor_` din pachet).
+- **Mecanismul Oracle exista, dar e mort in fluxul curent:** `cursor_retur_document` (`PACK:3993-4000`)
+ are `CASE V_PROFORMA = 1 THEN 0`, insa se cheama doar la **copiere**, unde `V_PROFORMA` trimis e
+ `eProforma` al documentului **nou** — mereu `0`. **Nu e o contradictie intre rapoarte**: sunt doua
+ mecanisme reale, doar unul activ.
+- **`pret_achizitie` depinde de sursa:** pe calea principala (lista de preturi) ramane `0` —
+ `cursor_preturi` nici nu-l selecteaza. Pe surse care carata un document existent (avize, copiere)
+ vine real din `VANZARI_DETALII.PRET_ACHIZITIE`.
+- **Daca liniile ar pastra gestiunea reala pana la salvare, nu s-ar strica nimic pe contabilizare sau
+ stoc:** `adauga_articol_factura` se cheama oricum si pentru proforma, dar `scrie_proforma` **nu**
+ cheama `contabilizeaza_articol`, deci `descarca_gestiune` tot n-ar rula; iar **`do_alege_stoc` nu
+ rezerva stoc** (doar `SELECT` + scadere locala in memorie, zero scriere Oracle). Singurul loc unde
+ s-ar vedea o diferenta e la **relistare** (`crsDetaliiListare` / `fact_vfacturi2` citesc
+ `id_gestiune` fara filtru pe `eproforma`) — **neconfirmat** daca vreun raport chiar il tipareste.
+
+**Consecinta care schimba forma deciziei: cele doua sensuri nu sunt simetrice.**
+- **FACTURA → PROFORMA cu linii deja adaugate:** liniile au trecut deja prin `do_alege_stoc`, deci au
+ gestiune reala si pret de achizitie corect. **E sigur, si sentinela se poate aplica abia la salvare**
+ — exact varianta ceruta de Marius. **Fara atentionare.**
+- **PROFORMA → FACTURA cu linii deja adaugate:** liniile au fost adaugate **fara** alegere de stoc
+ (`gestionabil` fortat `0`), deci **nu au gestiune**. Aici e riscul „drumului invers".
+- **A forta alegerea stocului si pe proforma NU e o optiune** — ar regresa cerinta din 12.03.2021
+ (*„nu mai este necesara existenta articolelor in stoc pentru a genera proforma"*): un articol fara
+ stoc n-ar mai putea intra pe proforma, pentru ca `do_alege_stoc` ar cere un lot inexistent.
+
+### Decizia 43 (Marius, runda 12) — proforma NU alege stoc, si factura se face DIN proforma
+
+**Pe proforma nu se alege stoc, si asta e cerinta, nu efect colateral.** Motivul, in cuvintele lui
+Marius: *„sa dau o proforma chiar si in absenta stocului, pentru ca ma intereseaza doar pretul de
+vanzare, nu si cel de achizitie din stoc"*. Deci:
+- **Varianta (b) — realegerea gestiunii linie cu linie la comutare — e RESPINSA.** Nu se mai
+ reargumenteaza.
+- **Comutarea PROFORMA → FACTURA cu linii prezente se blocheaza**, cu mesaj explicit. Comportamentul de
+ azi (`gestionabil = 0` fortat la incarcare, `ofacturare.prg:333-336`) se **pastreaza**, nu se rafineaza.
+- **Sensul FACTURA → PROFORMA ramane liber**, fara atentionare, cu sentinela aplicata **la salvare** —
+ liniile au deja gestiune reala, deci nu se pierde nimic.
+
+**Cerinta noua: „ulterior o sa vreau si o factura din proforma".** Nu prin comutarea tipului pe acelasi
+document, ci ca **document nou**, generat din proforma. **Mecanismul pare sa existe deja pe calea de
+copiere** — `cursor_retur_document` reface gestionabilitatea reala cand `V_COPIERE = 1`
+(`GESTIONABIL = B.IN_STOC`, `PACK:3993-4000`), deci liniile venite dintr-o proforma **redevin
+gestionabile**, trec prin `do_alege_stoc` la adaugare, primesc `id_gestiune` real si descarca gestiune
+normal (`docs\cercetare\s5b_proiectare_proforma_copiere.md` §2.6). **De verificat inainte de a te baza
+pe asta**, pentru ca §2.6 descria copierea in general, nu cazul „sursa e o proforma":
+1. poate fi azi o **proforma** aleasa ca sursa de copiere, sau e exclusa undeva?
+2. `do_copiaza` degradeaza tipul spre `{1,5,10,22}` — ce tip rezulta dintr-o proforma si e cel dorit?
+3. ~~se pastreaza legatura proforma → factura?~~ **RASPUNS (Marius, runda 12): DA — „ar fi bine sa aiba
+ urma sursei, la fel ca factura din aviz".** Deci trasabilitatea **e ceruta**, si tiparul de urmat e
+ cel deja existent pentru aviz → factura: `scrie_corespondente_vanzari(1)`, chemata din
+ `finalizeaza_factura`, care scrie in **`VANZARI_CORESP`** perechea
+ `(ID_VANZARE_FACT = factura, ID_VANZARE_AVIZ = documentul sursa, TIP = 1)`. Numele coloanei e generic,
+ deja reutilizat pentru mai multe feluri de perechi (`TIP = 1/2` aviz-factura, `TIP = 3` retur), deci
+ **structura nu se schimba — se adauga o valoare noua de `TIP`** pentru proforma → factura.
+ **De proiectat, nu de presupus:** ce valoare de `TIP` se aloca; de unde stie fluxul de copiere ca
+ sursa a fost o proforma (azi `do_copiaza` degradeaza tipul, deci informatia s-ar putea pierde
+ **inainte** de scriere — vezi punctul 2); si daca `marcheaza_facturat` / `FACTURAT` trebuie sau nu
+ atinse (pe aviz sunt, pe proforma probabil **nu**, pentru ca proforma nu e un document de livrare —
+ **de confirmat, e exact genul de detaliu care se copiaza gresit din tiparul avizului**).
+~~**Aceasta e prima sarcina de proiectare a rundei 13.**~~ **LIVRATA — vezi S5c mai jos.**
+
+*Depinde de:* S5.
+
+#### S5c — Factura din proforma (decizia 43, cerinta noua)
+**PROIECTAT (runda 13) — `docs\cercetare\s5c_factura_din_proforma.md`. Toate cele trei intrebari si
+ambele capcane au raspuns cu dovada. Vestea buna: mecanismul de baza chiar exista, si nu se atinge.**
+
+- **(a) O proforma poate fi azi aleasa ca sursa de copiere, fara nicio excludere.** `IsCopy` returneaza
+ **necondiționat `.T.`** (`COMUN\clase\ofacturare_comun.vc2:4969`, cu comentariul explicit *„POT SA
+ COPIEZ ORICE, TRATEZ TIPURILE IN DO_COPIAZA"*; filtrul vechi pe tip e comentat dedesubt, la `:4971`) —
+ **verificat direct**. Nici vizibilitatea butonului, nici filtrul de grid „Facturi&Avize / Proforme" nu
+ se uita la `eproforma`. Deci nu e nimic de deblocat.
+- **(b) Tipul rezultat e corect, fara schimbare.** Copierea produce un document real
+ (`nIdTipDoc = 5`, `eproforma = 0`) — factura fiscala, exact ce trebuie. Degradarea lasa neatins
+ grupul-tinta **`{1,5,7,10,22,23}`** (vezi corectia de cifre de mai sus).
+- **(c) `TIP = 4` e liber in `VANZARI_CORESP`** si se aloca pentru „factura din proforma". Confirmat
+ **cod + date** pe schema vie: tabela are un **singur scriitor in toata baza**
+ (`pack_facturare.scrie_corespondente_vanzari`), iar azi se folosesc doar `1/2/3`. **Structura nu se
+ schimba.**
+- **Capcana (i) — confirmata, si e miezul poveștii.** `id_vanzare` al proformei **supravietuieste**
+ copierii (prin `poDate.listaid`), dar faptul ca **sursa era o proforma se pierde**:
+ `completeaza_setari_document` copiaza `.listaid`, dar **nu** si `eproforma`
+ (`COMUN\programe\ofacturare_comun.prg:387` — **verificat direct: `eproforma` nu apare nicaieri in tot
+ fisierul**). De aceea legatura **nu se poate agata de `CASE`-ul din `finalizeaza_factura`**, care e
+ cheiat pe `ntip` — `ntip` nu poarta distinctia. Solutia: un semnal nou, client-side
+ (`poDate.lProformaSursa`), capturat exact acolo unde informatia mai exista, plus un **apel Oracle
+ explicit separat** care reutilizeaza `scrie_corespondente_vanzari(4)` **neschimbata**. Zero cod PL/SQL
+ nou pe calea recomandata.
+- **Capcana (ii) — INFIRMATA presupunerea comoda, cu patru argumente: `marcheaza_facturat` NU se cheama
+ pe proforma.** Proforma n-are `VANZARI_CANTITATI`, n-are ramura de reversare la stergere in
+ `sterge_factura`, nimic nu filtreaza dupa `FACTURAT` pe proforme, si oricum calea aleasa e in afara
+ `CASE`-ului care il cupleaza azi. Era exact detaliul care se copia gresit din tiparul avizului.
+
+**Ce NU se schimba:** `IsCopy`, vizibilitatea butonului de copiere, filtrul de grid, degradarea de tip
+din `do_copiaza`, `cursor_retur_document` (`GESTIONABIL = B.IN_STOC`), si `scrie_corespondente_vanzari`
+insasi.
+
+**INCHISE, nu de reintrebat (marcaj pus in runda 17).** Cele cinci puncte de mai jos au primit raspuns: punctul 1 (`TIP = 4`) prin **decizia 51**, restul in bloc prin **decizia 56** („da la toate"). Lista ramane ca **inventar al recomandarilor acceptate**, ca sa se stie ce s-a decis si de ce — nu ca intrebari:
+1. **`TIP = 4`** — liber azi, dar alocarea e **ireversibila in date** odata intrata in productie. De
+ confirmat explicit, nu tacit.
+2. **Apel pe starea de sesiune a pachetului (`clistaid` / `nid_vanzare`) vs. procedura noua cu
+ parametri expliciti.** *Recomandarea raportului:* varianta simpla (zero cod Oracle nou), **cu
+ conditia** verificata la implementare ca niciun apel Oracle intercalat nu reseteaza starea intre
+ scrierea facturii si scrierea corespondentei.
+3. **Aceeasi proforma poate fi copiata de N ori**, fiecare copie cu randul ei `TIP = 4`. E comportamentul
+ implicit al oricarei copieri de azi. *Recomandare:* daca deranjeaza, avertisment — **nu** blocare.
+4. **Garda simetrica la stergere** (*„nu poti sterge o proforma care are deja factura generata din ea"*),
+ pe tiparul `TIP IN (1,2,3)` din `sterge_factura` — de decis daca se doreste.
+5. **Afisarea „provine din proforma X"** pe factura noua — vine gratis din legatura scrisa, la nivel de
+ **document** (ca la retur), nu de linie. De decis daca intra acum sau mai tarziu.
+
+*Gata cand:* dintr-o proforma emisa se genereaza o factura reala, cu numar nou, care descarca gestiunea
+normal, are rand `TIP = 4` in `VANZARI_CORESP` catre proforma sursa, iar proforma **nu** e marcata
+`FACTURAT`.
+*Depinde de:* S5b.
+
+### Decizia 49 (Marius, runda 13) — cele doua formulare merg IN PARALEL, si ALEGE UTILIZATORUL
+
+**Cerinta, in cuvintele lui Marius:** *„utilizatorul sa poata accesa alternativ, daca doreste"*. Deci
+**nu** o setare care ruteaza tacit pe un flux sau altul, si **nu** un pilot pe cativa oameni: ambele
+formulare raman accesibile, iar **alegerea o face omul, in momentul in care factureaza**. Rostul e sa
+existe mereu **un flux despre care se stie ca functioneaza**, cat timp cel nou se stabilizeaza.
+
+> **Corectie a rundei 13:** prima formulare a acestei decizii descria un pilot per utilizator, prin
+> optiunea de firma. **Gresit** — Marius a corectat: optiunea **nu alege**, ci doar **face alegerea
+> disponibila**. Nu se reargumenteaza in varianta veche.
+
+**Mecanismul exista deja in produs si face exact asta**, nu se inventeaza:
+- `factureaza` (`COMUN\programe\ofacturare.prg:87-93`) verifica `gnFacturareNou` si, cand e pornita,
+ **intreaba la fiecare facturare**: `AMESSAGEBOX('Facturare noua (DA) sau standard (NU)?', 4+32, ...)`.
+ Optiunea deschide alegerea; raspunsul il da utilizatorul, de fiecare data.
+- `gnFacturareNou` e o **optiune de firma**: `optiuni_firma` (`COMUN\programe\oinit_optiuni.prg:225-275`)
+ cheama `SCRIE_OPTIUNI(gcUserName)`, parcurge `v_optiuni` si **declara dinamic** globalele publice dupa
+ tip (`Public gn&lcvarname` pentru `NUMERIC`), cu filtru optional pe program
+ (`Isnull(programe) Or gcNumeProgram $ programe`). **Deci se activeaza si se dezactiveaza din date,
+ fara livrare de exe.**
+- **Fluxul vechi ramane intreg:** `factureaza` + `frm_facturare_articole`. S2 sterge doar
+ **`factureaza2`**, un fork mort din 2017 (executia interogarii dezactivata, `lnSucces = 1` hardcodat,
+ zero utilizatori reali) — **nu** calea veche. **S2 nu are voie sa desfiinteze alegerea.**
+- **Pentru etapa II plasa e alta, si exista deja:** editarea prin regenerare e o **actiune noua**, deci
+ „fluxul vechi" pentru ea e **fluxul lui #6**, pe care decizia 38 il pastreaza oricum.
+
+**Cum se prezinta alegerea — de ales la implementare, ambele satisfac cerinta:**
+- **(A) intrebarea de azi**, modal la fiecare facturare. Exista deja, zero cod. Neajuns: intreaba si
+ cand utilizatorul stie de o luna ce vrea.
+- **(B) doua intrari distincte** in meniu / doua butoane („Facturare" si „Facturare (nou)"). Aceeasi
+ libertate, fara modal la fiecare document. **Recomandat.** Se poate porni cu (A), care e gata, si trece
+ la (B).
+
+**Limita, si trebuie spusa explicit ca sa nu creeze o falsa siguranta: alegerea acopera VFP-ul, nu
+Oracle.** Modificarile din pachete — parametrul nou al lui `contabilizeaza_articol` (decizia 34),
+variabila noua din `SET_IDFACT`, si `INSERT` → `MERGE` in `DOCUMENTE` (S9) — sunt **cod comun al
+intregii suite** si se aplica **tuturor deodata**, indiferent pe ce formular alege omul sa lucreze.
+Proiectarea le face **inerte prin constructie** (parametru `NULL` → executie identica cu azi;
+`WHEN MATCHED` care nu se declanseaza pe drumul normal), dar asta e o garantie de regresie zero,
+**nu** o cale de intoarcere. Consecinta practica: pe formular si procedura intoarcerea e imediata; pe
+baza de date, siguranta vine din **testarea unui ciclu normal de scriere in fiecare produs** (deja
+ceruta in S9).
+
+### Decizia 50 (Marius, runda 13) — se editeaza documente curente, nu documente dintr-un lant
+
+**Formularea lui Marius:** *„in principiu nu se poate edita un document pentru care s-a facut retur;
+de principiu se pot modifica documente curente, nu cele care fac parte dintr-un lant"*.
+
+**Deci garda de azi ramane, si devine regula declarata, nu limitare tolerata.** `sterge_factura` arunca
+`ORA-20000` cand documentul are deja facturi / avize de retur emise peste el; S7 **semnaleaza conditia
+inainte de intrarea in formular**, cu mesaj clar, nu ca eroare Oracle la final. Utilizatorul care chiar
+vrea sa editeze sterge intai documentele-copil — comportament existent, nu ceva de construit.
+
+**PRECIZAT de Marius (runda 13), si inchide punctul: „lantul" se citeste IN AMONTE, nu in ambele
+sensuri.** In cuvintele lui: *„daca este generata factura din aviz, avizul nu se mai poate modifica,
+factura da, pentru ca este documentul curent; ma refeream la documentele din lant anterioare"*.
+
+Deci regula, in forma finala:
+- **Documentul care are urmasi se blocheaza** — avizul din care s-a facut factura, factura peste care
+ s-a emis retur. Are deja o reprezentare in cod: garda din `sterge_factura`.
+- **Documentul de la capatul lantului ramane editabil** — el e „documentul curent". **Factura din aviz
+ (`ntip = 4`) ESTE editabila**, chiar daca are parinte.
+- Prin urmare **perimetrul etapei II nu se restrange**, iar intrebarea deschisa din S10 despre `ntip = 4`
+ (aceeasi re-derivare tacuta ca pe contract, dar cu alta sursa de comparat) **ramane in picioare** — nu
+ dispare, cum s-ar fi intamplat la citirea stricta.
+
+**VERIFICAT in runda 14 — si premisa era gresita.** Raport: `docs\cercetare\garda_aviz_facturat.md`.
+Se credea ca garda de azi blocheaza documentul doar cand are **retururi** peste el. **Nu e asa:** a doua
+garda din `sterge_factura` testeaza `TIP IN (1, 2)`, iar **`TIP = 1` este corespondenta aviz → factura
+normala, nu retur** (`EXPORT:5464-5476`, semantica citita ramura cu ramura din `CASE`-ul lui
+`finalizeaza_factura`, `EXPORT:14818-14839`). Formularea gresita venea din citirea comentariului
+`-- verific daca exista facturi sau avize de retur`, in care „de retur" se distribuia si peste „facturi";
+codul zice altceva. **Deci regula ceruta de decizia 50 e deja implementata pentru avize** — nu e nevoie de
+nicio garda noua ca *regula*.
+
+**Dar sunt trei garzi, nu doua, si a treia schimba enuntul deciziei 50:**
+
+| garda | `EXPORT` | ce blocheaza |
+|---|---|---|
+| 1 | 5452-5462 | **factura** care are facturi de retur peste ea (`TIP = 3`) |
+| 2 | 5466-5476 | **aviz** care are factura (`TIP = 1`) sau aviz de retur (`TIP = 2`) peste el |
+| 3 | 5480-5494 | **factura din aviz** ale carei avize-sursa au primit intre timp aviz de retur |
+
+Prin urmare **„factura din aviz ESTE editabila" nu e neconditionat**: e editabila doar cat timp niciunul
+dintre avizele ei nu a primit aviz de retur. Nu e „capat de lant" prin definitie.
+
+**Ce lipseste nu e regula, e MOMENTUL.** Garda traieste in interiorul lui `sterge_factura`, deci se
+manifesta ca `ORA-20000` **in mijlocul** pasului de stergere din regenerare — dupa ce utilizatorul a
+completat formularul si dupa deschiderea tranzactiei. S7 are nevoie de un **pre-flight read-only** pe
+**exact aceeasi conditie**, fara reimplementarea regulii (vezi S7). Interogarea se face pe
+`VANZARI_CORESP`, **nu** pe `VANZARI.FACTURAT`: `FACTURAT` e un marcaj derivat, scris si resetat, dar
+**necitit de nicio garda** — semnalul autoritar e `VANZARI_CORESP`.
+
+**GOLUL REAL NU E PE AVIZ, E PE PROFORMA — si a devenit relevant chiar in runda 14, odata cu decizia 51.**
+`pack_facturare.sterge_proforma` (`EXPORT:5610-5635`) **nu are nicio garda**: corpul ei e doua
+`UPDATE ... SET STERS = 1`. E o procedura **complet separata**, care nu cheama `sterge_factura`, deci
+garda existenta **nu se extinde automat** la `TIP = 4`. O proforma din care s-a emis factura se poate
+sterge azi fara niciun avertisment. Calea VFP iese devreme din `do_sterge`
+(`ofacturare_comun.vc2:4707-4719`), inainte de restul verificarilor. **Asta e continutul concret al
+punctului deschis 4 din S5c** („garda simetrica la stergere") — nu mai e o intrebare de principiu, e o
+garda de scris intr-o procedura care azi n-are niciuna.
+
+**Comanda si contractul nu trec prin `VANZARI_CORESP`** si n-au garda de tip „are urmasi" pe factura:
+comanda se leaga prin `VANZARI.ID_COMANDA` + `inchide_comanda`, iar garda ei e **in VFP si pe comanda**,
+nu pe factura (`COMUN\clase\ocomenzi.vc2:1806-1807` la modificare, `:2065-2066` la stergere); contractul
+se leaga prin `VANZARI.ID_CTR` + `CTR_RATE_FACTURI`.
+
+### Deciziile lui Marius, runda 13 (10.08.2026) — luate, nu de reluat
+
+Cele cinci puncte neblocante ramase din runda 12. **Patru din cinci au mers pe recomandare; al
+cincilea (48) a respins-o motivat.** Fiecare e scrisa si la locul ei, in povestea careia ii apartine.
+
+44. **`poArticol` devine parametru explicit** al dialogurilor de linie (`do_verifica_articol`,
+ `do_alege_stoc` / `frm_articol_gest_factura`), in loc de variabila `Private` populata de apelant.
+ **O singura solutie pentru golul din S4e si cel din S4f (R7)** — e aceeasi problema structurala.
+ Schimbare de contract, **aprobata ca atare**; cere inventarul si actualizarea tuturor apelantilor
+ existenti inainte de prima editare. (S4e, S4f)
+45. **Asimetria din `do_modifica`** se lasa sa se **corecteze de la sine** prin recalculul la cerere,
+ dar corectia se **declara explicit in changelog**. (S4, punctul 2)
+46. **Corectia pe tipurile `23,41` asteapta punctul 2** (recalculul pe server, care acopera Rolul B).
+ Punctul 1 **nu se redeschide** acum. (S4, punctul 2)
+47. **`zi_curs`: simetrie.** Campul se ascunde la loc la stergerea ultimului articol in valuta;
+ „clipitul" e acceptat ca pret al unei reguli unice. (S4d)
+48. **Tabelul de configurare per tip = cursor generat in cod la pornire**, nu `DBF` static, nu tabela
+ Oracle. Detectia tipului necunoscut (eroare la deschidere) se pastreaza; se accepta recompilarea
+ la orice tip nou. (S5)
+
+### Deciziile lui Marius, runda 14 (11.08.2026) — luate, nu de reluat
+
+51. **`TIP = 4` in `VANZARI_CORESP` = „factura scrisa dintr-o proforma".** Confirmat explicit, dupa ce
+ i s-a explicat ce inseamna `1/2/3` (`TIP` = **natura legaturii parinte-copil**, nu tipul
+ documentului: `1` = aviz → factura, `2` = aviz → aviz de retur, `3` = factura → factura de retur).
+ `4` intra in aceeasi familie cu `1`. Valoarea e libera pe ambele fronturi (niciun apel cu `4` in
+ pachet, zero randuri in date), tabela are un singur scriitor in toata suita, structura nu se
+ schimba. **Alocarea e ireversibila odata cu primele date de productie** — acceptat ca atare. (S5c)
+52. **`do_modifica` ramane activ pentru multi-selectie.** Formularul unificat preia cazul cu un singur
+ document; calea veche ramane pentru modificarea in bloc. **Nicio capacitate nu se pierde la
+ retragere** — dar consecinta e ca S2 nu poate desfiinta nici aceasta ruta, nu doar alegerea de la
+ decizia 49. (S8b, punctul 10)
+53. **Atasamentul PDF se sterge la reemitere**, nu se remigreaza si nu se marcheaza „versiune
+ inlocuita". Documentul reemis porneste curat; PDF-ul se regenereaza la prima listare. **Consecinta
+ semnalata explicit lui Marius si acceptata de el:** urma a ceea ce s-a trimis efectiv clientului
+ dispare din sistem. Pasul `UPDATE ATASAMENTE_VANZARI SET id_vanzare = :nou`, adaugat in S9 la runda
+ 13, **se inlocuieste cu stergere**. (S11, punctul 15)
+54. **La reemitere se scriu valorile din formular, nu se reciteste sursa.** Formularea lui Marius:
+ *„nu inteleg de ce se schimba valorile fata de ce se incarca din factura sursa care se modifica?
+ asta este comportamentul pe care il doresc — modific sursa"*. **Asta rastoarna S10:** intrebarea nu
+ mai e „ce garda punem peste re-derivare", ci **„re-derivarea chiar se produce pe calea de
+ reemitere?"** — si daca da, se **elimina**, nu se avertizeaza. Avertizarea + confirmarea propuse de
+ raportul S10 sunt **respinse**: nu se cere utilizatorului sa confirme o schimbare pe care n-a
+ cerut-o. Vezi S10, rescris. (S10, punctele 11 si 12)
+56. **„DA LA TOATE" — Marius a acceptat in bloc toate recomandarile deschise, runda 14.** Formularea
+ lui: *„da la toate, mai putin"* cele doua puncte pe care le-a intrebat separat (48/49 si voiajele).
+ **Nu se mai reintreaba niciunul dintre punctele de mai jos** — sunt luate, si fiecare e scris si la
+ locul lui, in povestea careia ii apartine:
+ - **S8** — canalul de citire a liniilor: **(B), procedura noua `cursor_editare_document`** (nu se
+ extinde `cursor_retur_document`, ca sa nu se schimbe comportamentul copierii; nu
+ `FACT_VFACTURI_DETALII`, care pierde `ID_POL`, `PRETD` si tratamentul valutar — argument intarit
+ de faptul ca **`VVANZARI_ARTICOLE` nu expune `ID_POL` / `ID_CTR`**, vezi S10).
+ - **S8** — `GESTIONABIL` la editare: **din document**, nu din nomenclatorul curent.
+ - **S8** — `text_aditional`: **se normalizeaza la incarcare** (`Chr(170)` → `CR+LF`) si se
+ re-normalizeaza la comparatie. Formele diferite salvate de cele doua rute de scriere se
+ **semnaleaza separat** ca defect preexistent.
+ - **S8** — `zi_curs` pe calea de editare: **ascuns** (precedent: tipurile 8/9). Abatere mica de la
+ decizia 5, asumata.
+ - **S8** — `poDate.lEditare`: **proprietate pe `oDateFactura`**, nu parametru (patru locuri au
+ nevoie de semnal; `lCopiere` e deja acolo cu acelasi rol).
+ - **S8** — `id_ruta`: **proprietate noua pe `oDateFactura`** (fara ea S8c nu poate implementa unul
+ din cei 14 parametri).
+ - **S8** — defectul de prefixare `text_aditional` la `Init` pentru contracte: **se ocoleste in #13**
+ prin `lEditare` si **se semnaleaza separat**, nu se repara pe calea de emitere.
+ - **S5c** — apelul Oracle pentru legatura proforma → factura: **varianta simpla**, pe starea de
+ sesiune a pachetului, zero cod PL/SQL nou — **cu conditia verificata la implementare** ca niciun
+ apel intercalat nu reseteaza starea intre scrierea facturii si scrierea corespondentei.
+ - **S5c** — aceeasi proforma facturata de N ori: **avertisment, nu blocare**.
+ - **S5c** — garda simetrica la stergerea proformei: **se scrie**. Nu e reutilizare —
+ `sterge_proforma` n-are azi nicio garda (vezi decizia 50, sectiunea rescrisa).
+ - **S5c** — afisarea „provine din proforma X": **da**, la nivel de document.
+ - **S4g** — `CU_TVA = 1` hardcodat: **se verifica pe date inainte de implementare**, nu se
+ presupune inofensiv. Efectul prin `nproc_tva_max` e masurat, pe linie scutita + discount global.
+ - **S4g** — trasabilitatea `CONT_VENIT` pe `VANZARI_DETALII`: **da**, se pastreaza coloana.
+ - **Decizia 54, cele trei consecinte: acceptate toate trei.** `IN_STOC` vine din formular (si **S8
+ trebuie sa-l incarce** — vezi S10, consecinta 1); **se pierde validarea** liniei fata de comanda
+ pe ramura comenzi, asumat; **`PROC_TVAV` ramane derivat** — reemiterea dupa o modificare legala
+ de cota va da cota noua, **acceptat deocamdata**; transformarea lui in parametru ramane o
+ decizie separata, daca se cere vreodata reproducere exacta si peste asta.
+ - **Defectul `lnTip` din `do_copiaza`** (runda 13): **se repara la #6**, fisierul fiind al lui.
+ - **Punctele pur interne** (numarul codului de eroare `FACT-0xx`, numele cheii de optiune
+ `FACT_SCD_ARTFPRET`, forma semnalului de regenerare) — **lasate la latitudinea implementarii**,
+ cu recomandarile deja scrise in povestile lor.
+
+ **Raman deschise doar doua**, si amandoua din motive proprii, nu din lipsa de raspuns:
+ **(a) tipurile 48/49** (custodie) — Marius a cerut sa stie implicatiile, i s-au explicat, decizia
+ n-a fost inca data. *Inchis intre timp — decizia 60, runda 16: da, sunt editabile prin #13,
+ cu executia conditionata de verificarea custodiei in curs.*
+ **(b) cota si explicatia de TVA a discountului de document** —
+ **cercetare TERMINATA** (sectiunea K-bis): cota era regula implicita „cota maxima de pe factura",
+ explicatia e azi o constanta hardcodata (`ReasonCode="95"`, text „Discount"). **Partea de
+ repartizare s-a decis — decizia 59, runda 16: proportional pe cote.** Ramane deschis doar campul
+ text optional de motiv — **inchis si el: decizia 61** (da, se adauga), cu asezarea fixata de
+ **decizia 66** (in banda de totaluri, langa discount).
+55. **Metoda de executie e obligatorie, si e scrisa in plan.** La implementare planul **se sparge pe
+ stories**, fiecare story fiind o livrare de sine statatoare; **fiecare pas se testeaza**, nu doar
+ capetele de etapa (S6 / S12); si **fiecare story trece prin code review dupa implementare si dupa
+ teste, inainte de commit**. Sectiunea **„Metoda de executie"**, imediat inainte de Etapa I. S13
+ nu mai e momentul review-ului, ci al inchiderii.
+
+### Deciziile lui Marius, runda 15 (11.08.2026) — luate, nu de reluat
+
+57. **Asezarea zonei de jos: VARIANTA D.** Aprobata explicit („sunt de acord cu varianta D"), dupa doua
+ corectii cerute de el pe drum: (a) *„imi place linia de totaluri de la varianta C, dar incasarea si
+ alte date le vreau tot in acelasi formular, colapsate, mai jos de totaluri"*; (b) *„sectiunile
+ incasare si alte date colapsate trebuie sa fie pe acelasi rand — este destul loc pentru amandoua,
+ detaliile pot sa fie grupate pe orizontala, nu pe verticala"*. A / B / C **cad**.
+
+ **Ce inseamna D, concret, pentru S1 si S3:**
+ 1. **Banda de totaluri** (preluata din C): pe toata latimea, lipita de grid, cu baza, discountul pe
+ articole, discountul de document **cu procentul editabil pe loc** si TVA desfacute pe un rand;
+ totalul mare, singur, la dreapta.
+ 2. **Incasare si Alte date sunt sectiuni colapsabile in formular, nu dialoguri modale** — **una
+ langa alta pe acelasi rand**, sub totaluri, fiecare pe jumatate de latime. Randul inchis arata
+ **rezumatul continutului** („NUMERAR · 5 570,55 lei"), nu doar un titlu. Independente: se poate
+ tine deschisa doar una. Campurile dinauntru se aseaza **pe orizontala**, doua randuri fiecare.
+ 3. **Nu exista bara de comenzi jos.** `but_renunt` / `but_termin` raman unde sunt azi — in banda de
+ titlu, sus in dreapta (`COMUN\clase\cmd_butoane.vc2:288` si `:386`, butoane-imagine cu
+ `Top = 1`, `Anchor = 8/9`, tooltip „Renuntare (ESC)" / „Terminare (CTRL+F)").
+ 4. **Antetul strans la doua randuri**, fara titluri de grup, si **panoul „Discount pe document"
+ dispare** ca panou separat.
+
+ **Patru consecinte de dus in executie, nu de redescoperit:**
+ - **Dispare „renunt doar la incasare".** Fara `Accept` propriu pe dialog, ce se completeaza in
+ sectiune se scrie la `Termina`, impreuna cu documentul. **I-a fost spus explicit** inainte de
+ aprobare si a acceptat.
+ - **Validarea incasarii nu mai are moment propriu** — se muta in `Termina`, langa restul
+ verificarilor. **De scris explicit in S9.**
+ - **Starea deschis/inchis a sectiunilor** — de decis daca se retine intre documente sau porneste
+ mereu inchisa. Nu blocheaza nimic; recomandare: porneste inchisa, se retine per utilizator.
+ - **Caption pe cele doua butoane.** Sus in dreapta, langa `✕`-ul ferestrei, un `✓` verde fara text
+ e ambiguu. Punctul era deja notat in v8 pentru `But_renunt1` / `But_reset1`; D il face mai
+ apasat, pentru ca acum ele sunt **singura** cale de iesire.
+
+ **INCHIS.** Cercetarea despre cota si explicatia de TVA a discountului de document (punctul
+ deschis (b) de la decizia 56) **s-a terminat** — vezi sectiunea K-bis — si repartizarea s-a decis
+ (**decizia 59, runda 16**: proportional pe cote, fara sa se ceara cota de la utilizator), deci a
+ treia sectiune „grea" (cota + explicatie proprii) nu mai e in discutie. Ramane varianta minimala:
+ **decizia 61 (runda 16) a materializat-o** — Marius vrea campul text optional de motiv. Asezarea
+ lui a oscilat o data: decizia 64 il facea a treia sectiune jos, **decizia 66 (runda 17) o
+ rastoarna si il muta in banda de totaluri, langa discount**. **Punctul 2 de mai sus ramane deci
+ exact cum a fost aprobat: doua sectiuni jos, fiecare pe jumatate de latime.** D ramane intr-un etaj.
+
+58. **Mockup-ul asezarii ramane doar online.** Formularea lui: *„nu vreau artifactul html, doar online,
+ ca sa nu mai intretii 2 variante"*. `docs\mockup_13_variante_asezare_jos.html` **a fost scos din
+ `docs\`**; sursa de adevar e
+ **https://claude.ai/code/artifact/dfc70d38-856f-48fd-b6af-3da78e9da4f7**.
+ Ca sa-l modifici: `WebFetch` pe URL → scrie HTML-ul intr-un fisier de lucru **in scratchpad, nu in
+ `docs\`** → `Artifact` cu **`url` = link-ul de mai sus** (fara `url` se creeaza link nou).
+ **`docs\mockup_13_formular_unificat.html` (v8) nu intra sub regula asta** — cerinta a fost data
+ numai pentru mockup-ul asezarii.
+
+### Decizia 59 (Marius, runda 16) — luata, nu de reluat
+
+59. **Discountul de DOCUMENT se repartizeaza PROPORTIONAL PE COTE.** Formularea lui: *„discount pe
+ document repartizat proportional pe cote"*. Se adopta recomandarea cercetarii din **K-bis**:
+ regula de azi („toata valoarea discountului primeste cota MAXIMA de pe factura", prin
+ `Calculate Max(proc_tvav)`) **se inlocuieste** cu repartizarea proportionala cu baza fiecarei
+ cote de pe factura. **Nu se cere utilizatorului cota** — repartizarea e automata.
+
+ **Ce atrage dupa sine, tot din K-bis:**
+ 1. **Doua locuri de schimbat, nu unul, si in ACEEASI livrare:** `prelucreaza_facturacrs` (VFP,
+ `COMUN\programe\ofacturare_comun.prg:1886-1897`) trebuie sa insereze cate un rand-sentinela
+ **per cota** in loc de unul singur; si `recalculeaza_totaluri_vanzari` (PL/SQL,
+ `ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16081-16092`) trebuie sa inlocuiasca `MAX(...)`
+ cu suma repartizarii. Daca se schimba doar unul, `VANZARI.TOTAL_TVA` si TVA-ul din eFactura
+ **diverg** pe facturile cu cote mixte. **Nu e optional si nu se poate esalona.**
+ 2. **Bucatile de discount trebuie sa primeasca `id_jtva_coloana` al grupului pe care il reduc**,
+ nu doar cota. Cheia de grupare din `xmlefactura.prg:246` are cinci campuri si `expltva` se
+ completeaza tot prin `id_jtva_coloana`. O implementare care seteaza doar `proc_tva` **lasa
+ grupul orfan exact unde e azi** — repara jumatate din defect si o lasa pe cealalta.
+ 3. **eFactura nu cere nicio modificare** — `xmlefactura.prg:758-792` grupeaza deja
+ `GROUP BY proc_tva` si emite cate un `AllowanceCharge` per cota.
+ 4. **Diferenta de rotunjire cade pe cota cu baza cea mai mare**, ca suma bucatilor sa fie exact
+ `VANZARI.DISCOUNT`. E recomandarea cercetarii, luata ca implicita — Marius a fost instiintat
+ ca se merge asa fara sa mai fie intrebat, deci se schimba doar daca obiecteaza. (Raportul
+ spune pe alocuri „ultima cota preia diferenta"; **regula care se implementeaza e cea de aici**,
+ ca sa nu ramana doua formulari in circulatie.)
+ 5. **Doua consecinte vizibile, acceptate implicit prin decizie:** factura tiparita va arata **N
+ randuri** „Discount X % Factura" in loc de unul, pe facturile cu cote mixte; si **nota
+ contabila** primeste TVA-ul discountului spart pe cote.
+ 6. **Rezolva si grupul orfan** de pe facturile scutite / taxare inversa / intracomunitare
+ (K-bis), fara garda separata, si desfiinteaza ambiguitatea lui `agettipcota(1)`.
+
+ **Raman DESCHISE, nu de presupus rezolvate:**
+ - **campul text optional de motiv** (`AllowanceChargeReason` in locul constantei „Discount";
+ `ReasonCode` ramane `95`) — Marius **nu s-a pronuntat**; de el atarna si intrebarea de asezare
+ din S1 / decizia 57 (a treia sectiune pe rand sau rand propriu);
+ - **retroactivitatea la relistare / retrimitere**: o factura veche relistata sau retrimisa in
+ eFactura ar genera alt XML decat cel trimis initial. **Nedecis.**
+
+### Deciziile 60-65 (Marius, runda 16) — luate, nu de reluat
+
+60. **Facturile de marfa in CUSTODIE (tipurile 48 si 49) SUNT editabile prin #13.** Formularea lui:
+ *„vreau sa fie posibila editarea si a facturilor in custodie"*. Intra deci in perimetrul
+ **etapei II**, contrar recomandarii „nu acum" din raportul S8 (intrebarea 7, §8.2).
+
+ **Inchide** punctul **(a)** de la **decizia 56** (tipurile 48/49, singurul ramas deschis din
+ blocul „da la toate") si **necunoscuta N5** din `docs\cercetare\s8_incarcare_document.md` §8.1,
+ plus restul intrebarii 7 din §8.2.
+
+ **Ramificatie noua pentru S8:** pe tipurile 48/49, controlul `ct_clb_altele` e scos
+ **neconditionat** la copiere (`ofacturare.vc2:9705-9712`), spre deosebire de tipurile 1/5/10
+ unde copierea il **pastreaza** si il reeticheteaza (`s8_incarcare_document.md` §3.2, ramura 3).
+ Calea de **editare** trebuie sa-l pastreze si pe custodie — ramura 48/49 a copierii nu poate fi
+ refolosita ca atare.
+
+ **VERIFICAT — blocantul CADE, dar premisa initiala era gresita.** Raportul:
+ `docs\cercetare\custodie_48_49_stergere_reemitere.md`. `scrie_fact_aviz_custodie` **nu are
+ legatura cu tipurile 48/49** — are un singur apel in tot pachetul (`PACK:7521`), pe ramura
+ `pack_facturare.ntip <> 4` (`:7472`), deci serveste `ntip = 4` (factura din avize), nu custodia;
+ numele procedurii a indus in eroare, si premisa gresita a circulat pana in aceasta decizie.
+ Emiterea unui document 48/49 **nu atinge deloc stocul**: sursa lor unica de articole e
+ `cursor_articole_k` (`PACK:3595-3701`), restransa explicit la `WHERE C.IN_STOC = 0` (`:3695`),
+ iar `descarca_gestiune` se cheama doar cand `in_stoc = 1` (garda dubla, la apelant `:7472-7475`
+ si in corpul procedurii `:7789-7797`). `sterge_factura` (`:5432-5607`) nu are ramura dedicata
+ pentru 48/49, si nici cele trei garzi de refuz al stergerii (`:5452-5494`) nu le prind — dar
+ **n-are ce reversa**, fiindca nimic legat de stoc n-a fost scris la emitere. **Regenerarea e
+ sigura pe 48/49**, nu pentru ca reversarea ar functiona, ci pentru ca nu exista nimic de
+ reversat.
+
+ **Rezerva, de scris, nu de ascuns:** siguranta atarna de un invariant azi impus doar de sursa de
+ articole — „documentele 48/49 contin numai articole cu `IN_STOC = 0`". Invariantul **nu s-a
+ verificat exhaustiv**, doar constatat pe sursa curenta. #13 schimba modul de adaugare a
+ articolelor (**S4** — cautare pe server, in linie; **S4g** — adaugare de articole la modificarea
+ oricarui document): daca formularul unificat ajunge sa permita adaugarea unui articol
+ **gestionabil** pe un document 48/49, invariantul se rupe si concluzia de siguranta pica.
+ **Cerinta pentru S4/S4g/S5: pe tipurile 48/49 se pastreaza restrictia la articole `IN_STOC = 0`**
+ — vezi notele de executie la acele povesti; devine **criteriu de test**, nu presupunere.
+
+ Pentru **emitere**, tipurile 48/49 erau oricum deja acoperite de etapa I (S5 completeaza cele
+ patru randuri lipsa din `Do Case`: 45, 48, 49, 52) — decizia 60 priveste doar **editarea**.
+
+61. **Discountul de document primeste un CAMP TEXT OPTIONAL de motiv.** Formularea lui: *„la
+ discount, da, un camp text optional"*.
+
+ **Inchide** ultimul punct ramas deschis din **K-bis** si din **decizia 56 (b)** — campul de
+ motiv nu mai e „Marius nu s-a pronuntat".
+
+ **Ce inseamna concret:**
+ - inlocuieste constanta hardcodata `"Discount"` ca `cbc:AllowanceChargeReason`
+ (`COMUN\programe\xmlefactura.prg:774-776`); **`ReasonCode` ramane `95`**;
+ - cere **stocare noua** — azi nu exista nicio coloana pe `VANZARI` pentru motivul discountului
+ de document;
+ - cere **un control nou in formular** — singura bucata din reparatia discountului (K-bis /
+ decizia 59) care chiar cere UI nou, restul fiind repartizare automata fara interactiune.
+
+ **Redeschisese, in varianta minimala, intrebarea de asezare de la decizia 57. INCHISA DEFINITIV
+ PRIN DECIZIA 66 (runda 17): campul sta in banda de totaluri, langa discount.** Decizia 64, care il
+ facea a treia sectiune jos, **e rasturnata** — randul de jos ramane cu doua sectiuni, ca la decizia
+ 57. Varianta D ramane intr-un etaj. Paragrafele din **S1** si din **decizia 57** sunt actualizate
+ in acest sens.
+
+62. **Restrictia de modificare e „documentul sa NU fi fost trimis in eFactura" — si de aici
+ retroactivitatea NU mai e o intrebare.** Formularea lui: *„singura restrictie pentru modificare
+ este sa nu fie trimisa in eFactura, deci nu are legatura retroactivitatea"*.
+
+ Garda insasi nu e noua — **S7** o are deja, reutilizata din #6
+ (`COMUN\programe\ofacturare_editare.prg:19-28`, functia `EsteInEFactura`; apelata din
+ `COMUN\clase\ofacturare_comun.vc2:3764`). Ce era intrebare deschisa era
+ doar partea lasata de **decizia 59**: daca o factura veche, retrimisa, ar trebui tratata altfel
+ fata de una noua. Raspunsul lui Marius **inchide** acea intrebare: nu se leaga de nicio data si
+ de niciun flag suplimentar — verificarea `EsteInEFactura` ramane singurul criteriu de
+ modificare.
+
+ **Ramane un rest neacoperit, semnalat lui Marius, nedecis inca:** o factura **veche, deja
+ trimisa**, daca e doar **relistata** (tiparita din nou, nu editata), trece iar prin
+ `prelucreaza_facturacrs` si — dupa decizia 59 — ar produce **N randuri de discount in loc de
+ unul** pe facturile cu cote mixte, deci hartia ar diferi de originalul trimis in eFactura.
+ Relistarea nu e modificare, deci garda `EsteInEFactura` nu o acopera.
+
+63. **CERINTA NOUA DE AUDIT pe documente.** Formularea lui: *„este doar util de stiut data crearii,
+ data modificarii daca este cazul, utilizatorul crearii si al modificarii daca este cazul,
+ respectiv data stergere si utilizator stergere daca este cazul, pentru audit"*. Sase informatii:
+ **data + utilizator** pentru **creare**, **modificare** si **stergere**.
+
+ Scrisa initial ca cerinta, cu cercetarea in curs. **Cercetarea TERMINATA**, raport:
+ `docs\cercetare\audit_vanzari_creare_modificare_stergere.md`.
+
+ **Verdict, in doua randuri:** patru din cele sase informatii cerute **exista deja** pe `VANZARI`
+ si se scriu consecvent (`ID_UTIL`/`DATAORA` la creare, `ID_UTILS`/`DATAORAS` la stergere); **lipseste
+ complet perechea de modificare** (nicio coloana, verificat cu filtru `%MODIF%` pe
+ `all_tab_columns`), iar editarea prin stergere+reemitere (S9) ar **suprascrie tacit** perechea de
+ creare cu utilizatorul si data regenerarii, daca nu se transporta explicit — acelasi risc deja
+ rezolvat pentru `ID_FACT` (sectiunea „E. `ID_FACT`", linia 762).
+
+ **Poveste noua, proiectata: S14** — verdict complet, recomandare si punctele ramase de decis cu
+ Marius acolo.
+
+64. ~~**Asezarea campului de motiv: RANDUL SE IMPARTE IN TREI.**~~ **RASTURNATA DE DECIZIA 66
+ (runda 17) — NU MAI E IN VIGOARE.** Formularea de atunci: *„campul de motiv imparte randul in 3"*;
+ randul de jos ar fi avut trei sectiuni (incasare, alte date, motivul discountului), ~440 px
+ fiecare la 1366 px.
+
+ **Se pastreaza ca istorie, nu ca regula**, si merita pastrata: varianta a fost **construita in
+ mockup (v9) si respinsa dupa ce Marius a vazut-o** — *„motiv discount vreau sa fie langa discount,
+ nu a treia coloana"*. E argumentul cel mai bun din tot planul pentru **de ce se face mockup
+ inainte de cod**: decizia luata pe descriere s-a intors la prima privire pe forma desenata.
+ Ce e in vigoare: **decizia 66**, mai jos.
+
+65. **Auditul (decizia 63) se afiseaza in gridul din `frm_facturi`, nu in formularul facturii.**
+ Formularea lui: *„auditul presupun coloanele dataora si utilizator adaugat/modificat/sters, le
+ vreau pe grid-ul din formularul frm_facturi, nu in formularul facturii propriu-zise - este
+ posibil sa fie deja coloane"*.
+
+ Confirma continutul cerintei de audit (decizia 63): trei perechi **data + utilizator**, pentru
+ **adaugat**, **modificat** si **sters**. Locul de afisare e **gridul din `frm_facturi`**, nu
+ formularul unificat — deci **S14 nu cere controale noi in formularul unificat**, cere **coloane
+ in gridul listei de facturi**. E o cerinta mai usoara decat presupunea S14, si e de spus explicit.
+
+ **Sarcina de verificat la implementarea lui S14, adaugata ca prim pas al povestii:** Marius
+ banuieste ca unele coloane exista deja in acel grid. **Nu s-a verificat.** S14 incepe deci cu
+ **inventarul gridului din `frm_facturi`** — ce coloane de audit sunt deja acolo, ce surse au —
+ si abia apoi adauga ce lipseste. Nu se presupune nici ca exista, nici ca nu.
+
+### Decizia 66 (Marius, runda 17) — luata, nu de reluat. RASTOARNA DECIZIA 64.
+
+66. **Motivul discountului sta LANGA DISCOUNT, in banda de totaluri — nu ca a treia sectiune jos.**
+ Formularea lui: *„motiv discount vreau sa fie langa discount, nu a treia coloana"*.
+
+ **Anuleaza decizia 64** (randul de jos se imparte in trei). Randul de jos revine la **doua
+ sectiuni colapsabile** — incasare si alte date — adica exact la ce aprobase decizia 57, punctul 2,
+ inainte ca decizia 61 sa redeschida discutia. **Decizia 57 ramane intreaga; nu se mai atinge.**
+
+ **Ce inseamna concret, pentru S1 si S3:**
+ - campul de motiv e un **control in banda de totaluri**, imediat dupa suma discountului de
+ document, inainte de TVA; ia latimea ramasa pana la totalul mare, care sta la dreapta;
+ - **cele doua sectiuni de jos redevin pe jumatate de latime** (~660 px la 1366 px), nu ~440 —
+ argumentul „strans, asumat ca atare" din decizia 64 **cade odata cu ea**;
+ - **regula de activare, adaugata de proiectare, nu ceruta explicit:** campul e activ **numai cand
+ discountul de document nu e zero**. Un motiv fara discount n-are ce explica, si ar ajunge in
+ `AllowanceChargeReason` pe un `AllowanceCharge` inexistent. Daca Marius vrea altfel, e o linie
+ de schimbat.
+
+ **Consecinta de asezare, de stiut la implementare:** banda de totaluri devine plina — baza,
+ discount articole, discount document (procent + suma + bifa „evidentiat"), motiv, TVA, total. La
+ latimi mici **se rupe pe doua randuri** (`flex-wrap`), si asta e acceptat: alternativa ar fi
+ scoaterea bifei „evidentiat" din banda, care n-a fost ceruta.
+
+ Restul deciziei 61 (stocare noua pe `VANZARI`, `AllowanceChargeReason`, `ReasonCode` ramane `95`)
+ **e neatins** — se schimba doar locul controlului in formular.
+
+### Decizia 67 (Marius, 20.08.2026) — intrare separata „Facturare (nou)", nu comutator. Inchide (A)/(B) din decizia 49 pe (B).
+
+67. **Nu comutator global cu dialog — buton nou de meniu, ca ambele fluxuri sa fie accesibile in
+ acelasi timp.** Formularea lui: *„nu vreau sa modific o optiune pentru facturarea pe model nou,
+ ci vreau sa pui in meniu o varianta de facturare nou, ca sa pot sa accesez in acelasi timp ambele
+ facturari, si cea existenta si cea noua"*.
+
+ **Inchide definitiv alegerea (A)/(B) din decizia 49 (plan, liniile 3040-3082) pe varianta (B).**
+ Implementarea S2 din runda anterioara (comutator `gnFacturareNou` + `AMESSAGEBOX` DA/NU la
+ inceputul lui `factureaza`, care selecta intre proceduri) **se inlocuieste**, nu se pastreaza ca
+ alternativa.
+
+ **Mecanismul, minim, pe doua fisiere:**
+ - `COMUN\programe\ofacturare.prg`, in `factureaza`, la punctul de alegere a lui `lcObject`:
+ `llFacturareNoua = (Type('plFacturareNoua') = 'L' And m.plFacturareNoua)` — variabila
+ `plFacturareNoua` e `Private`, declarata de apelant; nedeclarata => `.F.` => calea veche,
+ identica azi, in toata suita (celelalte produse nu o declara). Fara dialog, fara comutator
+ global. `gnFacturareNou` dispare complet din fisier.
+ - `Clase\ofundal_facturare.vc2`, `Page2` (fundalul „Facturare"): buton nou `Cw10`, „Facturare
+ (nou)", cu propriul `do_actiune` care declara `Private plFacturareNoua = .T.` si ofera acelasi
+ meniu de surse (lista de preturi, contracte, comenzi, avize) ca butoanele existente, apeland
+ aceiasi wrapperi din `oproceduri_facturare.prg`. Popup-urile (`politica.mpr`/`contracte.mpr`)
+ executa `factureaza(N)` in interiorul `ACTIVATE POPUP`, deci vad variabila privata a
+ apelantului pe tot lantul de apel, fara sa fie redeclarata pe drum.
+
+ **Criteriul „gata" pentru S2 se rescrie in consecinta** (vezi story S2 mai jos): zero aparitii
+ `gnFacturareNou`, exact o aparitie `plFacturareNoua` in `ofacturare.prg`; butonul `Cw10` deschide
+ `frm_facturare_articole2` din formularul unificat vechi al meniului `Facturare`, fara sa
+ afecteze butoanele Cw1-Cw9 existente.
+
+ **COMPLETARE (Marius, 20.08.2026, aceeasi zi) — acoperire completa, nu doar 4 intrari.**
+ Intrarea „model nou" trebuie sa acopere **toate** intrarile de facturare existente, pe **ambele**
+ pagini ale fundalului, nu doar cele patru de pe `Page2` alese initial. Implementare generica,
+ fara duplicare de cod:
+ - `Page2.Cw10.do_actiune` ofera **toate cele noua** optiuni ale paginii „Facturare" (captions
+ identice, extrase textual din `Label_item1.Caption`/`LABEL_ITEM1.Caption` al fiecarui `Cw1..Cw9`,
+ in aceeasi ordine), si apeleaza `This.Parent.Cw.do_actiune()` pentru optiunea aleasa — nu mai
+ cheama wrapperii direct, ca sa nu duplice logica fiecarui buton (unele cheama wrapperi din
+ `oproceduri_facturare.prg`, altele — pe `Page3` — cheama `.mpr` direct; `This.Parent.Cw` merge
+ identic in ambele cazuri).
+ - Buton nou `Page3.Cw5`, „Avize (nou)", acelasi tipar, peste cele patru intrari ale paginii „Avize"
+ (`Cw1`=catre clienti, `Cw2`=catre clienti in custodie, `Cw3`=catre clienti debitori,
+ `Cw4`=transfer intre subunitati).
+ - `plFacturareNoua` (Private, setata `.T.` in `do_actiune`-ul butonului nou) ramane vizibila prin
+ `This.Parent.Cw.do_actiune()` -> wrapper/`.mpr` -> `ACTIVATE POPUP` -> `factureaza(N)`, la fel
+ ca in varianta cu patru intrari - niciun apel din lant nu o redeclara.
+ - **Verificat in `factureaza`**: exista un singur punct unde se atribuie `lcObject`, intr-un
+ `If tnTip = 27 ... Else ... Endif` cu exact doua ramuri. Tipul 27 (aviz pe baza de lucrare) e
+ **singura exceptie** - toate celelalte tipuri (toate avizele, toate vanzarile, contractele,
+ returul, credit note) cad in `Else`, deci vad `plFacturareNoua`. Daca un utilizator ajunge la
+ tipul 27 prin butonul nou „Avize (nou)" (posibil via `aviz_subunitati.mpr`), flagul nu are efect
+ pentru acel sub-flux - comportament asteptat, nu bug, semnalat aici explicit.
+
+ **CORECTIE dupa review (aceeasi zi) — 5 din cele 9 optiuni initiale ale `Page2.Cw10` NU treceau
+ niciodata prin `factureaza`.** Review-ul (`docs\review_s2.md`, sectiunea 3) a gasit ca `Cw5..Cw9`
+ (materii prime, produse, marfa la pret de achizitie/vanzare/achizitie-vanzare) ruteaza prin
+ `vanzare_*` -> `vanzare1-5.mpr` -> `initializeaza_vanzare_din_stoc()`
+ (`COMUN\programe\ofacturare_stoc.prg:35-103`), un flux complet separat de „facturare" (deschide
+ formularul prin `lans()`, nu apeleaza niciodata `factureaza()` - `grep -c "factureaza("` pe fisier
+ = 0). Analiza de mai sus despre `lcObject`/`Else` e corecta, dar incompleta: demonstreaza doar ca
+ *daca* un tip ajunge la `factureaza`, vede `plFacturareNoua` - nu ca toate cele noua optiuni ale
+ lui `Cw10` ajung acolo. **`Page2.Cw10.do_actiune` s-a corectat la primele patru optiuni (`Cw1..Cw4`
+ - lista de preturi, contract, comanda, aviz), singurele care trec prin `factureaza`.** `Page3.Cw5`
+ ramane neschimbat - toate cele patru optiuni ale lui verificate ca trec prin `factureaza`. Vanzarile
+ din stoc (`Cw5..Cw9` de pe `Page2`) raman in afara perimetrului povestii #13 - `factureaza` nu are
+ nicio legatura cu ele.
+
+ **`frm_facturare_articole2` ramane, ca si pana acum, un prototip neterminat** (S1/S3) — decizia
+ 67 schimba doar *cum se ajunge la el* (intrare de meniu explicita, nu comutator ascuns), nu
+ starea lui functionala.
+
+
+### Decizia 68 (Marius, 21.08.2026) — S3 se sparge in S3-1..S3-4; logica comuna a antetului trece in `.prg`, designul ramane in `.vcx`
+
+Marius a aprobat, pe nota de executie `docs\nota_executie_s3.md`: **spargerea lui S3** in S3-1 (pas 0
++ `Init` fuzionat + C3 + `do_cauta_fdoc`), S3-2 (cele 28 `do_cauta_*` + `do_verifica`), S3-3
+(`inainte_de_do_termin` fuzionat + `do_schimba_tipdoc` + evenimentele de antet + testul UI), S3-4
+(integrarea buclei din `factureaza`, `ofacturare.prg` — cod comun suitei; raspunde la Q1), in
+ordinea asta; si recomandarile Q2 (combo `cboFdoc` dezactivat „AVIZ" pe aviz, `do_cauta_fdoc`
+portata, nelegata) si Q3 (doar `RemoveObject`, reasezarea la S3b).
+
+**Q4, precizat de Marius, textual:** *„toate metodele care se preteaza se pot muta in prg, sub forma
+de metode de clase. preteaza inseamna ca sunt lucruri comune, folosite de mai multe clase, sau
+utilitare [...]. imi este mult mai usor sa editez prg decat vcx. daca sunt lucruri care afecteaza
+design, ar trebui sa fie in vcx."* Regula de aplicat in S3-1..S3-4 (si in restul lui #13):
+
+- **in `.prg`, ca metode ale unei clase** (`Define Class ... As Custom`, sablon `anaf_efactura.prg`;
+ un singur cod, nu doua — in spiritul deciziei 35): cautarile `do_cauta_*` care scriu pe `poDate`
+ prin `caut_*()`, validarile din `inainte_de_do_termin` (lanturile `Do Case` / `amessagebox`),
+ regulile de `do_schimba_tipdoc` care nu ating controale, si orice utilitar folosit din mai multe
+ clase (`frm_date_factura`, `frm_date_aviz`, `frm_facturare_articole2`). Metoda din `.vcx` devine
+ un apel de o linie catre obiectul din `.prg` (`This.oAntet.(This)` sau echivalent), ca sa
+ ramana `cprocedura` al controalelor valid.
+- **in `.vcx`**: tot ce tine de design si de suprafata — `Init`-ul (asezare, `RemoveObject`, focus,
+ etichete, serie/numar pe controale), `SetFocus`, `Enabled`/`Visible`, `ADD OBJECT`, evenimentele
+ controalelor.
+- Linia de demarcatie nu se trage mecanic: o metoda care amesteca o regula cu un `SetFocus` se
+ desparte — regula in `.prg`, efectul pe control in `.vcx`. Portarea ramane verificabila fata de
+ sursa (diff-ul citeaza de unde a venit fiecare corp).
+- Fisierul `.prg` nou (sau clasa noua in `COMUN\programe\ofacturare_comun.prg`, unde traieste deja
+ `oDateFactura`) se inregistreaza in `SET PROCEDURE ... ADDITIVE` din `Programe\roafacturare.prg`
+ daca e fisier nou — alegerea (fisier nou vs. clasa in `ofacturare_comun.prg`) se face in S3-2, o
+ singura data, si se noteaza in nota de executie.
+
+Consecinta pe S3-1, deja pornit: `Init` ramane in `.vcx` (e design); `do_cauta_fdoc` se porteaza in
+`.vcx` acum si **se muta** in clasa `.prg` la S3-2, odata cu celelalte `do_cauta_*` — ca sa nu se
+faca de doua ori alegerea locului.
+### Decizia 69 (Marius, 21.08.2026) — S3-4: forma functiei, declansarea incarcarii, antetul dupa incarcare, numarul ars
+
+Raspunsuri la Q5-Q7 din `docs\nota_executie_s3_4.md` plus perimetrul semnalat de
+`docs\verif_nract_do_cauta.md`.
+
+- **Q5 — functie globala**, langa clasa, in `COMUN\programe\ofacturare_antet.prg`. Constructia
+ cursorului de articole se apeleaza si din `factureaza` (unde nu exista formular), si din
+ `do_incarca_articole` (unde exista); o metoda de clasa ar cere fie doua cai de apel, fie
+ instantierea artificiala a lui `oAntetFacturare` doar pentru acest apel.
+- **Q6 — buton explicit** `but_incarca_articole` pe formularul unificat. Incarcarea automata la
+ completarea ultimului camp obligatoriu ar re-executa interogari Oracle la fiecare corectie de camp.
+- **Q7 — limitare cunoscuta, se lasa pentru S3b.** S3-4 livreaza exact criteriul „gata" al lui S3:
+ antetul se completeaza o data, articolele se incarca o data, documentul se termina. Ce se intampla
+ cu `crsfactura` daca antetul se schimba dupa incarcare nu se rezolva aici si nu se blocheaza
+ antetul; se documenteaza.
+- **Q8 — numarul ars se repara pe AMBELE cai, in S3-4.** In `do_schimba_tipdoc` alocarea
+ (`clb_serie_act1._cbbase1.LostFocus()`) ruleaza inaintea garzii „s-a schimbat tipul?"
+ (`ofacturare_antet.prg:906-908`; echivalent inline pe calea veche, `ofacturare.vc2:9396+`), deci se
+ consuma un numar real la simpla intrare-iesire din combo, fara nicio schimbare. Garda se muta
+ inainte de alocare in ambele implementari.
+
+ **Abatere asumata de la politica S3** („calea veche nu se atinge — nici nu se repara, nici nu se
+ reproduce"): orchestratorul a recomandat amanarea ca bug separat dupa #13, fiindca reparatia atinge
+ cod din productia tuturor utilizatorilor in mijlocul unificarii. Marius a decis reparatia pe ambele
+ cai. Consecinte de verificat la implementare: `test_s3_neregresie_vechi` compara amprente de dupa
+ `Init` (controale, etichete, `nid_tip`, `Height`) si nu exercita `do_schimba_tipdoc`, deci ar trebui
+ sa ramana identic — **de dovedit, nu de presupus**; iar paritatea pe `nract` din
+ `test_s3_do_cauta`/`test_s3_tipdoc` se pastreaza doar daca ambele cai se schimba impreuna.
+
+### Decizia 70 (Marius, 21.08.2026, seara) — amendament la Q8: pe modelul vechi se lasa cum era
+
+Reparatia Q8 ramane **doar pe calea unificata** (`plFacturareNoua`); `frm_date_factura` revine
+neatins. Politica S3 „calea veche nu se atinge" se restabileste.
+
+Motivul: review-ul independent (`docs\review_q8_numar_ars.md`, Q8-R5) a aratat ca pe calea veche
+reparatia nu inseamna doar „nu se mai arde un numar", ci **muta momentul alocarii** — documentul nou
+primeste numar abia la iesirea din controlul de serie, iar utilizatorul care sare peste el cu mouse-ul
+vede „Numar document" gol si primeste la finalizare „Nu ati completat numarul documentului!"
+(`ofacturare.vc2:9492-9495`). Schimbare de flux zilnic pentru toti utilizatorii suitei, in mijlocul
+unificarii.
+
+Ce ramane ca **datorie deschisa pe calea veche** (constient, nu prin omisiune): numarul ars la simpla
+intrare-iesire din combo si eroarea 1925 pe configuratiile cu `rezultat_serii = 0`.
+
+Consecinta prevazuta de decizia 69 s-a materializat: cele doua suite de paritate au incetat sa mai fie
+valabile ca atare (`test_s3_tipdoc` 11/5 FAIL, `test_s3_do_cauta` cu 23 de comparatii excluse tacit).
+Au fost adaptate sa **afirme divergenta explicit**, nu s-o excluda — `docs\raport_adaptare_paritate_q8.md`.
+
+
+### Decizia 71 (Marius, 22.08.2026) — `incarca_cursor_articole` nu mai primeste `poDate` ca parametru
+
+Functia extrasa la S3-4a isi pierde parametrul `poDate`; foloseste doar `Private`-ul apelantului.
+Semnatura devine `Lparameters tnTip, tlCopiere, poGeneratorNumere`.
+
+Motivul, ridicat de review-ul S3-4a (`docs\raport_s3_4a_implementare.md:142-177`): parametrul creeaza
+**doua legaturi** pentru acelasi nume. Codul VFP din corp foloseste parametrul, dar parametrii SQL
+`?poDate.*` se rezolva in `oExecute` la `poDate`-ul `Private` al apelantului. Azi coincid; un apel
+viitor cu alt obiect (de exemplu `This.oDate` din formularul unificat, exact ce urmeaza la S3-4b) ar
+construi cursorul pe alt antet decat cel trimis la Oracle — **tacut**, fara eroare si fara mesaj.
+Testul actual nu ar prinde-o: foloseste acelasi obiect pe ambele cai, cu executor mock-uit.
+
+Garda runtime propusa in review nu functioneaza in VFP (`Evaluate('poDate')` in interiorul functiei
+intoarce parametrul local, nu privatul apelantului), deci singura varianta care inchide problema prin
+constructie e eliminarea parametrului. Pretul: un parametru mai putin explicit in semnatura.
+
+### Decizia 72 (Marius, 22.08.2026) — reasezarea formularului unificat. RASTOARNA DECIZIA 26.
+
+Mockup aprobat, online: https://claude.ai/code/artifact/de29f441-7f23-4c73-801f-e75d801ed3e9
+(inventarul complet control-cu-control e sectiunea 5 din mockup; nu se duplica aici). Castigul masurat
+pe captura 1920x944: antet 177 -> ~139 px, banda de totaluri 154 -> ~36 px, grid 580 -> ~674 px,
+adica ~4-5 randuri de articole in plus.
+
+**1. Formularul se deschide maximizat** (`WindowState`).
+
+**2. Antetul pe doua randuri grupate, etichete deasupra casetelor** (varianta D din mockup):
+- rand 1, documentul: tip document, serie, numar, data, scadenta, inregistrare, data curs;
+- rand 2, partenerul: client, cod fiscal **cu butonul ANAF in caseta**, sold lei, bifa
+ **TVA la incasare** — bifa tine de client, nu de document.
+
+**3. Ies din antet si coboara in sectiunea pliata `Alte date`:** analiticele (venit/cheltuiala, sectie,
+lucrare, responsabil), **gestiunea sursa** — etichetata „filtru de stoc", fiindca `poDate.id_gestiune_init`
+pleaca pe server ca `V_ID_GESTIUNE_INIT` si restrange ce gestiuni intra in calculul stocului
+(`ofacturare.prg:471`, `:479`), nu e o valoare implicita a liniilor — si **explicatia pentru nota
+contabila** (`Ed_tx_simplu1` = `poDate.explicatia4`), etichetata „nu apare pe factura": ajunge in `ACT`
+prin `initializeaza_date_factura` (`ofacturare_stoc.prg:335`), dar nu apare nici pe `.frx`, nici in
+`xmlefactura.prg`.
+
+**4. Banda de totaluri pe un singur rand**, lipita de grid: Baza · Disc. art. · Disc. factura (procent +
+suma + bifa scurta „evid." cu tooltip) · Motiv · TVA · **TOTAL** la dreapta. Inlocuieste cele doua
+panouri de azi.
+
+**5. Gridul se intinde pe toata latimea** — azi se opreste la ~1360 px din 1920.
+
+**6. Bara de butoane deasupra gridului**, forma minima: Linie noua / Sterge linia / Incarca articole.
+**`But_verifica1` NU intra aici**: e verificarea ANAF (`do_verifica` -> `VerificaCodFiscal(...,
+"ANAF_SERVICIU_WEB")`, `ofacturare_antet.prg:740-754`), ramane langa codul fiscal.
+
+**7. `Alte date` si `Incasare` raman JOS, sub totaluri, una langa alta.** Marius: *„nu este esentiala
+pentru completarea facturii... nu vreau sa ocupe loc principal"*. **Decizia 57 punctul 2 ramane
+intacta**; propunerea de a le muta deasupra gridului a fost retrasa si nu se reia.
+
+**8. Analiticele raman EDITABILE, definitiv — decizia 26 se rastoarna.** Marius: *„de ce sa fie blocate?
+la introducere sa pot sa aleg sectia, lucrarea etc. la fel si la editarea ulterioara a facturii, care
+face stergere + inregistrare noua. editarea din #6 este separata de ce faci acum"*. Venit/cheltuiala,
+sectie, lucrare si responsabil se aleg si la introducere, si la reemitere; **nu se scrie `ReadOnly` pe
+ele nicaieri**. Consecinta de consemnat, nu de reluat: la reemitere nota se reconstruieste uniform pe
+document, deci o diferentiere facuta in #6 **la nivel de linie de nota** se pierde — e inerent
+regenerarii (documentul vechi se marcheaza `sters=1`, se scrie unul nou), nu efectul acestei decizii.
+
+**Punctele deschise la momentul aprobarii — INCHISE de decizia 73** (sursa deasupra gridului langa buton,
+buton cu eticheta dupa sursa, `explicatia`/`explicatia5` amanate, grupul contabil fara optiune de
+ascundere). Ramane deschis un singur punct:
+- **Adresa de livrare** — cercetare completa in `docs\cercetare\adrese_facturare_livrare.md`. Golul real:
+ pe o factura din comanda adresa de livrare **pleaca in eFactura** (`xmlefactura.prg:696-736`, cu
+ validari blocante) venind tacit din `comenzi.id_livrare` prin `poDate.oClient.adresa_livrare`
+ (`ofacturare.prg:685`, `694-695`), dar utilizatorul **nu o vede si nu o poate schimba** pe formularul
+ de facturare. `frm_alte_date` are un singur control de adresa, `clb_adresa_facturare`
+ (`ferestre_cere_date.vc2:2422-2440`) — control de livrare nu exista. Daca se vrea vizibila/editabila:
+ camp nou pe `poDate` + control in `Alte date` + propagare in `poClient`.
+
+**De stiut la implementare:** nici `Incasare`, nici `Alte date` nu exista azi in `frm_facturare_articole2` —
+amandoua sunt inca dialogul modal `frm_alte_date` (`COMUN\clase\ferestre_cere_date.vc2:2219`), deschis cu
+`Createobject("frm_alte_date")` (`ofacturare.vc2:19193`). Continutul lui se imparte astfel: **Incasare** —
+`Clb_incasat`, `opt_incasat`, `Clb_serie_chit`, `Clb_nrchit`, `Cb_casa`, `chkPOS`, `chkDetaliat`,
+`cmdModificaBon`, `But_modifica1`; **Alte date** — `Ct_clb_delegat`, `Ct_clb_masina`, `Ct_clb_agent`,
+`Clb_dataora_exp`, `clb_adresa_facturare`, `cboTipFactura`.
+
+
+### Decizia 73 (Marius, 22.08.2026) — inchide cele patru puncte lasate deschise de decizia 72
+
+**1. Sursa (`Ct_clb_altele`) sta deasupra gridului, langa butonul de import** — nu in antet si nu in
+`Alte date`. Marius: *„cred este nevoie de sursa sa fie vizibila la factura din comanda/contract/aviz/retur
+etc. probabil si cu butonul importa din comanda/contract/aviz etc"*. Sursa si butonul care importa din ea
+stau impreuna; dupa incarcare butonul dispare (`do_incarca_articole` face
+`This.but_incarca_articole.Visible = .F.`, `ofacturare.vc2:18071`), iar sursa ramane vizibila ca referinta.
+
+Bara devine: `[Nr. comanda: 1234]` `[Incarca din comanda]` | `[Linie noua]` `[Sterge linia]`.
+
+**Verificat pe cod, nu e cerinta noua:** `Ct_clb_altele` isi schimba deja eticheta dupa tipul documentului —
+„Nr. comanda", „Nr. contract", „Nr. aviz / avize", „Nr. facturi", „Gestiune destinatie", „Retur la",
+„Locatie" — in `Do Case`-ul din `Init` (`COMUN\clase\ofacturare.vc2:19375-19520`), si e scos cu
+`RemoveObject` exact acolo unde nu exista sursa (factura din lista de preturi, necopiata). Deci
+vizibilitatea ceruta exista deja; decizia priveste **doar pozitia**.
+
+**2. Butonul de import primeste eticheta dupa sursa:** „Incarca din comanda" / „din contract" / „din aviz" /
+„din facturi", in loc de „Incarca articole" (`ofacturare.vc2:15982`). Caption-ul se seteaza din **acelasi**
+`Do Case` care seteaza eticheta lui `Ct_clb_altele` — un singur loc, cateva linii. Cand sursa lipseste si
+controlul e scos, ramane „Incarca articole".
+
+**3. `explicatia` si `explicatia5` NU intra in aceasta reasezare.** S3b livreaza doar `explicatia4`, ca azi.
+Aducerea lor pe formular cere doua campuri noi pe `poDate` (`ofacturare_comun.prg:200`) plus lantul de
+scriere pana in `ACT` — story propriu, in afara #13 asa cum e definit acum.
+
+**4. Grupul contabil nu primeste optiune de ascundere.** Plierea sectiunii `Alte date` acopera deja cazul:
+cine nu foloseste analiticele nu deschide sectiunea. Zero cod in plus, niciun camp de configurare nou.
+
+
+### Decizia 74 (Marius, 22.08.2026) — trei corectii de asezare, dupa ce cercetarea a infirmat premisele mockup-ului
+
+Cercetarea completa, cu citate: `docs\cercetare\s3b_geometrie_grid_totaluri.md`.
+
+**1. Gridul de cursuri valutare coboara in sectiunea pliata `Alte date`.**
+
+Mockup-ul spunea „ascunse pe factura in lei". **Fals.** `grd_cursuri` / `lb_cursuri` apar si pe
+facturile in lei: conditia de afisare nu e moneda documentului, ci existenta cursurilor zilei.
+Pe ramura de lei, `ofacturare.prg:599` apeleaza `citeste_cursuri_zi(poDate.zi_curs)`, care citeste
+tot `vcurs`-ul valabil in ziua respectiva (`oproceduri_curs.prg:113-122`), iar `zi_curs` e setat
+neconditionat la data documentului (`ofacturare_comun.prg:247`, `:496`). Formularul nu verifica
+nicaieri `in_valuta` pentru vizibilitate — doar `Used('crscursuri') And Reccount('crscursuri') > 0`
+(`ofacturare.vc2:18072`, `:19269`).
+
+Blocul ocupa deci permanent ~100 px stanga-jos, exact unde vine banda de totaluri. Marius: intra
+in `Alte date`, langa analitice — nu ocupa loc cand sectiunea e pliata, ramane accesibil pe orice
+document, iar banda de totaluri ia toata latimea. **Nu se schimba conditia de populare** a
+cursorului si nu se ascunde nimic pe criteriu de moneda; se muta doar locul.
+
+**2. „Motiv" (motivul discountului) se creeaza acum, gol.**
+
+Nu exista azi: zero potriviri in `frm_facturare_articole2` si niciun camp pe `poDate`. E controlul
+nou cerut de reparatia discountului (deciziile 59 / 64 / 66), pe care decizia 66 l-a asezat in banda
+de totaluri, langa discount.
+
+Marius alege sa fie creat acum, ca sa nu se rearanjeze banda a doua oara. Ca sa nu fie un camp
+vizibil care minte, controlul se leaga de o proprietate noua pe `poDate` (`ofacturare_comun.prg`),
+deci valoarea traieste cat sesiunea de editare a documentului. **Nu primeste coloana in baza si nu
+se scrie nicaieri** — persistenta vine odata cu reparatia discountului. Limitare declarata, de
+consemnat ca atare.
+
+**3. Latimea ramasa se imparte proportional pe toate coloanele gridului.**
+
+Azi `grd_factura` se intinde prin `Anchor = 15`, dar coloanele raman la latimile de design, de unde
+spatiul gol de la ~1360 px la 1920 px. **Nu exista niciun mecanism de autofit in suita** — cautare
+exhaustiva pe `ColumnWidth` / `AdjustColumns` / `autofit` in `COMUN\clase\*.vc2` si
+`COMUN\programe\*.prg`; `_grdrow` (`_grd_base.vc2:445`) si `_grdbase` (`_grd_base.vc2:7`) n-au asa
+ceva. Deci e cod nou.
+
+**Preferintele salvate per utilizator nu intervin aici**, contrar capcanei generale din
+`COMUN\docs\capcana_grid_preferinte_utilizator.md`: instanta `Gridextra3` din acest formular are
+`allowgridpreferences = .F.` explicit (`ofacturare.vc2:17172`), iar `restoregridpreferences` si
+`savegridpreferences` sunt amandoua gardate de acea proprietate (`gridextras.vc2:1051-1078` si
+`:1130`). Latimile redistribuite la runtime nu vor fi suprascrise.
+
+Codul nou merge intr-o clasa dintr-un `.prg`, nu ca metoda in `.vcx` (`reguli_lucru.md`, punctul 3);
+formularul doar instantiaza si apeleaza.
+
+
+#### S6 — Test pe fluxul real, formularul unificat
+Headless (`COMUN\docs\depanare_testare_vfp.md`) + UI (`COMUN\docs\testare-ui-vfp.md`), cate un caz
+pe fiecare sursa: lista de preturi, comanda, contract, aviz, retur, transfer, valuta. Comparatie
+directa cu documentul emis pe calea veche: `vanzari`, `vanzari_detalii`, `act`, `rul`, totalurile
+denormalizate, listarea.
+*Depinde de:* S5.
+
+### Etapa II — editarea prin regenerare
+
+#### S7 — Actiunea si garzile
+Actiune noua pe `frm_facturi`, sub tokenul de drepturi existent. Garzi refolosite din
+`COMUN\programe\ofacturare_editare.prg` (`EsteInEFactura:12`, plus luna inchisa, luna curenta,
+`ReferinteDocumenteNota`) — **nu se rescriu**, sunt deja extrase de #6. Plus garzile proprii
+regenerarii: refuz daca documentul are **urmasi**.
+
+**PRECIZAT in runda 14, pe cod** (`docs\cercetare\garda_aviz_facturat.md`): regula exista deja integral
+in Oracle, in **trei** garzi consecutive din `sterge_factura` — factura cu retururi (`TIP = 3`,
+`EXPORT:5452-5462`), **aviz cu factura sau aviz de retur** (`TIP IN (1,2)`, `EXPORT:5466-5476`), si
+factura din aviz ale carei avize-sursa au primit intre timp aviz de retur (`EXPORT:5480-5494`).
+**S7 nu reimplementeaza regula** — o citeste **mai devreme**, read-only, inainte de intrarea in
+formular:
+
+```sql
+select count(*) from vanzari_coresp
+ where sters = 0 and id_vanzare_aviz = :id_vanzare and tip in (1, 2, 3)
+```
+
+plus subinterogarea din garda 3 pentru cazul „factura din aviz". Se interogheaza `VANZARI_CORESP`,
+**nu `VANZARI.FACTURAT`** — `FACTURAT` e derivat si necitit de nicio garda. Garda din `sterge_factura`
+**ramane pe loc ca plasa de siguranta**: nu se muta, nu se slabeste.
+
+**Gol de acoperit, iesit tot in runda 14:** pentru **proforma** (`TIP = 4`, decizia 51) garda **nu
+exista deloc** — `sterge_proforma` (`EXPORT:5610-5635`) e o procedura separata fara nicio verificare,
+iar calea VFP iese din `do_sterge` inainte de restul (`ofacturare_comun.vc2:4707-4719`). Garda simetrica
+ceruta de S5c e **cod nou**, nu reutilizare.
+*Gata cand:* actiunea refuza corect si cu mesaj clar documentele trimise in eFactura, sterse, din
+luna inchisa, referentiate, sau care au urmasi (retur, factura din aviz, factura din proforma) —
+**inainte** de deschiderea formularului, nu ca `ORA-20000` la final.
+*Depinde de:* S6, si de inchiderea perimetrului cu #6 (fisier partajat).
+
+#### S8 — Incarcarea documentului in formular
+
+> **PROIECTAT INTEGRAL in runda 14 — `docs\cercetare\s8_incarcare_document.md` (52 KB, 8 sectiuni).**
+> **Schita de mai jos e corecta ca directie, dar gresita in piese, si nu marunt:**
+> 1. **`completeaza_setari_document(toFactura, .T.)` copiaza 16 proprietati din ~120**
+> (`COMUN\programe\ofacturare_comun.prg:361-411`) si **niciuna de identitate**. Lipsesc serie,
+> numar, data, scadenta, `text_aditional`, `id_facturare`, `id_ruta`, `tip_saft`, `efactura`,
+> `listare_detaliata`, `dataora_exp`, discountul de document, `discount_evidentiat`, `eproforma`,
+> valuta, cursul.
+> 2. **`cursor_retur_document(V_COPIERE = 1)` nu umple documentul, ci selectorul-sursa.** Rezultatul
+> intra in `crsarticole` (gridul din stanga); `crsfactura` se creeaza **gol si ramane gol** —
+> comentariul din cod e explicit (`COMUN\programe\ofacturare.prg:338`, `:455-457`). Transferul se
+> face doar prin `do_adauga_tot` → `do_adauga_articol`, care pentru articolele gestionabile trece
+> **prin dialogul de alegere din stoc**.
+> 3. **`cursor_retur_document` nu intoarce `ID_VANZARE_DET` si nici `TAXCODE`**
+> (`PACK_FACTURARE:3949-4054`). Fara `ID_VANZARE_DET`, cheia de linie presupusa de S8b **nu exista**,
+> iar ruta ieftina `modifica_explicatie_articol` **devine neapelabila** — primul ei parametru *este*
+> `V_ID_VANZARE_DET` (`PACK_FACTURARE:14511-14519`).
+>
+> **Recomandarea centrala:** S8 se construieste pe precedentul care face deja exact asta —
+> `relisteaza_ofacturare_stoc` (`COMUN\programe\ofacturare_stoc.prg:456-742`), care reconstituie
+> `poDate` + cursorul de linii dintr-un document salvat, prin `FACT_VFACTURI` + `FACT_VFACTURI_DETALII`
+> (ambele au `ID_VANZARE_DET` si `TAXCODE`). Canalul final e intrebarea 1 din §8.2 al raportului
+> (*recomandat:* procedura noua `cursor_editare_document`, ca sa nu se schimbe comportamentul copierii).
+>
+> **CORECTIE la raportul S8, facuta de sesiunea principala (runda 14):** raportul lasa deschis (N6,
+> intrebarea 7) daca „`frm_facturare_articole2` (varianta paralela)" intra in perimetru, si recomanda
+> „nu acum". **Premisa e gresita: `frm_facturare_articole2` NU e o varianta paralela de exclus — e
+> PROTOTIPUL pe care se construieste formularul unificat**, conform S1 („se porneste de la prototip",
+> `ofacturare.vc2:15741-19355`). Deci S8 il tinteste pe el, nu pe `frm_facturare_articole`. Faptul ca
+> are `do_adauga_tot` / `do_adauga_articol` proprii, cu logica divergenta (fara testul `llGestionabil`,
+> `ofacturare.vc2:17476`, `:17124`), **nu e un motiv de excludere, e exact driftul din 2017 pe care S2
+> il inchide** — cele doua se unifica, nu se aleg. Partea de tipuri 48/49 din intrebarea 7 **s-a
+> inchis prin decizia 60**: sunt editabile. Intrebarea 7 e deci inchisa integral.
+
+> **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
+> complet al celorlalte initializari „pentru document nou" care trebuie sarite (§2.2).
+
+`completeaza_setari_document` pentru antet + `cursor_retur_document(V_COPIERE = 1)` pentru linii,
+**fara** degradarea de tip din `do_copiaza`. Se incarca in plus, fata de copiere: serie / numar /
+data / scadenta reale, discountul de document (`VANZARI.DISCOUNT`), `discount_evidentiat`, textul
+aditional, datele din `frm_alte_date` (delegat, auto, agent, adresa de facturare), explicatia si
+`taxcode` pe fiecare linie, si legatura cu sursa (`id_comanda`, `id_ctr`, lista de avize din
+`vanzari_coresp`) — ca reemiterea sa reconsume aceeasi sursa.
+**Campul de sursa exista deja** — nu e de adaugat, ci de pastrat vizibil: e `Ct_clb_altele`, cu
+eticheta schimbata pe tip de `do_schimba_explicatia` („Nr. contract” / „Nr. comanda” / „Nr. factura” /
+„Nr. facturi” / „Locatie”, `ofacturare.vc2:9633-9643`), eliminat azi din formular cand
+`gnScadereStoc = 0` si tipul e 1/5/10 fara copiere. La modificare e blocat: schimbarea sursei ar
+insemna alt document, nu o corectie.
+Formularul arata **identic** cu cel de introducere: fara banda de avertizare, fara coloane cu
+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; **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
+Comasarea celor trei actiuni de modificare (G-bis): la confirmare se compara starea din formular cu
+cea incarcata si se alege ruta — `modifica_date_factura` pentru antet, `modifica_explicatie_articol`
+pentru explicatia liniei, regenerare pentru orice atinge sumele, nimic daca nu s-a schimbat nimic.
+Cele trei actiuni vechi de pe `frm_facturi` (`do_modifica`, `do_modifica_explicatie`) se retrag
+abia dupa ce formularul unificat le acopera, nu inainte.
+**PROIECTAT (runda 13) — `docs\cercetare\s8b_rutarea_scrierii.md`. Reteta G-bis e corecta ca directie,
+dar avea un gol nedocumentat, si el schimba forma solutiei.**
+
+- **Cele patru rute NU sunt teste independente, ci un lant cu prioritate — sumele primele.**
+ Motivul e concret: **`modifica_date_factura` nu e singura ruta care scrie cei 14 parametri de antet.**
+ **Sapte din 14** (`id_delegat`, `id_masina`, `id_facturare`, `listare_detaliata`, `dataora_exp`,
+ `id_agent`, `text_aditional`) sunt scrisi **si** de calea normala de emitere, prin `scrie_factura2`,
+ direct din `poDate` — **verificat direct de sesiunea principala** pe apelul de la
+ `COMUN\clase\ofacturare.vc2:14345-14359`. Nu exista doi proprietari ai acestor campuri: e **acelasi
+ obiect `poDate`** citit de ambele cai.
+- **Deci, cand regenerarea porneste, `modifica_date_factura` NU se mai cheama.** Inainte de regenerare
+ ar scrie pe randul care urmeaza sa fie sters — pierdut. Dupa, ar fi a doua scriere pe aceleasi sapte
+ coloane, pe alt `ID_VANZARE`. Regenerarea **este** deja calea de scriere a antetului cand sumele se
+ schimba, nu o cale care trebuie compusa cu alta.
+- **Ordinea rutarii:** (1) s-au schimbat liniile / discountul de document? → **regenerare, gata**;
+ (2) altfel, antet? → `modifica_date_factura`; (3) altfel, doar explicatie de linie? →
+ `modifica_explicatie_articol`; (4) altfel → **nimic**.
+- **Explicatia de linie e transportata gratuit de regenerare**, prin parametrii nativi ai lui
+ `adauga_articol_factura` (`V_EXPLICATIE`, `V_TAXCODE`) — **cu conditia** ca regenerarea sa citeasca
+ din cursorul curent al formularului, nu dintr-un snapshot separat.
+- **Cel mai probabil fals pozitiv al criteriului „deschid si inchid → nicio scriere":** lookup-ul
+ „ultimul delegat / masina al clientului" din `frm_alte_date.Init`
+ (`COMUN\clase\ferestre_cere_date.vc2:3119-3136`). E cod gandit pentru **document nou**. Pe calea de
+ editare ar suprascrie delegatul **incarcat corect din document** cu ultimul folosit de client — deci
+ ori documentul apare „modificat" fara ca nimeni sa fi atins nimic, ori, daca ruleaza inainte de
+ snapshot, **salveaza tacit delegatul gresit**. **S8 trebuie sa-l sara explicit pe calea de editare.**
+- **Comparatia se face pe valori rotunjite la precizia de scriere** (`gnPc` / `gnPPretV` / `gnPCant`),
+ nu pe valoarea binara — altfel rotunjirea singura produce diferente.
+
+**INCHIS, nu de reintrebat (marcaj pus in runda 17).** Punctul de mai jos are raspuns: **decizia 52** — `do_modifica` ramane activ pentru multi-selectie, iar formularul unificat preia doar cazul cu un singur document. Se pastreaza enuntul, nu intrebarea:
+1. **Editarea multipla** — `do_modifica` de azi lucreaza pe multi-selectie, capacitate fara echivalent
+ in formularul unificat. Se accepta pierderea ei la retragere, sau `do_modifica` ramane activ separat
+ exact pentru cazul asta?
+
+**Doua goluri de inchis inainte de implementare (semnalate, nu presupuse):**
+- **Ce canal scrie `serie_act` / `numar_act` / `data_act` / `data_scad` / `id_ruta` / `tip_saft` /
+ `efactura`** pe documentul reemis — **nu apar in `scrie_factura2`**, deci vin pe alt drum. Raspunsul
+ decide daca mai e nevoie de o scriere separata dupa regenerare. **Se inchide in S9.**
+- ~~**`cursor_retur_document` re-deriva pretul la incarcare?**~~ **INCHIS (runda 13): NU** — pretul vine
+ din `VANZARI_DETALII.PRET` stocat, fara `JOIN` catre contract sau politici (`PACK_FACTURARE:3960-4062`,
+ verificat direct). **Mecanismul de detectie e valid.** Detaliul despre rotunjire si `DIFERENTA` — in S10.
+
+*Gata cand:* fiecare din cele patru situatii din tabelul G-bis produce exact scrierile din tabel si
+nimic in plus; in special, deschiderea si inchiderea fara modificari nu scrie nimic.
+*Depinde de:* S8.
+
+#### S8c — Butonul comutator de antet si salvarea separata a antetului
+Decizia 9, proiectata in I. Antetul unui document existent porneste **blocat**; un singur
+`but_modifica` il deschide si isi schimba imaginea in discheta de salvare; a doua apasare cheama
+`modifica_date_factura` si **nu atinge articolele** — exact ce face azi `do_modifica`, dar din
+formularul unificat, dupa care antetul se blocheaza la loc si butonul revine la creion. **Fara nicio
+bifa**: butonul deschide tot antetul, inclusiv serie / numar / data / scadenta; cele patru bife de
+azi nu se transpun. `Termina` ramane salvarea intregului document.
+Se generalizeaza reteta de blocare din `clb_tx_data.dezactiveaza()` / `reactiveaza()`
+(`lb_tx.vc2:521-538`) la containerele de antet care azi nu au niciuna (I), si se aplica **uniform**
+tuturor campurilor de antet — asta e ce face posibila eliminarea bifelor.
+Comutarea imaginii butonului se copiaza din `frm_rulaje.se_modifica_assign` (`rulaje.vc2:4716-4773`):
+o singura instanta `but_modifica`, cu `.cpicturedown` / `.cpictureup` / `.Picture` rescrise impreuna
+si `.Refresh()` — vezi decizia 9 pentru capcana hover-ului.
+**Ce deschide efectiv butonul (decizia 25, verificat pe cod in G-bis).** „Tot antetul” nu inseamna
+ca totul se salveaza pe aceeasi ruta:
+- **cei 14 parametri** — pe loc, prin `modifica_date_factura`. Asta livreaza S8c;
+- **grupul B** (tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi) si
+ **grupul C** (incasare) — **nu au ruta de scriere pe loc**, deci raman **blocate in etapa I**, cu
+ explicatie la hover; se deschid in etapa II, cand modificarea lor marcheaza documentul pentru
+ regenerare;
+- **grupul A** (analiticele) — **editabile** (decizia 72, care rastoarna decizia 26), si la introducere,
+ si la reemitere; nota se reconstruieste uniform pe document.
+
+Deci in etapa I butonul deschide **exact cei 14**, si asta nu e o abatere de la decizia 9, ci
+consecinta ei corecta pe starea de azi a codului: restul campurilor n-ar avea unde sa se scrie.
+*Gata cand:* se poate corecta delegatul unui document emis, salva antetul si inchide formularul,
+**fara nicio scriere in `VANZARI_DETALII` si fara recalcul de sume in note sau rulaje**; se poate
+corecta si data scadentei prin acelasi buton, fara alt control intermediar; iar un document deschis
+si inchis fara a apasa butonul nu produce nicio scriere.
+*Atentie la formularea criteriului:* „nicio scriere in note si rulaje” ar fi un criteriu imposibil —
+schimbarea seriei / numarului / datei propaga coloanele de identitate in `JV2007` si `RUL` prin
+procedura insasi (I-bis). Ce se verifica e ca **nu se ating sumele**, nu ca nu se atinge tabelul.
+*Depinde de:* S8.
+
+#### S9 — Stergerea si reemiterea intr-o singura tranzactie, cu `ID_FACT` pastrat
+Partea grea. Doua lucruri simultan:
+
+**Constrangere de la decizia 35, inainte de orice:** reemiterea **scrie prin `pack_facturare`**, pe acelasi
+drum ca emiterea (`scrie_factura2` → `contabilizeaza_articol`, cu parametrul de cont de la decizia 34).
+`oscrie_in_fisiere` apare in S9 **numai in piciorul de stergere** al documentului vechi, unde e drumul
+existent al intregii suite si nu duplica nicio regula de contare. **Nu se scrie si nu se corecteaza niciun
+rand din `ACT_TEMP` direct din VFP.** Consecinta de secventiere: **S9 nu poate porni inaintea parametrului
+deciziei 34** — nu mai exista varianta „editarea nu cere nimic in pachet".
+
+**VERIFICAT ca decizia 35 e realizabila** (`docs\cercetare\parametru_cont_contabilizeaza_articol.md`,
+sectiunea 1): pe partea Oracle, **a doua emitere a aceluiasi document merge pe cod identic**.
+`scrie_factura2` cheama `initializeaza_date_factura` (`PACK_FACTURARE:1808-1846`) la fiecare apel, iar
+aceasta face `DELETE FROM VANZARI_DETALII_TEMP` (`:1835`) si `nid_act := 0` (`:1836`) — contorul folosit
+de `scrie_nota` / `scrie_discount` / `scrie_tva` la fiecare `INSERT INTO ACT_TEMP` **porneste curat si la
+reemitere**. Nimic din `contabilizeaza_articol`, ramura noua inclusa, nu citeste vreo stare care sa
+presupuna „documentul e nou": variabilele de sesiune sunt **citite**, nu comparate cu o stare anterioara.
+**Singurul obstacol real al regenerarii e in alt pachet** — `PACK_CONTAFIN`, prin `SET_IDFACT` si
+`PK_DOCUMENTE`, exact ce e deja analizat mai jos in acest S9. Adica: „cod separat" inseamna **alta
+procedura, in alt pachet**, nu o a doua ruta de contare — deci **decizia 35 nu e contrazisa**.
+
+- **Tranzactia.** Apelul de stergere (`oscrie_in_fisiere` + `finalizeaza_stergere_nota` +
+ `sterge_factura`) se muta in interiorul tranzactiei deschise de `do_scrie_articole`, inaintea
+ primului `adauga_articol_factura`. Fara `commit` intermediar (`VANZARI_DETALII_TEMP` e GTT
+ `ON COMMIT DELETE ROWS`). La orice eroare, rollback total.
+- **Tripleta de mai sus e si ce face ciclul NEUTRU fata de stoc — nu se simplifica.** `sterge_factura`
+ **nu** reverseaza rulajele. Revenirea stocului vine din `PACK_CONTAFIN.STERGE_DIN_RUL`
+ (`UPDATE RUL SET STERS = 1, ID_UTILS = ..., DATAORAS = ...`,
+ `ff_2026_07_29_03_COMUN_PACK_CONTAFIN.sql:1867-1882`, apelata la `:8473`), la care se ajunge prin
+ `finalizeaza_scriere_act_rul(tnScrieSterge = 2)` ← `oscrie_in_fisiere(2, ...)`. Adica **stocul e
+ derivat** din miscari nesterse, iar marcarea lor `STERS = 1` inchide subiectul — dar **numai daca
+ piciorul de stergere chiar trece prin `oscrie_in_fisiere`**. O implementare care „simplifica" pasul
+ la un apel direct de `sterge_factura` ar lasa rulajele in picioare si reemiterea ar descarca
+ gestiunea **a doua oara**, tacut. Verificat pe sursa pachetului.
+ `docs\cercetare\stoc_la_stergere_si_reemitere.md`.
+- **`ID_FACT`.** Se citeste inainte de stergere (vezi capcana `STERS = 0` din E) si se impune
+ documentului nou, printr-un comutator folosit **numai** de regenerare. `SET_IDFACT` nu se schimba
+ neconditionat — e cod comun intregii suite.
+- **`ID_UTIL` / `DATAORA` (audit de creare, S14).** Acelasi tipar ca la `ID_FACT`: se citesc din
+ documentul vechi **inainte** de stergere si se impun explicit documentului nou — altfel `INSERT
+ INTO VANZARI` de la reemitere le rescrie cu utilizatorul si momentul curente, si „data/utilizatorul
+ crearii" se pierde tacut. Detaliu si recomandare de coloane: S14.
+
+**VERIFICAT — se poate, dar cere TREI schimbari simultane, nu una.** Raport:
+`docs\cercetare\idfact_refolosire_si_documente.md`. Verdict: **DA, cu conditii.**
+
+1. **Varianta comentata din `SET_IDFACT` NU rezolva S9** — nu se reactiveaza.
+ (`PACK_CONTAFIN.pck:3016-3035`) cauta documentul pe `NRACT + SERIE_ACT + DATAACT + ID_CTR` cu
+ `STERS = 0`; dupa soft-delete `STERS` e deja 1, deci **nu-l gaseste** si cade tot pe secventa.
+ In plus e vulnerabila la coliziuni cu un document viitor neinrudit care are aceleasi patru campuri.
+ `ID_FACT`-ul se **citeste explicit inainte de stergere** (VFP il are in cursor) si se **transmite**.
+2. **`SET_IDFACT` are nevoie de o cale de intrare noua, inerta implicit.** Azi **nu exista niciun
+ canal**: `pack_contafin.nIdFact` e scrisa neconditionat de fiecare apel, si nu exista alt global sau
+ parametru de sesiune. Solutia cu suprafata minima: **variabila noua de pachet** („ID_FACT fortat",
+ implicit `NULL`), citita **doar in corpul activ** al lui `SET_IDFACT`, consumata si resetata la prima
+ folosire. **Nu se atinge semnatura `SET_IDFACT(V_GCS)`** — altfel s-ar schimba apelul pentru toti.
+3. **Blocajul real nu e in `SET_IDFACT`, ci in `DOCUMENTE`** — si asta e descoperirea care schimba
+ estimarea. Scrierea de azi (`PACK_CONTAFIN.pck:796-817`) e un **`INSERT` simplu** pe `ID_DOC`, care e
+ **PRIMARY KEY** (`PK_DOCUMENTE`, `fn_script.sql:5192-5198`). Stergerea (`STERGE_DIN_ACT:1835-1855`) e
+ **soft-delete pur** — randul vechi ramane fizic in tabel cu `STERS = 1`. Deci reemiterea cu acelasi
+ `ID_FACT`, cu codul de azi, **arunca `ORA-00001`**. Dovada, nu presupunere.
+ `MERGE`-ul deja comentat (`:818-847`) **nu ajuta**: are doar `WHEN NOT MATCHED`, deci ar ignora tacit
+ randul existent si documentul reemis ar ramane cu `STERS = 1`. E nevoie de **upsert real**, cu
+ `WHEN MATCHED THEN UPDATE SET STERS = 0, ...` pe restul coloanelor de identitate.
+
+**Succesiunea corecta**, in aceeasi tranzactie: citeste `ID_FACT` **si lista sursa** -> sterge documentul
+vechi (soft-delete, ca azi) -> seteaza variabila fortata -> scrie documentul nou pe drumul obisnuit ->
+**remigreaza atasamentele** -> commit doar daca toate au reusit; orice eroare -> rollback total,
+documentul vechi intact.
+
+**DOI PASI ADAUGATI DE S11 (runda 13) — niciunul nu „vine gratis" din drumul normal:**
+1. **Citirea listei sursa INAINTE de stergere, si refurnizarea ei la reemitere.** `VANZARI_CORESP` si
+ `marcheaza_facturat` **se rescriu singure** prin `CASE`-ul pe `ntip` din `finalizeaza_factura` — dar
+ **numai daca** `ntip` si lista sursa (`clistaid` / `clistaid_avize`) sunt refurnizate. Ele traiesc in
+ randurile `VANZARI_CORESP` ale documentului **vechi**, care dupa stergere nu mai sunt disponibile.
+ **Fara acest pas nu apare nicio eroare — corespondenta si `FACTURAT` pur si simplu nu se scriu.**
+ Scriere lipsa silentioasa, exact tipul de defect care trece de o verificare vizuala.
+2. ~~**`UPDATE ATASAMENTE_VANZARI SET id_vanzare = :nou`**~~ — **INLOCUIT de decizia 53 (runda 14):
+ atasamentele NU se remigreaza, se sterg la reemitere.** Documentul reemis porneste curat; PDF-ul se
+ regenereaza la prima listare. Pasul ramane **cod nou**, dar e o **stergere**, nu un `UPDATE`
+ (`STERS = 1`, ca sa ramana consistent cu view-ul `VATASAMENTE_VANZARI`, care filtreaza `b.sters = 0`
+ — vezi S11). Consecinta acceptata explicit de Marius: **urma PDF-ului efectiv trimis clientului
+ dispare din sistem.**
+
+**Suprafata de risc pentru suita**, masurata: **~25-30 cai de apel** — cate o copie a lui
+`COMUN\programe\oscrie_in_fisiere.prg` in fiecare produs ROA, plus trei variante care cheama
+`SCRIE_IN_ACT` direct. Toate converg in acelasi punct, `SET_IDFACT(V_GCS)`. **Garantia e structurala,
+nu prin inspectie:** cu variabila implicit `NULL` si citita strict local, toate cele ~25-30 de cai raman
+identice cu azi — nu trebuie verificat fiecare apelant.
+**Dar `INSERT` -> `MERGE` in `DOCUMENTE` e cod comun apelat de toata suita.** Practic ramura noua e
+inerta (secventa e monoton crescatoare, `WHEN MATCHED` nu se declanseaza niciodata pe drumul normal),
+**dar se testeaza un ciclu normal de scriere in fiecare produs care scrie facturi sau note**, nu doar in
+ROAFACTURARE.
+
+*Gata cand:* o editare care mareste cantitatea peste stocul curent trece (stocul documentului
+initial e eliberat inainte); documentul reemis are **acelasi `ID_FACT`, serie, numar si data** ca
+inainte; **randul din `DOCUMENTE` e acelasi, revenit la `STERS = 0`**, nu unul nou; o eroare la scriere
+lasa documentul initial intact; si un ciclu normal de scriere ramane neschimbat in celelalte produse.
+*Depinde de:* S8b.
+
+#### S10 — Pretul care nu trebuie re-derivat
+Inventarul ramurilor din `adauga_articol_factura` (H) si, unde e nevoie, un mod in care preturile
+vin din formular.
+
+**VERIFICAT (runda 9) — `docs\cercetare\s10_pret_rederivat.md`. Verificarea 3 e inchisa.**
+**Exista exact o ramura care suprascrie pretul: contractul.** Cu `OPT_FACTURARE = 3` (sau `NULL`, care
+se implicit-eaza tot la 3), daca `CTR_ARTICOLE.PRET_UNITAR` e diferit de 0, acea valoare **inlocuieste**
+pretul trimis de VFP — `DECODE(A.PRET_UNITAR, 0, V_PRET_TEMP, A.PRET_UNITAR)` — necondiționat de faptul
+ca linia a fost sau nu atinsa pe ecran. Procedura **nu are nicio notiune de „reemitere"**: la fiecare
+apel cu acelasi `V_ID_CTR` se reface derivarea din contract. Pe celelalte ramuri (implicita, restaurant)
+pretul trimis de VFP e respectat ca atare. **Nu exista niciun parametru sau flag care sa opreasca
+re-derivarea** — deci S10 nu poate „cere pachetului sa nu re-derive", trebuie sa lucreze in jurul
+ramurii de contract. Riscul se materializeaza doar cand pretul din contract s-a schimbat intre emitere
+si reemitere; pana atunci rezultatul e identic si nimeni nu observa. Detaliile pe discount, TVA si curs
+sunt in sectiunile 6 si 7 ale raportului.
+**PROIECTAT (runda 13) — `docs\cercetare\s10_pret_contract_reemitere.md`. Faptul portant al rundei 9
+se reconfirma la sursa, dar problema e mai larga decat „pretul".**
+
+- **Nu e doar pretul: acelasi `SELECT` de pe ramura de contract alimenteaza CINCI valori.**
+ **Verificat direct de sesiunea principala** (`PACK_FACTURARE:5149-5166`): `DECODE(A.PRET_UNITAR, 0,
+ V_PRET_TEMP, A.PRET_UNITAR)` **impreuna cu** `B.PROC_TVAV`, `B.ID_VALUTA`, `A.PRET_CU_TVA` si
+ `C.IN_STOC` intra in aceeasi interogare. Raportul semnalase trei (pret, TVA, valuta); sunt **cinci** —
+ se adauga flagul „preturi cu TVA" si **gestionabilitatea**, care vine din **nomenclatorul curent**,
+ nu din document. **Orice garda trebuie sa acopere tot setul**, nu doar pretul.
+- **Nu exista alt loc care suprascrie pretul mai departe in lant** — `scrie_in_vanzari` copiaza `PRET`
+ neschimbat din `VANZARI_DETALII_TEMP` in `VANZARI_DETALII`.
+- **Divergenta e reala, nu ipotetica:** pe baza de dezvoltare, **3 din 11** linii deja facturate pe
+ contract au azi alt pret in contract decat cel facturat. Esantionul e mic si **nu se extrapoleaza** la
+ productie — dar demonstreaza ca situatia se intampla.
+- **Discountul ramane passthrough** — acolo nu e nicio problema.
+- **Recomandarea raportului: varianta (c) — se avertizeaza si se cere confirmare, cu diferenta
+ afisata.** Satisface literal criteriul „decis explicit, nu accidental", se implementeaza **integral in
+ VFP**, fara sa se atinga `pack_facturare`. Variantele: (a) accepta tacit — respinsa, e exact ce cere
+ criteriul sa nu se intample; (b) blocheaza — mai sigura, dar frustranta daca divergentele sunt dese;
+ (d) ocoleste ramura trimitand `V_ID_CTR = NULL` — **respinsa motivat**, pierde **permanent** legatura
+ `VANZARI_DETALII.ID_CTR`.
+- **„Reemitere identica" nu e garantata uniform:** pe ramurile `ELSE` / restaurant, da; pe **comenzi**
+ esueaza **tare** (eroare, deci vizibila); pe **contract** si pe **aviz (`ntip = 4`)** esueaza **tacit**.
+ Riscul pe aviz **nu fusese semnalat pana acum** ca decizie explicita.
+
+**GOLUL LUI S8b E INCHIS — `cursor_retur_document` NU re-deriva pretul.** Verificat direct de sesiunea
+principala (`PACK_FACTURARE:3960-4062`): pretul vine din **`VANZARI_DETALII.PRET`** stocat, printr-un
+`FROM VANZARI_DETALII A1` fara niciun `JOIN` catre `CTR_ARTICOLE` sau catre politici; `PROC_TVAV` la fel,
+din document. **Deci mecanismul de detectare a schimbarii din S8b e valid** — un document deschis nu
+apare „modificat" din cauza citirii. **Confirmat independent si pe partea VFP** (raportul S10): in
+`ofacturare.prg:266-283`, ramura `Case m.llCopiere` are **prioritate indiferent de tip** — pentru un
+document de contract (`2,6,26,52`) **nu se ajunge deloc** la `cursor_contract` la incarcare. Citirea si
+scrierea sunt guvernate de **cursoare complet diferite, fara cod comun**: riscul de suprascriere tacita
+apare **strict la re-scriere**, niciodata la deschidere. O garda pusa la scriere nu afecteaza citirea si
+nu e afectata de ea.
+> **Dar citirea nu e o copie curata, si asta conteaza pentru S12.** Pretul returnat e
+> `ROUND(A.PRET, nzecimale_pretv) + A.DIFERENTA` (pe valuta: `ROUND(CURS * ROUND(PRET, ...) /
+> MULTIPLICATOR, ...) + DIFERENTA`). Adica **rotunjit la precizia de sesiune si cu `DIFERENTA` pliata
+> inauntru**. La reemitere se trimite inapoi valoarea pliata, deci **impartirea `PRET` / `DIFERENTA` se
+> reface**, nu se conserva. De verificat in S12 ca o reemitere identica reproduce **suma**, chiar daca
+> nu reproduce neaparat aceeasi impartire — si ca `DIFERENTA` nu se acumuleaza la reemiteri repetate.
+
+### RASTURNAT de decizia 54 (Marius, runda 14) — nu garda, ci eliminarea re-derivarii
+
+Cele trei intrebari de mai sus (blocare vs. avertizare; ramura de aviz; masurarea frecventei) **sunt
+inchise, si nu prin alegerea uneia dintre variante — prin respingerea premisei lor.** Formularea lui
+Marius: *„nu inteleg de ce se schimba valorile fata de ce se incarca din factura sursa care se modifica?
+asta este comportamentul pe care il doresc — modific sursa"*.
+
+**Deci:** la reemitere se scriu **valorile din formular** (incarcate din documentul editat), nu se
+reciteste sursa. Nu se cere utilizatorului sa confirme o schimbare pe care n-a cerut-o. Variantele
+(b) si (c) **cad amandoua**; ramane obiectivul (a-invers): re-derivarea, unde exista pe calea de
+reemitere, se **elimina**.
+
+**Si aici e problema reala, spusa pe fata:** runda 9 a stabilit deja ca **„nu exista niciun parametru
+sau flag care sa opreasca re-derivarea"**, iar singura varianta care ocolea ramura — (d), `V_ID_CTR =
+NULL` — a fost **respinsa motivat**, pentru ca pierde permanent legatura `VANZARI_DETALII.ID_CTR`.
+Prin urmare decizia 54 **cere, cel mai probabil, o modificare in `pack_facturare`** (un semnal „nu
+re-deriva, foloseste ce ti-am trimis" pe `adauga_articol_factura`), nu o solutie curat VFP. Asta atinge
+un pachet din `COMUN`, partajat de toata suita — **iar modificarile de pachet se aplica tuturor
+deodata, fara cale de intoarcere prin alegerea de la decizia 49.** Trebuie proiectata ca inerta pentru
+apelantii de azi (implicit = comportamentul actual), exact ca la S4g.
+
+**VERIFICAT in runda 14 — `docs\cercetare\s10_rederivare_pe_calea_reemiterii.md`.** Confirmat pe fisier
+**si** pe DB (`all_source`, corp VALID, `last_ddl_time = 2026-08-09 20:03:50`).
+
+**Se pierd intr-un SINGUR loc:** `adauga_articol_factura`, in `CASE`-ul de la `PF:5052-5220`, adica
+**inainte** de `INSERT INTO VANZARI_DETALII_TEMP` (`PF:5222`). Tot ce urmeaza — copierea temp →
+`VANZARI_DETALII` (`PF:13705-13757`) — e **1:1**, deci „copiaza `PRET` neschimbat" e adevarat dar **nu
+e o protectie**: dauna e amonte de temp.
+
+**RAMURILE CARE RE-DERIVA SUNT TREI, NU UNA. Raportul rundei 9 gresea.**
+
+| valoare | **contract** (2/6/26/52) | **aviz** (`ntip = 4`) | **comenzi** (3/21/28/42/47) | restaurant (45) | `ELSE` |
+|---|---|---|---|---|---|
+| `PRET` | re-derivat din `CTR_ARTICOLE.PRET_UNITAR` daca `<> 0`; temp daca `= 0`; **NULL daca e NULL** (`PF:5149`) | **re-derivat neconditionat** din avizul sursa (`PF:5082`) | temp de facto — `WHERE A.PRET = V_PRET_TEMP` (`PF:5077`) | temp | temp |
+| `PROC_TVAV` | re-derivat din `CRM_POLITICI_PRET_ART` | re-derivat din aviz | re-derivat din `COMENZI_ELEMENTE.PTVA` | derivat din `JTVA_COLOANE` | derivat din `JTVA_COLOANE` pe `ID_JTVA_COLOANA` **din formular** |
+| `ID_VALUTA` | re-derivat | re-derivat | re-derivat | temp | temp |
+| `PRET_CU_TVA` | re-derivat | re-derivat | re-derivat | temp | temp |
+| `IN_STOC` | re-derivat din `NOM_ARTICOLE` | re-derivat | re-derivat | temp | temp |
+
+- **Ramura AVIZ e cea mai agresiva din tot `CASE`-ul** (`PF:5080-5103`): `PRET` se inlocuieste
+ **neconditionat**, nu exista nici `DECODE`, nici `AND A.PRET = V_PRET_TEMP`, **si nu exista bloc
+ `EXCEPTION`**. Un pret modificat pe ecran e inlocuit tacit. In plus **nu filtreaza `A.STERS = 0`**,
+ desi coloana exista — linii sterse ale avizului sursa pot fi citite. Si depinde de `clistaid`, care
+ la reemitere **trebuie repopulata** (leaga direct de pasul 1 adaugat in S9).
+- **Ramura comenzi esueaza tare, nu tacit** — fara `EXCEPTION`, o linie care nu se mai potriveste da
+ **ORA-01403**, vizibila. Mai putin periculoasa, dar tot re-derivare.
+- **Ramura contract are o portita** — `EXCEPTION WHEN NO_DATA_FOUND` (`PF:5167-5185`) pune **toate cele
+ cinci** pe valorile din formular. **Comportamentul cerut de decizia 54 exista deja in cod**, dar
+ numai pe calea de exceptie. Aviz si comenzi **nu au** asa ceva.
+- **Capcana NULL, dedusa din semantica `DECODE`, nerulata:** daca `CTR_ARTICOLE.PRET_UNITAR` e `NULL`
+ (nu `0`), `DECODE` nu potriveste literalul `0` → rezultatul e **NULL**, deci pretul din formular se
+ pierde complet si linia intra cu `PRET` gol. In dev cazul nu apare (27 randuri, 0 NULL) — **ceea ce
+ nu spune nimic despre productie**.
+- **`PROC_TVAV` nu vine din formular pe NICIO ramura** — nu e parametru al procedurii. Pe calea „buna"
+ se deriva din `JTVA_COLOANE` pe `ID_JTVA_COLOANA`-ul trimis de formular, deci reproduce documentul
+ **doar cat timp cota nu s-a schimbat**. La o modificare legala de cota, reemiterea schimba TVA-ul
+ **chiar si pe `ELSE`**.
+- **`IN_STOC` nu ajunge in `VANZARI_DETALII`** — coloana nu exista (verificat pe DB). Traieste doar in
+ temp, unde decide **descarcarea de gestiune**.
+- **Dupa insertul in temp nimic nu mai suprascrie cele cinci valori.** `adauga_diferente_pret` atinge
+ numai `DIFERENTA`, `scrie_factura_avize` numai `CANTITATE`, `scrie_seturi` numai `ID_VANZARE_SET`.
+
+### Cum se implementeaza decizia 54
+
+**Curat VFP nu se poate — confirmat cu dovada pozitiva, nu prin absenta.** Semnatura n-are comutator
+(`PF:4989-5015`, 27 de parametri, toti date de linie); globalele pachetului n-au (`PF:126-212`); poarta
+`CASE`-ului se decide pe `ntip` (care ajunge in `VANZARI.TIP`, deci nu se poate falsifica) si pe
+`CONTRACTE.OPT_FACTURARE` (date de contract, nu parametru). Singurele parghii VFP care ar devia pe
+`NO_DATA_FOUND` sunt `V_ID_CTR = NULL` — **deja respinsa** — si `V_ID_POL = NULL`, care are **exact
+acelasi defect pe alta coloana** (`PF:5258` → `temp.ID_POL` → `PF:13737` → `VANZARI_DETALII.ID_POL`) si
+in plus ar rupe ramura aviz, care potriveste pe `A.ID_POL`. **Notata aici tocmai ca sa nu fie
+redescoperita ca „solutie" intr-o runda urmatoare.**
+
+**Deci decizia 54 cere obligatoriu modificare in `pack_facturare`** — dar mica, si care nu adauga
+comportament nou:
+
+- **Semnalul:** variabila noua de pachet („regenerare in curs"), implicit `0` = comportamentul de azi,
+ scrisa de VFP **dupa** `initializeaza_date_factura` (`ofacturare.vc2:13981`) si inainte de bucla de
+ `adauga_articol_factura`. *Recomandata* fata de un parametru `DEFAULT 0`, din trei motive: se
+ potriveste cu stilul pachetului (deja o punga de stare de sesiune); se scrie o data pe document, nu
+ o data pe linie, in toate produsele; si **punctul de resetare exista deja** —
+ `initializeaza_date_factura` (`PF:1808-1917`) reinitializeaza ~40 de globale si goleste temp
+ (`PF:1835`), deci flag-ul nu poate scapa in documentul urmator.
+- **Ce face:** un `WHEN` nou, **primul** in `CASE`-ul de la `PF:5052`, cu **acelasi corp ca `ELSE`-ul de
+ azi** (`PF:5189-5203`). Nimic inventat — se forteaza ramura care exista deja. **Acopera dintr-o data
+ toate trei ramurile problematice**, fiind in acelasi `CASE`. `INSERT`-ul de la `PF:5222` ramane
+ neatins.
+- **Inert prin constructie** pentru toti apelantii de azi, exact ca la S4g. **Consecinta de livrare:
+ DB inainte de EXE.**
+
+### Trei consecinte de acceptat explicit, nu de descoperit la S12
+
+1. **`IN_STOC` ar veni din formular.** Nu murdareste documentul (coloana nu exista), dar schimba
+ **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
+ exact asta, dar e schimbare de comportament — **se declara, nu se descopera**.
+3. **`PROC_TVAV` ramane derivat, nu preluat.** Reproducerea exacta cere ca S8 sa pastreze
+ `ID_JTVA_COLOANA` **si** ca `JTVA_COLOANE` sa nu se fi schimbat. Daca se cere reproducere exacta si
+ peste o modificare legala de cota, `PROC_TVAV` trebuie sa devina **parametru** — schimbare mai mare
+ decat flag-ul, **de decis separat**.
+
+### Obstacol pentru S9, gasit in treacat
+
+**`VVANZARI_ARTICOLE` nu expune `ID_POL` si nu expune `ID_CTR`** (lista de coloane interogata pe DB) —
+exact cei doi pe care `adauga_articol_factura` ii cere (`V_ID_POL`, `V_ID_CTR`) si pe care
+`VANZARI_DETALII` ii pastreaza. **Reemiterea nu poate folosi acest view ca atare**: ori se completeaza
+view-ul, ori loader-ul citeste direct din `VANZARI_DETALII`. Se leaga de intrebarea 1 din S8 (canalul de
+citire a liniilor) — **un argument in plus pentru varianta (B), procedura noua.**
+
+*Gata cand:* pentru fiecare tip, documentul reemis are **exact valorile din formular** — pret, TVA,
+valuta, flag „preturi cu TVA" — iar o reemitere fara modificari reproduce documentul identic, inclusiv
+dupa ce pretul din contract s-a schimbat intre timp.
+*Depinde de:* S9.
+
+#### S11 — Legaturile care raman pe `ID_VANZARE`
+`ID_FACT`, seria, numarul si data se pastreaza (E, F), deci legaturile prin `ID_FACT` sunt in
+regula. Ramane discontinuitatea pe **`ID_VANZARE`**, care se schimba: `ATASAMENTE_VANZARI`,
+`marcheaza_facturat`, `vanzari_coresp`, si eventualele referinte de incasari / plati.
+De verificat si daca `DOCUMENTE` primeste un al doilea rand pe acelasi `ID_DOC` sau il refoloseste.
+
+**PROIECTAT (runda 13) — `docs\cercetare\s11_legaturi_id_vanzare.md`. Inventarul s-a facut prin
+FK-urile reale din Oracle, nu prin grep — si asta a scos doi consumatori pe care nicio cautare de text
+nu-i gasise.**
+
+- **Premisa centrala, corectata: mecanismul lui #6 NU se mosteneste de S9.** La #6, documentul isi
+ **pastreaza randul** din `VANZARI` — `actualizeaza_vanzari` face `UPDATE ... SET COD = nou,
+ STERS = 0`, deci **`ID_VANZARE` nu se schimba**, doar `COD`, si atasamentele se realiniaza in acelasi
+ gest. La S9, reemiterea merge pe drumul normal de emitere (`INSERT ... RETURNING ID_VANZARE`), deci
+ **rand nou, cheie noua, si `actualizeaza_vanzari` nu se declanseaza deloc.** Tot ce e protejat azi
+ tacit de #6 e **expus** la regenerare. Asta nu era in plan.
+- **Sapte tabele au FK declarat pe `VANZARI.ID_VANZARE`. Doua nu erau in nicio lista:**
+ **`REST_NOTE_PLATA`** (modul restaurant) si **`IPS_VOYAGES_VANZARI`** (modul specific unui client).
+ Clasificate **(A) suspecte** — pachetele lor PL/SQL n-au fost citite integral.
+ **INCHIS de Marius, runda 14 — riscul dispare, si nu prin presupunere.** Intrebat direct, a raspuns:
+ *„daca este vorba despre facturarea voiajelor din ROAACNPRO, acolo nu merge modificarea de genul
+ acesta, ci doar editarea de la #6"*. **Documentele acestor module sunt IN AFARA domeniului
+ regenerabil al #13** — pentru ele ramane calea #6 (modificare pe loc). Pachetele lor **nu mai trebuie
+ citite**. Doua consecinte de dus mai departe: **(a) garda lui S7 trebuie sa le refuze EXPLICIT**, nu
+ doar sa nu le trateze — altfel „in afara domeniului" e o intentie, nu o garantie; **(b)** conditia se
+ declara in S13, la actualizarea `tipuri_documente_facturare.md`.
+- **`ATASAMENTE_VANZARI` — corectie de premisa, in favoarea noastra.** **Nu** sunt documente incarcate
+ de utilizator: sunt **PDF-uri auto-generate la listare** (`poDate.scrieAtasamente()` dupa
+ `export2pdf`; cursorul nu vine din niciun dialog de fisier — cautat explicit, zero potriviri). Deci
+ **nu e pierdere ireparabila**, cum presupusese briefingul. Se rup totusi real: view-ul
+ `VATASAMENTE_VANZARI` filtreaza pe `b.sters = 0`, deci dupa regenerare atasamentele vechi **dispar
+ tacit** din toate interogarile (inclusiv din ROAGEST / ROAIMOB), desi BLOB-ul ramane fizic.
+ ~~**(A) — remigrare printr-un simplu `UPDATE ... SET id_vanzare = :nou`**~~ — **INCHIS altfel,
+ decizia 53 (runda 14): se STERG la reemitere.** Marius a ales a treia varianta, nici remigrare, nici
+ marcaj „versiune inlocuita". Documentul reemis porneste curat. **Consecinta i-a fost spusa explicit
+ si a acceptat-o:** motivatia care sustinea remigrarea — *pastrarea urmei PDF-ului trimis clientului* —
+ **cade odata cu ea**; dupa editare nu mai exista in sistem dovada a ce a primit clientul. Punctul 15
+ se inchide aici.
+- **Incasarile si platile nu sunt afectate — si dovada e structurala, nu statistica:** niciun tabel de
+ incasari/plati n-are FK pe `ID_VANZARE`, si nici referinta text. Se leaga prin **`ID_FACT`**, care se
+ pastreaza. **(C)**, cu dovada dubla.
+- **eFactura, `DOCUMENTE`, listarile, `VANZARI_CANTITATI` — (C)**, toate cheiate pe `ID_FACT` sau
+ rescrise automat.
+
+**INCHISE, nu de reintrebat (marcaj pus in runda 17).** Punctul 1 e transat de cercetarea garzilor din runda 14 (garda exista si e corecta; S7 o muta in pre-flight read-only) — ramane **limitare declarata**. Punctul 2 e rasturnat de **decizia 53**: atasamentul vechi **nu se remigreaza, se sterge**, deci premisa „factura editata ajunge cu PDF-ul vechi" nu se mai produce. Punctul 3 e inchis in runda 14, cu cerinta ca **S7 sa refuze explicit** cele doua tipuri. Se pastreaza ca inventar:
+1. **Editarea unui document care are deja retur emis pe el e azi BLOCATA, nu doar riscanta** —
+ `sterge_factura` arunca `ORA-20000`. Garda e corecta (protejeaza lantul), iar **S7 planifica deja
+ sa semnaleze conditia inainte de intrarea in formular**, nu ca eroare Oracle la final. Ce ramane de
+ decis: se accepta ca **limitare declarata** (utilizatorul sterge intai documentele-copil), sau se
+ vrea alt comportament?
+2. **Atasamentul vechi arata continutul dinainte de editare.** Remigrat pe documentul nou, factura
+ editata ajunge sa aiba atasat PDF-ul **vechi**. De decis daca asta e exact ce se vrea (audit trail),
+ sau daca vechiul ar trebui marcat cumva ca „versiune inlocuita".
+3. **`REST_NOTE_PLATA` / `IPS_VOYAGES_VANZARI`** — de confirmat ca tipurile lor sunt in afara
+ domeniului regenerabil.
+
+*Gata cand:* documentul reemis se regaseste corect in borderoul eFactura, in listari, in atasamente
+si in rapoartele care il cauta dupa numar.
+*Depinde de:* S9.
+
+#### S12 — Test pe fluxul real, regenerarea
+Cate un caz pe fiecare sursa, rulat de doua ori (o data fara modificari — reemitere identica, o data
+cu modificari de cantitate, pret si linii adaugate / sterse). Se verifica: documentul initial
+`sters = 1` cu nota si rulajele lui, documentul nou corect, sursa eliberata **si** reconsumata
+(comanda redevine facturabila si redevine facturata), stocul corect dupa ciclu, totalurile
+denormalizate din `VANZARI`, si ca o reemitere identica produce **exact** aceleasi sume.
+
+**Probe adaugate de runda 13:**
+- **Reemitere repetata de trei ori pe acelasi document** — `DIFERENTA` **nu se acumuleaza**. Motivul:
+ `cursor_retur_document` intoarce pretul deja **rotunjit si cu `DIFERENTA` pliata inauntru** (S10), iar
+ reemiterea trimite inapoi valoarea pliata, deci impartirea `PRET` / `DIFERENTA` se **reface** la
+ fiecare ciclu. Se verifica **suma**, nu impartirea — dar se verifica si ca impartirea nu deriveaza.
+- **„Reemitere identica" nu e garantata uniform** (S10): pe `ELSE` / restaurant da; pe **comenzi**
+ esueaza **tare** (eroare vizibila); pe **contract** si pe **aviz (`ntip = 4`)** esueaza **tacit**.
+ Fiecare din cele patru situatii isi are cazul lui de test, cu rezultatul asteptat **declarat dinainte**
+ — inclusiv cele care trebuie sa dea eroare.
+- **Deschid si inchid fara sa modific nimic → nicio scriere** (S8b), rulat pe un document al unui client
+ **cu activitate recenta** — cazul in care lookup-ul „ultimul delegat / masina" ar polua antetul.
+
+*Depinde de:* S10, S11.
+
+#### S14 — Audit: creare, modificare si stergere pe document
+
+**Cerinta (decizia 63):** pentru fiecare document, sase informatii de audit — data + utilizator
+pentru creare, pentru modificare (daca e cazul) si pentru stergere (daca e cazul).
+
+**Cercetarea s-a terminat** — `docs\cercetare\audit_vanzari_creare_modificare_stergere.md`.
+Verificat pe `all_tab_columns` (`ROA_CENTRAL`, schema live) si pe cod.
+
+**Ce exista deja, pe `VANZARI`:**
+- `ID_UTIL` + `DATAORA` — **creare**, ambele `NOT NULL`, scrise consecvent la fiecare `INSERT`
+ (`PACK_FACTURARE.scrie_in_vanzari`, `EXPORT:13598-13640`, si a doua ruta din
+ `finalizeaza_avize_lucrare`, `EXPORT:14930`). Niciun `UPDATE VANZARI SET ID_UTIL/DATAORA` in tot
+ pachetul (cautare directa, zero rezultate).
+- `ID_UTILS` + `DATAORAS` — **stergere**, nullable, scrise consecvent de `sterge_factura`
+ (`EXPORT:5496-5499`) si `sterge_proforma`.
+- (neceruta, dar arata conventia) `ID_UTILFACT` + `DATA_FACTURAT` — facturare din aviz.
+- Pe `VANZARI_DETALII`: acelasi tipar de creare/stergere, plus `ID_UTIL_VALID` + `DATAORA_VALID`
+ (validare).
+
+**Conventia casei:** o pereche utilizator + data per eveniment. Patru din cele sase informatii
+cerute exista deja si se scriu consecvent.
+
+**Ce lipseste, integral:** nicio coloana de **modificare**, nici pe `VANZARI`, nici pe
+`VANZARI_DETALII`. Interogat explicit `all_tab_columns` cu filtru pe `%MODIF%` — zero rezultate.
+`DATA_ACT` nu e echivalentul: e data contabila, propagata in `ACT`/`DOCUMENTE`/`JV2007`/`RUL`
+(verificat in `modifica_date_factura`, `EXPORT:14439-14500`), nu un marcaj de audit.
+
+**Capcana, si e miezul povestii:** editarea din #13 se face prin stergere + reemitere (S9), iar
+documentul nou se scrie pe **acelasi `INSERT`** ca o creare normala (`scrie_in_vanzari`). Fara un
+pas explicit, `ID_UTIL` / `DATAORA` ale documentului reemis ar deveni tacut utilizatorul si data
+**modificarii**, iar informatia despre creare s-ar pierde — exact ce cere decizia 63 sa nu se
+intample. **Precedentul de rezolvare exista deja in plan, pentru `ID_FACT`** (sectiunea „E.
+`ID_FACT`", linia 762, si S9: se citeste din documentul vechi inainte de stergere si se impune
+celui nou). **Niciun pas echivalent nu e proiectat azi pentru `ID_UTIL` / `DATAORA`** — cautare
+directa in tot planul, zero mentiuni.
+
+**Atenuare, nu solutie:** la regenerare randul vechi ramane cu `STERS = 1` si cu `ID_UTILS` /
+`DATAORAS` completate — iar acea stergere **este** momentul modificarii. Cum `ID_FACT` se pastreaza
+peste regenerare, lantul vechi → nou e parcurgibil, deci o parte din istoric e reconstruibila din
+randurile existente, fara coloane noi. O pereche explicita pe documentul curent ramane insa
+preferabila: se citeste direct, fara parcurgerea lantului.
+
+**Complicatie reala, verificata pe cod livrat de #6:** editarea de linie
+(`COMUN\programe\ofacturare_editare.prg`) scrie `id_utils` / `dataoras` pe `VANZARI_DETALII` si pe
+randuri care **nu sunt sterse** — `ofacturare_editare.prg:492-494` (corect, cu `sters = 1`),
+`:501-505` (odata cu `sters = 0`, pe rand viu) si `:522-525` (pe un rand proaspat inserat). Acolo
+perechea de stergere e folosita ca marcaj „cine a umblat ultima data", nu strict ca „sters de/la".
+**Consecinta:** un raport de audit nu poate citi `ID_UTILS` / `DATAORAS` ca „sters de/la" fara sa
+puna si `STERS` in conditie. `ofacturare_editare.prg` e perimetrul lui #6, in lucru — semnalat aici,
+neatins.
+
+**Recomandare (de confirmat, nu decisa):**
+1. **O singura pereche noua pe `VANZARI`**, urmand conventia casei — nume propus
+ `ID_UTILM` / `DATAORAM` (utilizator si data ultimei modificari). Numele e de confirmat.
+2. **La regenerare (S9): `ID_UTIL` / `DATAORA` se transporta din documentul vechi in cel nou**,
+ exact ca `ID_FACT` — vezi nota adaugata la S9. Perechea noua de modificare primeste utilizatorul
+ curent si `sysdate`. Fara acest pas, creare si modificare se suprapun.
+3. **Perechea de stergere nu are nevoie de nimic** — exista si e scrisa consecvent.
+4. **Cere migrare de DB** (`ALTER TABLE` pe `VANZARI`) — **DB inainte de EXE**, ca la S10. Scriptul
+ intra in `D:\ROA\DATABASE\SCRIPTURI_CLAR\`, `versiune_db.txt` se bumpeaza.
+
+**De decis cu Marius — AMBELE INCHISE prin decizia 65 (runda 16):**
+- **(a)** Auditul e cerut numai pe antet (`VANZARI`) sau si pe linii (`VANZARI_DETALII`)? **Raspuns
+ prin deductie, nu spus explicit de Marius:** locul de afisare ales de el e gridul din `frm_facturi`,
+ care listeaza **documente** — deci auditul e pe **antet**.
+- **(b)** Se afiseaza undeva in interfata (formular / lista), sau ramane doar pentru interogare?
+ **Da, se afiseaza** — in **gridul din `frm_facturi`**, nu in formularul facturii propriu-zise.
+ Prim pas de implementare: inventarul acelui grid, posibil sa existe deja coloane de audit.
+
+*Gata cand:* documentul reemis pastreaza `ID_UTIL` / `DATAORA` ale creatiei originale; perechea noua
+de modificare e completata la fiecare regenerare, cu utilizatorul si momentul curente; perechea de
+stergere ramane neschimbata fata de azi; migrarea DB e aplicata inainte de EXE.
+*Depinde de:* S9.
+
+#### S13 — Diff, review, changelog, documentatie
+
+**Atentie: S13 NU e momentul in care se face review-ul.** Conform metodei de executie, **fiecare story
+isi are propriile teste, propriul diff si propriul code review, inainte de commit-ul ei** — S13 nu
+strange la final ce n-a fost revizuit pe parcurs. Ce ramane aici e **inchiderea**, adica exact ce nu se
+poate face per story:
+
+- **Review de ansamblu**, pe suma povestilor: coerenta intre ele, cai ramase orfane, cod mort din
+ fluxul vechi care trebuia retras si n-a fost, si verificarea ca alegerea de la decizia 49 chiar
+ functioneaza in ambele sensuri.
+- **Changelog** `:nou:`, cu mentiunile declarate explicit pe parcurs: asimetria `do_modifica`
+ corectata prin recalculul la cerere (decizia 45), si faptul ca `do_modifica` ramane activ pentru
+ multi-selectie (decizia 52).
+- **Documentatie**: `COMUN\docs\tipuri_documente_facturare.md` — ce tipuri sunt regenerabile si ce
+ tipuri sunt **declarate explicit ca neacoperite** (48/49 si `frm_facturare_articole2`, daca se merge
+ pe recomandarea din S8), plus confirmarea din S11 pentru `REST_NOTE_PLATA` si `IPS_VOYAGES_VANZARI`.
+- **Rularea suitei complete** — toate testele scrise per story, la un loc, nu doar cele ale ultimei
+ povesti.
+- **Commit-urile finale**, in **ambele** repo-uri (ROAFACTURARE si COMUN), dupa aprobare.
+
+---
+
+## Riscuri
+
+- ~~**Cel mai mare: perimetrul comun cu #6.**~~ **Inchis prin decizia 30** — implementarea lui #13
+ incepe dupa terminarea lui #6, deci nu exista doi scriitori simultan pe `ofacturare_comun.vc2` /
+ `ofacturare_editare.prg`. Riscul revine doar daca ordinea se schimba.
+- ~~**Riscul „cod nou in `pack_facturare`" e evitat prin constructie (decizia 27-bis).**~~ **Caduc dupa
+ deciziile 34 si 35, si riscul revine ca risc principal.** Politica tehnica per `SCC` si scrierea in
+ `CRM_POLITICI_PRET_ART` nu se mai fac — deci cade si riscul ca o politica tehnica sa apara in
+ `caut_politici_curente_util()`. In locul lui: **`pack_facturare` se modifica** (parametru de cont +
+ ramura fara politica in `contabilizeaza_articol`), iar pachetul e **comun intregii suite** — ROACONT,
+ ROAGEST, ROACONTRACTE, ROAAUTO, ROAACNPRO. Mitigarea e structurala, nu prin inspectie: parametru
+ **`DEFAULT NULL` la finalul listei** si ramura inerta cand lipseste, astfel incat apelantii existenti
+ sa fie identici cu azi.
+ **MASURAT — `docs\cercetare\suprafata_regresie_contabilizeaza_articol.md`. Riscul e mai mic decat parea.**
+ `contabilizeaza_articol` are **trei apelanti, toti interni pachetului**, toti pozitionali cu acelasi
+ singur argument — **zero apelanti externi, nici PL/SQL, nici VFP, in niciunul din cele sapte produse**.
+ `adauga_articol_factura` e apelata **pozitional peste tot**, niciodata cu notatie pe nume (`=>`), iar
+ cele sapte copii `COMUN\clase\ofacturare.vc2` sunt **acelasi sit de apel duplicat**, nu sapte
+ implementari care ar putea diverge: fisierele difera intre ele (patru variante distincte pe MD5), dar
+ **textul apelului e identic cuvant cu cuvant**, doar offsetul de linie difera. Exista in plus doua
+ implementari proprii reale — ROAGEST (`Programe\ofactureaza.prg:264`) si ramura `_deviz` din ROAAUTO /
+ ROAACNPRO.
+ **Precedentul e activ, nu teoretic:** ROAGEST apeleaza azi `adauga_articol_factura` cu **24 din 25 de
+ parametri**, omitand `V_TAXCODE` si `V_LOT` tocmai pentru ca au `DEFAULT NULL`. Tiparul propus e deja
+ in uz in productie.
+ **Ce ramane:** toate cele **sapte** produse emit efectiv prin acest pachet, deci aria de regresie e
+ toata suita chiar daca niciun apelant nu se modifica.
+- ~~**Anomalie preexistenta: `scrie_factura2` apelata cu 16 din 17 parametri.**~~ **INCHISA — fals
+ pozitiv, nu intra ca risc.** `oExecuta` (`COMUN\programe\oproceduri_comune.prg:121-159`) deleaga la
+ `oExecute` (`:173-504`), care face `SQLExec(lnHandle, lcSql, lcCursor)` (`:330`) — **textul SQL nu e
+ rescris**, deci al 17-lea parametru chiar n-are placeholder. Explicatia e tiparul cunoscut al
+ driverului ODBC Oracle: cand ultimul parametru declarat e un `REF CURSOR OUT`, driverul il ia din
+ catalog, nu din textul apelului, si intoarce randurile ca *result set* — captat exact de al treilea
+ argument al lui `SQLExec`. *Nuanta de pastrat:* mecanismul din interiorul driverului **nu poate fi
+ confirmat din codebase**, e verificabil doar prin comportament; dovada e indirecta, dar consistenta —
+ acelasi tipar in toate cele patru situri, neschimbat de la `v 2.0.13` la `v 2.0.93`, iar ecranul de
+ verificare depinde de acel cursor populat la fiecare emitere, deci un apel esuat s-ar fi vazut demult.
+- **Decizia 35 leaga etapa II de aceeasi modificare de pachet.** Editarea prin regenerare nu mai are cale
+ proprie (canalul `oscrie_in_fisiere` e respins ca al doilea cod de contare), deci **un blocaj pe
+ parametrul deciziei 34 blocheaza si S9-S12**, nu doar etapa I. In schimb dispare riscul de divergenta
+ intre regula de contare de la emitere si cea de la editare.
+- **`ofacturare.vc2` e in COMUN si are 843 KB / 25 de clase**, folosite de toata suita. Formularul
+ vechi trebuie sa ramana functional pana cand cel nou acopera toate tipurile — deci comutator, nu
+ inlocuire.
+- **`ID_FACT` pastrat cere atingerea unui punct comun intregii suite.** `SET_IDFACT` e in
+ `PACK_CONTAFIN` si e chemat de fiecare scriere de note din toate produsele ROA. Comutatorul din S9
+ trebuie sa fie inert pentru toate celelalte cai; altfel regresia nu e in ROAFACTURARE, ci peste tot.
+- **Formularul identic la introducere si la modificare taie o plasa de siguranta.** Decizia 9 o repune
+ **doar pe antet** — butonul protejeaza campurile de antet, nu si liniile. Pe articole nu exista niciun
+ semnal ca modificarea va sterge si va rescrie documentul; confirmarea de la `Termina` ramane
+ singurul moment in care se poate spune ce urmeaza sa se intample. De formulat cu grija.
+- **Ascunderea datei de curs poate lasa un document fara curs corectabil.** `poDate.zi_curs` se
+ trimite neconditionat catre cursoarele de articole; daca lipseste cursul pentru acea zi, Oracle da
+ eroarea 20005 si se deschide formularul de curs — dar utilizatorul nu mai are unde sa corecteze data
+ daca i-am ascuns campul. Regula din M trebuie sa aduca inapoi campul in exact acest caz.
+- **Sectiunea pliata ascunde campuri care schimba documentul.** Analiticele si datele de incasare
+ intra sub un panou inchis implicit. Daca un camp obligatoriu pe un anumit tip ajunge acolo,
+ utilizatorul primeste eroarea fara sa vada campul. Panoul trebuie sa se deschida singur cand
+ contine un camp necompletat si obligatoriu, si sa arate in antet ca are ceva completat.
+- **Mutarea `frm_alte_date` muta si alocarea de numere.** Bonul fiscal, POS-ul si chitanta primesc
+ numar din masina de stari a incasarii. Daca ea ajunge sa ruleze la deschiderea formularului in loc
+ de la alegerea tipului de incasare, se aloca numere pentru documente care nu se mai emit.
+- **`S3c` si `S4c` ating cod comun.** Parametrizarea sursei atinge `factureaza` (toata suita), iar
+ discountul editabil atinge listarile si eventual eFactura. Fiecare merge separat, cu regresie
+ proprie.
+- **Reemiterea nu e idempotenta prin constructie.** Daca la reemitere pretul se re-deriva (H) sau
+ cursul valutar al zilei difera, documentul "nemodificat" iese cu alte sume decat originalul.
+ Testul din S12 (reemitere identica) exista tocmai ca sa prinda asta.
+- **`verifica_total_document`** (`PACK_FACTURARE:16009+`) insereaza automat o linie de corectie cand
+ totalul difera de suma notelor. La regenerari repetate trebuie confirmat ca nu se acumuleaza —
+ aceeasi intrebare ca S7 din #6.
+- **Cautarea in linie schimba un obicei.** Utilizatorii care lucreaza azi cu gridul de articole
+ vizibil si filtrare locala pierd vederea de ansamblu. Merita verificat pe un client inainte de a
+ scoate definitiv gridul vechi.
+
+## Dependente
+
+- **#7 (pret cu TVA pe linie)** — flagul `pret_cu_tva` pe linie apare in gridul unificat; se
+ pastreaza comportamentul stabilit acolo.
+- **#12 (nomenclator ca lista de preturi)** — S4 construieste cautarea in linie peste politici de
+ preturi; daca #12 muta pretul in nomenclator, S4 se rescrie.
+- **#16** — bug-ul de focus / renumerotare la revenirea din cursul valutar. Confirmat ca apare **dupa**
+ ce antetul s-a inchis si s-a eliberat (`ofacturare.prg:248`), la recuperarea erorii Oracle 20005.
+ In formularul unificat nu mai exista un antet inchis la care sa te intorci, deci **mecanismul lui
+ dispare** — de confirmat in S4d, nu de presupus.
+- **#6** — **dependenta de calendar, nu de perimetru** (decizia 30): implementarea lui #13 incepe
+ dupa ce #6 se termina. Proiectarea si cercetarea merg mai departe in paralel.
+
+## Preconditii de mediu
+
+- Orice DDL / modificare `PACK_FACTURARE`: sursa de referinta e `MARIUSM_AUTO` pe `ROA_CENTRAL`,
+ nu productia (`COMUN\docs\scripturi-migrare-db.md`). Scripturi nivel Oracle 10.2, CRLF,
+ idempotente, `versiune_db.txt` actualizat.
+- Sursa completa `PACK_FACTURARE` nu e in working copy; copia pe disc e
+ `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql` (16 948 linii),
+ cu alta numerotare decat exportul din baza.
+- Editarile pe `.vc2` / `.sc2` trec prin `git_sync.ps1` + `txt2vcx.ps1`, cu atentie la
+ `COMUN\docs\conventie_encoding_cp1252.md` (diacriticele din `.vc2` sunt cp1250 — vezi si memoria
+ proiectului).
diff --git a/docs/plan_index.md b/docs/plan_index.md
index e023bc7..a67e621 100644
--- a/docs/plan_index.md
+++ b/docs/plan_index.md
@@ -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 | 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 in #6. Planul a fost sters la curatenie; istoricul e in `progres.md` |
| — | #6 — editare factura emisa | mediu | `omodificari.vc2` (COMUN) + `PACK_FACTURARE` | **INCHIS** 20.08.2026 (r18026, changelog 2.11.15). Planul a fost sters la curatenie; istoricul — inclusiv cele 2 esecuri ramase pe „factura din aviz" din S8 — e in `progres.md` |
-| 1 | [#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` |
+| 1 | [#13 — formular unificat + editare prin regenerare](plan_13_unificare_formular_facturare.md) | **mare** | `ofacturare.vc2` + `ofacturare.prg` + `PACK_FACTURARE` (COMUN) | **INCHIS ca plan (08.09.2026)**, pe branch `plan13-s2` (ROAFACTURARE + COMUN), nemerge-uit si netestat manual; ce ramane sunt datorii. Stare curenta: `handoff_reluare_13_b13.md`, `handoff_plan13_executie_continua.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** |
diff --git a/docs/progres.md b/docs/progres.md
index e320c33..100ead6 100644
--- a/docs/progres.md
+++ b/docs/progres.md
@@ -1,10 +1,37 @@
-# Progres implementare — ROAFACTURARE, punctele 6, 7, 8 (10, 11, 12 amanate)
+# Progres implementare — ROAFACTURARE, punctele 6, 7, 8, 13 (10, 11, 12 amanate)
**Fisierul curent de stare.** Orice sesiune il citeste primul si il actualizeaza inainte sa se
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: **19.08.2026**.
+Ultima actualizare: **21.08.2026**.
+
+> **RUNDA 21.08.2026 — #13 S2 implementata si comisa pe branch.**
+> Cerere Marius, aprobata azi: **fara teste manuale, commit pe branch, continuare in alta sesiune.**
+>
+> **Ce s-a schimbat**: `COMUN\programe\ofacturare.prg` — procedura duplicata `factureaza2` (fork mort
+> din 2017, zero utilizatori reali) a fost stearsa; alegerea formularului se face acum in
+> `factureaza`, dupa flagul `Private plFacturareNoua`. `Clase\ofundal_facturare.vc2` — butoane noi
+> `Page2.Cw10` „Facturare (nou)" (4 optiuni: lista de preturi, contract, comanda, aviz) si
+> `Page3.Cw5` „Avize (nou)" (4 optiuni), ambele seteaza `plFacturareNoua` si deschid
+> `frm_facturare_articole2`.
+>
+> **Decizia 67** (Marius, 20.08.2026): intrare separata in meniu, nu comutator/dialog; ambele cai
+> facturare vechi si noua raman accesibile simultan. Perimetru: vanzarile din stoc (`Cw5..Cw9` ->
+> `initializeaza_vanzare_din_stoc`) **nu** trec prin `factureaza` — raman in afara #13.
+>
+> **NETESTAT MANUAL** — decizia explicita a lui Marius, 21.08.2026. Ramane datorie de verificat cel
+> tarziu la S6 (test pe flux real, planificat dupa S5).
+>
+> **Commis pe branch `plan13-s2`** in ambele repo-uri (ROAFACTURARE + COMUN), **fara SVN** — SVN
+> ramane neatins pana la aprobarea finala si testele manuale. Detalii si hash-uri:
+> `docs\handoff_13_s2.md`.
+>
+> **Urmatoarea story: S3** — portarea logicii de antet in formularul unificat.
+>
+> **Capcana platita**: FoxBin2Prg ordoneaza obiectele si metodele **ASCII-lexicografic**, nu numeric —
+> `Cw10` cade intre `Cw1` si `Cw2` in textul `.vc2`, nu dupa `Cw9`. De verificat cu `vfp_symbols.ps1`
+> inainte de orice cautare pe pozitie in fisier.
> **RUNDA 19.08.2026 — butoanele de linie trec pe butoanele laterale ale grid-ului de articole.**
> Cerere Marius, executata si testata; **fara commit**.
@@ -2326,26 +2353,26 @@ Ramase: partea VFP a punctului 6 si intrarea de changelog pentru runda 6 (nu exi
livrare nu sunt surse de stare pentru ce e in Oracle. Starea se citeste din `VERSIUNE` +
`ALL_SOURCE`, prin diff, inainte de a re-aplica ceva.
- Ramane valabila interdictia: **nu se re-aplica `ff_2026_08_20_01`** — ar sterge punctul 6.
-
-## Runda 6 punctul 6 + runda 7 (sincronizare) - 20.08.2026, seara
-
-Starea completa, cu inventar pe `fisier:linie`, ce s-a stabilit si ce e in lucru:
-**`docs\handoff_r6_r7_sincronizare.md`**. Pe scurt:
-
-- **Punctul 6 (explicatie TVA in `frm_facturi`): TERMINAT**, write-back verificat prin
- reconversie (0 linii diferenta, md5 identic), probat pe ecran de Marius de doua ori.
- Filtrul final al listei: `id_jtva_coloana > 0 AND afisat > 0 AND jv = 1 AND cota_tva = `. Pe date (`vjtva_coloane`, `MARIUSM_AUTO`): `afisat = 0` sunt liniile de TVA,
- `afisat = 1` bazele, `afisat = 2` neimpozabilele; `jv = 1` tine afara explicatiile de
- achizitie, care altfel treceau de garda `FACT-029` fiindca au aceeasi cota.
-- **Runda 7, in lucru**: sincronizarea articole-rulaje porneste doar din buton (se scoate
- declansarea de la salvare, `omodificari.vc2:14484-14494`), si `AplicaModificareTrul`
- (`ofacturare_editare.prg:924`) scrie si `pretv`/`tvav`, nu doar `pretvtva`.
- **Perimetru fixat de Marius: doar preturi, nu si `valoarev`/`valtvav`/`valoarevcTVA`** -
- sincronizarea e intre cantitate si preturi. Ramane de raspuns, ca fapt, cine recalculeaza
- acele valori dupa sincronizare.
-- **Nimic nu e comis** - decizia lui Marius e un singur commit, dupa ce sunt gata toate trei.
-- `roafacturare.PJT`/`.PJX`/`.exe` apar modificate: zgomot din sesiunea lui de VFP, se lasa asa.
+
+## Runda 6 punctul 6 + runda 7 (sincronizare) - 20.08.2026, seara
+
+Starea completa, cu inventar pe `fisier:linie`, ce s-a stabilit si ce e in lucru:
+**`docs\handoff_r6_r7_sincronizare.md`**. Pe scurt:
+
+- **Punctul 6 (explicatie TVA in `frm_facturi`): TERMINAT**, write-back verificat prin
+ reconversie (0 linii diferenta, md5 identic), probat pe ecran de Marius de doua ori.
+ Filtrul final al listei: `id_jtva_coloana > 0 AND afisat > 0 AND jv = 1 AND cota_tva = `. Pe date (`vjtva_coloane`, `MARIUSM_AUTO`): `afisat = 0` sunt liniile de TVA,
+ `afisat = 1` bazele, `afisat = 2` neimpozabilele; `jv = 1` tine afara explicatiile de
+ achizitie, care altfel treceau de garda `FACT-029` fiindca au aceeasi cota.
+- **Runda 7, in lucru**: sincronizarea articole-rulaje porneste doar din buton (se scoate
+ declansarea de la salvare, `omodificari.vc2:14484-14494`), si `AplicaModificareTrul`
+ (`ofacturare_editare.prg:924`) scrie si `pretv`/`tvav`, nu doar `pretvtva`.
+ **Perimetru fixat de Marius: doar preturi, nu si `valoarev`/`valtvav`/`valoarevcTVA`** -
+ sincronizarea e intre cantitate si preturi. Ramane de raspuns, ca fapt, cine recalculeaza
+ acele valori dupa sincronizare.
+- **Nimic nu e comis** - decizia lui Marius e un singur commit, dupa ce sunt gata toate trei.
+- `roafacturare.PJT`/`.PJX`/`.exe` apar modificate: zgomot din sesiunea lui de VFP, se lasa asa.
### Runda 7 - terminata, 20.08.2026, 22:40
diff --git a/docs/sabloane/README_sablon_vcx.md b/docs/sabloane/README_sablon_vcx.md
new file mode 100644
index 0000000..c80c845
--- /dev/null
+++ b/docs/sabloane/README_sablon_vcx.md
@@ -0,0 +1,150 @@
+# Sablon `.vc2` gol — pornire pentru o biblioteca de clase noua
+
+`sablon_vcx_gol.vc2` e punctul de plecare cand trebuie creata o biblioteca `.vcx` noua in
+proiect. Exista pentru ca `txt2vcx.ps1` **refuza permanent** sa creeze un binar `.vcx`
+inexistent (`txt2vcx.ps1:203-206`, garda nu verifica provenienta binarului, doar existenta lui) —
+deci fluxul text->binar nu poate produce singur un `.vcx` nou de la zero. Solutia e sa pornesti
+de la un binar-purtator **copiat**, peste care aplici acest text.
+
+Continut: antetul FoxBin2Prg (6 linii, obligatoriu identic) + **o singura clasa-exemplu
+minimala** (`AS custom`, fara obiecte-copil). Am ales varianta cu o clasa, nu biblioteca goala
+de-a dreptul, pentru ca n-am gasit nicaieri in proiect un `.vcx` cu 0 clase de folosit ca
+referinta si n-am vrut sa presupun formatul text al unei biblioteci goale fara sa-l vad — o clasa
+`custom` fara copii insa exista deja ca tipar verificat (`COMUN\clase\_baza.vc2:114-121`, clasa
+`_custom`) si a fost **confirmata printr-un test complet text->binar->text in izolare** (vezi mai
+jos), deci e alegerea provata, nu doar plauzibila.
+
+## Procedura, pas cu pas
+
+### 1. Alege binarul-purtator
+
+Trebuie sa fie o pereche `.vcx` + `.vct` **existenta** (ambele — `.vct` e memo-ul cu proprietatile
+lungi/codul; fara el binarul nu se deschide). Nu presupune care e cea mai mica — verifica:
+
+```
+ls -la Clase/*.vcx Clase/*.vct
+```
+
+Alege perechea cu cel mai mic `.vcx`. Nu conteaza ce clase contine acum — le stergi la pasul 3.
+
+### 2. Copiaza si redenumeste
+
+```
+cp Clase/.vcx Clase/.vcx
+cp Clase/.vct Clase/.vct
+```
+
+Ambele comenzi, nu doar `.vcx` — un `.vcx` fara `.vct` pereche e un binar corupt pentru VFP.
+
+### 3. Aplica sablonul si inlocuieste
+
+```
+cp docs/sabloane/sablon_vcx_gol.vc2 Clase/.vc2
+```
+
+In fisierul copiat, inlocuieste **toate** aparitiile:
+
+- `SourceFile="__NUME_BIBLIOTECA__.vcx"` -> `SourceFile=".vcx"` (trebuie sa fie
+ exact numele fisierului `.vcx` de la pasul 2, cu tot cu extensie).
+- `DEFINE CLASS __NumeClasaExemplu__ AS custom` -> numele si clasa-parinte reala dorita. Poti
+ schimba si baseclass-ul (`AS custom` -> ex. `AS _frmbase OF "_frm_base.vcx"` pentru un formular)
+ si adauga `ADD OBJECT` / metode dupa nevoie — respecta constrangerile de mai jos.
+- `Name = "__NumeClasaExemplu__"` (in blocul `*`) -> **acelasi** nume ca la
+ `DEFINE CLASS`, cele doua trebuie sa coincida.
+
+Spre deosebire de fluxul folosit la crearea lui `Clase\ofacturare_util.vcx`
+(`docs\nota_s8b_vcx_util.md`), care a luat antetul dintr-o conversie reala ca sa nu-l inventeze,
+**antetul acestui sablon e deja verificat printr-un test text->binar->text complet** (mai jos) —
+nu mai trebuie reconfirmat printr-o conversie separata inainte de folosire, doar `SourceFile`
+trebuie sa corespunda numelui ales la pasul 2.
+
+### 4. Write-back
+
+```
+powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\txt2vcx.ps1 `
+ -TextFile 'D:\ROA\ROAFACTURARE\Clase\.vc2' `
+ -ProjectRoot D:\ROA\ROAFACTURARE -CacheRoot D:\ROA\ROAFACTURARE
+```
+
+Fara `-Force`, fara `-NoVerify` (fidelity check-ul trebuie sa treaca real). Adauga
+`-AllowComun` **doar** daca `.vcx` ajunge sub `COMUN\`.
+
+### 5. Dovada de sincronizare — pe continut, nu pe mtime
+
+`txt2vcx.ps1` rescrie mtime-ul textului la refresh de cache, deci mtime-ul egal nu dovedeste
+nimic. Reconverteste binarul proaspat scris intr-un cache **izolat** (diferit de `ProjectRoot`,
+altfel `vcx2txt.ps1` isi poate sterge singur binarul sursa — vezi capcana documentata in
+`docs\nota_s8b_vcx_util.md`, sectiunea "Conversie text") si compara pe octeti:
+
+```
+powershell -ExecutionPolicy Bypass -File D:\ROA\UTIL\foxbin2prg\vcx2txt.ps1 `
+ -Source 'D:\ROA\ROAFACTURARE\Clase\.vcx' `
+ -ProjectRoot D:\ROA\ROAFACTURARE -CacheRoot ''
+
+diff Clase/.vc2 /Clase/.vc2
+```
+
+Zero diferente = dovada reala. Orice diferenta inseamna ca binarul din proiect nu reflecta
+textul din arbore.
+
+### 6. Verificari de integritate
+
+```
+grep -c 'ADD OBJECT' Clase/.vc2
+grep -c 'OBJECTDATA:' Clase/.vc2
+```
+
+Trebuie sa fie **egale**. Pentru CRLF si diacritice, vezi `COMUN\docs\flux-editare-vfp-text.md`
+si memoria de proiect despre editarea `.vc2` in cp1250 (`Edit`/`sed -i` corup octetii non-ASCII —
+scrie orice modificare text cu un script Python pe disc, `latin-1`/`cp1250` passthrough, CRLF
+explicit, niciodata `sed -i` sau `python -c`).
+
+### 7. `.pjx` ramane manual
+
+`.pjx` nu e editabil din text (cf. `CLAUDE.md` proiect). `Clase\.vcx` trebuie adaugat
+manual in `roafacturare.pjx` (Project Manager > Classes > Add) — dar **doar** cand ai nevoie de
+Build/Rebuild pentru EXE. Nu e necesar pentru o proba cu `vfp9.exe` + `DO roafacturare.prg`, unde
+`SET CLASSLIB` (pasul 8) rezolva clasa prin `SET PATH`.
+
+### 8. Inregistrare in `roafacturare.prg`
+
+Biblioteca trebuie inregistrata ca sa fie vazuta de aplicatie. Exemplu deja existent in fisier,
+langa care se adauga o linie similara pentru biblioteca noua (`Programe\roafacturare.prg:137-139`):
+
+```
+SET CLASSLIB TO ocriterii.vcx ADDITIVE
+SET CLASSLIB TO ofacturare_util.vcx ADDITIVE
+Set Classlib To ctl32_statusbar.vcx Additive
+```
+
+`Clase\` e deja pe `SET PATH` (`Programe\roafacturare.prg:89`), deci fara cale completa. Aceasta
+editare **nu e facuta automat de acest sablon** — se face separat, cu aprobare, cand biblioteca
+noua chiar trebuie incarcata de aplicatie.
+
+## Constrangeri FoxBin2Prg de retinut (au picat fidelity check-ul in trecut)
+
+- `ADD OBJECT` la nivelul unei clase sunt ordonate **ASCII/colationat case-insensitive** pe
+ `ObjPath` (ex. `Cw10` intre `Cw1` si `Cw2`), inclusiv obiectele de top-nivel.
+- Proprietatile in interiorul unui bloc `ADD OBJECT` / `*` sunt in **ordine
+ alfabetica**.
+- **Ultima proprietate dintr-un bloc nu are `, ;`** la final (vezi ultima linie din blocul
+ `ADD OBJECT` din sablon — n-are virgula).
+- Numarul de `ADD OBJECT` == numarul de `*< OBJECTDATA:` (0 = 0 in sablonul de baza).
+- Liniile goale din corpul unui `PROCEDURE`/inainte de un `PROCEDURE` la nivel de clasa se
+ indenteaza cu un TAB; liniile goale **dintre blocuri `ADD OBJECT` consecutive** raman
+ neindentate (verificat direct pe text regenerat, `docs\nota_s8b_vcx_util.md` punctul 3).
+- Encoding **cp1250** pentru diacritice, CRLF (`\r\n`) pe fiecare linie, inclusiv ultima
+ (`ENDDEFINE\r\n`, fara linie goala dupa la finalul fisierului).
+
+## Ce s-a probat si cum
+
+Test complet text -> binar -> text, **izolat in scratchpad**, fara sa atinga arborele
+`D:\ROA\ROAFACTURARE`: copiat un binar-purtator existent intr-un proiect-fals in scratchpad,
+aplicat sablonul (cu `SourceFile`/nume de clasa concrete), rulat `txt2vcx.ps1` cu
+`-ProjectRoot`/`-CacheRoot` catre acel proiect-fals — **fidelity check trecut din prima
+incercare** (spre deosebire de `frm_cursuri_valutare`, care a avut nevoie de 3 corectii). Apoi
+reconvertit binarul proaspat cu `vcx2txt.ps1` intr-un cache izolat separat si comparat cu
+`diff` — **zero diferente**. Detalii complete si comenzile exacte: `docs\nota_s8b_sablon_vc2.md`.
+
+**Neprobat**: adaugarea in `.pjx` si deschiderea reala in designer/rulare (pasii 7-8 raman
+descrisi, nu executati — n-ar fi trebuit sa atinga arborele real fara aprobare).
diff --git a/docs/sabloane/sablon_vcx_gol.vc2 b/docs/sabloane/sablon_vcx_gol.vc2
new file mode 100644
index 0000000..83b81c0
--- /dev/null
+++ b/docs/sabloane/sablon_vcx_gol.vc2
@@ -0,0 +1,14 @@
+*--------------------------------------------------------------------------------------------------------------------------------------------------------
+* (EN) AUTOGENERATED - ATTENTION!! - NOT INTENDED FOR EXECUTION!! USE ONLY FOR MERGING CHANGES AND STORING WITH SCM TOOLS!!
+*--------------------------------------------------------------------------------------------------------------------------------------------------------
+*< FOXBIN2PRG: Version="1.21" SourceFile="__NUME_BIBLIOTECA__.vcx" CPID="1252" /> (Solo para binarios VFP 9 / Only for VFP 9 binaries)
+*
+*
+DEFINE CLASS __NumeClasaExemplu__ AS custom
+ *< CLASSDATA: Baseclass="custom" Timestamp="" Scale="Pixels" Uniqueid="" />
+
+ *
+ Name = "__NumeClasaExemplu__"
+ *
+
+ENDDEFINE
diff --git a/versiune_db.txt b/versiune_db.txt
index 36bff2c..4bc7c05 100644
--- a/versiune_db.txt
+++ b/versiune_db.txt
@@ -1 +1 @@
-2026_08_09_02
\ No newline at end of file
+2026_09_09_07
\ No newline at end of file