Files
roafacturare/docs/cercetare/rec_inainte_de_stoc.md
Marius Mutu d9f5ca4226 docs: planurile, proiectarile si rapoartele de lucru intra in versionare
Folderul docs\ era pana acum in afara oricarui control de versiuni - nici git,
nici SVN - desi contine planurile pe puncte, proiectarile si rapoartele de
cercetare pe care se sprijina modificarile din cod. O stergere acolo era
definitiva.

Fisierele intermediare (handoff-uri intre sesiuni, diff-uri deja aplicate) au
fost sterse inainte, nu versionate: ce era durabil in ele a intrat in antetele
fisierelor de test la care se refereau.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
2026-08-11 22:17:17 +03:00

95 lines
6.0 KiB
Markdown

# De ce la test crapa (View Parameter) si in productie merge — INAINTE_DE_STOC
Investigatie read-only, 08.08.2026. Intrebare de la Marius: acelasi tipar `DO ... WITH gnAn, gnLuna`
exista in productie la `COMUN\programe\oproceduri_stocuri.prg:35,130,207` — de ce nu s-a manifestat
niciodata acolo?
## Raspuns
**Varianta 1, confirmata prin citirea intregului cod al procedurii apelate: inofensiv prin
constructie.** Pe acest lant nu exista niciun `?gnAn`/`?gnLuna` (bind marker SQL) — deci pasarea prin
referinta, desi masca numele `gnAn`/`gnLuna` in interiorul procedurii apelate, nu are ce sa strice.
## Dovada, pas cu pas
1. **Apelul**: `oproceduri_stocuri.prg:35,130,207` —
`DO INAINTE_DE_STOC WITH gnAn, gnLuna, tnTipGest, lnStocObinv in oinainte_de.prg`.
2. **Procedura apelata**: `COMUN\programe\oinainte_de.prg:356-411`, `PROCEDURE INAINTE_DE_STOC`,
semnatura `Parameters tnAn, tnLuna, tnTipGest, tnStocObinv, tcListaIdGestiuni`. Deci `gnAn` ajunge
accesibil in interior **doar** sub numele local `tnAn` (si `gnLuna` sub `tnLuna`) — exact tiparul
care facea `TYPE('gnAn')='U'` in testul de ieri.
3. **Singurul SQL din procedura** e la `oinainte_de.prg:389-390`:
```
lcSql = "select pack_inainte_de.inainte_de_stoc(" + Alltrim(Str(tnAn)) + "," + Alltrim(Str(tnLuna)) + "," + ;
Alltrim(Str(tnTipGest)) + "," + Alltrim(Str(tnStocObinv)) + "," + Iif(Isnull(gnIdSucursala), "null", Alltrim(Str(gnIdSucursala))) + "," + ;
Iif(Empty(Nvl(m.lnIdGestiune, '')), "null", Alltrim(Str(lnIdGestiune))) + ") as valoare from dual"
```
Toti termenii intra prin **concatenare** (`Alltrim(Str(...))`), inclusiv `tnAn`/`tnLuna` — cele
masate. **Zero caractere `?` in acest string.** `gnIdSucursala` apare si el, dar tot prin
concatenare, nu ca bind marker — deci nici acolo nu conteaza ca e vizibil sau nu global.
4. **Procedura nu face niciun alt `DO ... WITH` mai departe** — bucla `For lnGestiune = 1 To
lnGestiuni` apeleaza direct `goExecutor.oExecute(lcSql, lcCursor)` (executie Oracle), nu alta
procedura VFP. Lantul se opreste aici; nu exista o veriga suplimentara unde `tnAn`/`tnLuna` sa
piarda contextul.
Concluzie: mecanismul care bloca testul (VFP incearca sa lege `?gnAn` la o variabila devenita `'U'`
si deschide dialogul nativ "View Parameter") **nu are niciun `?gnAn`/`?gnLuna` de legat** pe acest
lant — nu pentru ca variabila ar fi vizibila, ci pentru ca nimeni nu o cere prin acel mecanism.
Utilizatorul nu vede dialogul pentru ca bug-ul latent (pasarea prin referinta) exista, dar
consecinta lui (bind marker nelegat) nu e declansata de acest cod.
## Verdict
**Inofensiv, cazul specific din intrebare.** Nu e bug latent — e cod scris corect din intamplare
(sau prin obisnuinta autorului de a concatena SQL-ul in loc sa foloseasca bind markers), care
absoarbe fara sa observe efectul secundar al `DO ... WITH`.
## Cautare extinsa: aceeasi familie in restul `COMUN\programe` si `COMUN\clase`
Cautat tiparul complet (ambele conditii): `DO ... WITH <variabila globala>` (fara paranteze, deci
prin referinta) **si** acelasi nume aparand ca `?<variabila>` undeva accesibil pe lantul de apel.
Inventarul complet de apeluri `DO ... WITH <global g*>` neconditionate (comentariile `*DO ...` nu
conteaza, cod mort):
| Apel | Fisier:linie | Verdict |
|---|---|---|
| `DO INAINTE_DE_STOC WITH gnAn, gnLuna, tnTipGest, lnStocObinv` | `oproceduri_stocuri.prg:35,130,207` | **Inofensiv** — vezi mai sus |
| `DO fisa_magazie_fifo WITH gnTipGest,pnIdGestiune,pcNumeGestiune,PcCodul` | `rulaje.vc2:8243` | **Inofensiv** — vezi mai jos |
| `*DO schimba_firma WITH gnHandle,GCS,lcschemaParola` | `ostartfirma.prg:168` | cod mort (comentat) |
| `*DO schimba_firma WITH gnHandle,lcSchema,...` | `ferestre_comune.vc2:859`, `ferestre_oracle.vc2:858` | cod mort (comentat) |
**`fisa_magazie_fifo`** (`orapoarte.prg:266-...`, `Lparameters tnTipGest, tnIdGestiune,
tcNumeGestiune, tnIdArticol, tcSerie`): `gnTipGest` ajunge accesibil doar sub `tnTipGest`. Cautare
`\?gnTipGest\b` in tot `COMUN` gaseste 8 hituri, **niciunul in `orapoarte.prg`** — toate in fisiere
fara legatura cu acest lant de apel (`gest_selectii.db2`, `oproceduri_facturare.prg`,
`configurare.vc2`, `oschimbare_pret.vc2`, apeluri din alte fluxuri, nu din `fisa_magazie_fifo`).
Functia foloseste `tnTipGest` doar prin comparatie directa (`If tnTipGest = 6`) si transmis mai
departe ca parametru catre `caut_gestiune(tnTipGest, gnIdUtil)` — niciodata ca bind marker SQL.
Inofensiv, acelasi motiv ca la INAINTE_DE_STOC.
**Nu exista alt caz** in `COMUN\programe` / `COMUN\clase` unde ambele conditii (DO...WITH pe un
global + `?acelasi_nume` pe lantul de apel) sa se intalneasca simultan.
### Gasit in cautare, dar NU pe acest tipar (semnalat totusi)
`oinainte_de.prg:258`, procedura `test_casa`:
```
lcSql = [select PACK_INAINTE_DE.TEST_CASA(?gnAn,?gnLuna,?pcContTestCasa,?gnIdSucursala) AS VALOARE FROM DUAL]
```
Foloseste `?gnAn`/`?gnLuna`/`?gnIdSucursala` ca bind markers reali. **Dar** apelul catre `test_casa`
(`ocasabanca.prg:66`: `Do test_casa With lcCont In oinainte_de.prg`) paseaza **doar** `lcCont` —
`gnAn`/`gnLuna` nu sunt deloc argumente, deci nu sunt mascate pe acest lant. Nu se incalca conditia
ceruta (ambele trebuie sa se intample **impreuna**), deci nu e cazul cautat — dar e o structura
fragila: daca in viitor cineva ar adauga `gnAn`/`gnLuna` ca parametri suplimentari la `test_casa`
fara paranteze, ar reproduce exact blocajul de ieri, de data asta in productie (dialogul "View
Parameter" vazut de utilizator). Nu e remediat — doar semnalat, in afara scopului intrebarii.
## Remediu propus (NEAPLICAT)
Niciunul necesar pentru cazurile gasite — sunt inofensive prin constructie. Daca se doreste totusi
o plasa de siguranta impotriva viitoarelor regresii de acest tip: paranteze la orice `DO ... WITH`
care paseaza globale catre o procedura ale carei SQL-uri sunt necunoscute/in schimbare —
`DO INAINTE_DE_STOC WITH (gnAn), (gnLuna), tnTipGest, lnStocObinv` — cost zero, elimina clasa de bug
la sursa. **Nu s-a aplicat nicio modificare de cod** — cod de productie neatins, conform interdictiei.