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