Curatenie ceruta dupa inchiderea lui #6. Folderul cercetare\ NU se putea sterge in bloc: plan_13 se sprijina pe el cu 85 de trimiteri, deci e baza de dovezi a planului aflat in lucru. Impartirea: - 14 cercetari trans-proiect trec in COMUN\docs\cercetare\ - valuta si curs, TVA/VANZARI, consumatorii VANZARI din toata suita, integrarile #10/#11/#12, watchdog VFP, proiectarea Oracle a lui S5, view-ul VVANZARI_ARTICOLE. Nu sunt ale ROAFACTURARE, iar #10/#11/#12 se reiau chiar din ele. - 20 de rapoarte de executie ale lui #6, nereferite de nimic viu, sterse. - 91 raman, neatinse. Trimiterile catre handoff-urile si diff-urile intermediare deja desfiintate au fost curatate peste tot (39 de fisiere): 50 catre handoff-uri, 37 catre diff-uri aplicate, plus caile celor mutate in COMUN. Zero trimiteri rupte ramase. progres.md preia rolul de predare: ce ramane din #6 (cele sase documente parazite, cele doua esecuri reale din S8 pe factura din aviz), cifrele de test citite din log, si cele doua capcane de mediu platite - .FXP vechi executat in locul .prg-ului, si GETFONT() care atarna un formular instantiat fara goApp. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
205 lines
12 KiB
Markdown
205 lines
12 KiB
Markdown
# S5 — inchiderea golurilor de acoperire (rollback, al doilea punct de intrare, linii de set)
|
|
|
|
Continua `docs\livrare_s5.md`, sectiunea 5 „Ce NU e acoperit". Trei goluri, in ordinea cerută:
|
|
calea de ROLLBACK la esec partial, al doilea punct de intrare (`comun.vc2:2491`), liniile din
|
|
seturi de articole. Suite noi: `COMUN\utile\Teste\editare_factura\test_s5_rollback_real.prg`,
|
|
`COMUN\utile\Teste\editare_factura\test_s5_al_doilea_intrare.prg`. Niciun cod de productie atins.
|
|
|
|
## A. Calea de ROLLBACK la esec partial — INCHIS, cu o descoperire importanta
|
|
|
|
Suita: `test_s5_rollback_real.prg`. Log: `test_s5_rollback_real_log.txt` (rulare 10.08.2026,
|
|
01:20:31-01:20:32). **13 PASS / 0 FAIL.**
|
|
|
|
**PARTEA M (mock, fara Oracle)** — completeaza `test_s5_validari_articole.prg`/B3 (care opreste
|
|
esecul la a DOUA comanda, in mijlocul buclei de UPDATE): aici esecul e la PRIMA comanda a
|
|
helperului (pasul 1, „marcheaza tot sters"). Dovedit: functia intoarce `.F.` imediat, **o singura**
|
|
comanda incercata (`nApeluri=1`) — nicio comanda de UPDATE/INSERT/recalcul nu se mai declanseaza.
|
|
|
|
**PARTEA R (real, Oracle)** — pe `id_vanzare=1049`, prin `SQLEXEC` brut (nu prin
|
|
`ScrieArticoleFacturaEditate`/`goExecutor.oExecuta` — vezi descoperirea de mai jos), reproduce
|
|
EXACT secventa SQL pe care helperul o genereaza pentru un caz cu esec la INSERT (linie noua cu
|
|
`id_articol=999999999`, verificat inainte ca articolul chiar nu exista in `NOM_ARTICOLE`):
|
|
|
|
| Pas | Comanda | Rezultat |
|
|
|---|---|---|
|
|
| 1 | `UPDATE ... SET STERS=1` (marcheaza tot) | reuseste |
|
|
| 2 | 3x `UPDATE` (invie+actualizeaza liniile pastrate 1581/1583/1588) | reuseste |
|
|
| 3a | `INSERT` linie noua VALIDA | reuseste |
|
|
| 3b | `INSERT` linie noua cu `id_articol` inexistent | **ORA-02291** (FK_VANZARE_DET002) |
|
|
|
|
Dovedit, cu citiri **necomise** pe aceeasi conexiune, INTRE pasi (proba de executie PARTIALA
|
|
reala, nu doar teoretica): dupa pasii 1-2, cele 3 linii pastrate erau deja active si actualizate
|
|
(necomis); dupa insertul valid, documentul avea deja 5 linii (necomis). Insertul invalid a oprit
|
|
secventa exact acolo (simetric cu `EXIT` din `SCAN`-ul helperului) — `recalculeaza_totaluri_vanzari`
|
|
nu s-a mai apelat. Tranzactia s-a inchis cu **ROLLBACK** (tiparul apelantilor:
|
|
`lnSucces=Iif(...,1,-1)` → `MyInchideTranzactie(Iif(lnSucces<0,2,1))`).
|
|
|
|
Verificat **independent prin sqlplus**, dupa terminarea procesului VFP: `VANZARI.COD` neschimbat
|
|
(`1140898`), toate cele 4 randuri din `VANZARI_DETALII` identice octet-cu-octet cu starea de
|
|
dinainte (`id_vanzare_det:sters:cantitate:pret:pret_achizitie`), zero randuri cu
|
|
`id_articol=999999999`, zero tranzactii deschise.
|
|
|
|
### Descoperire, NEREPARATA (cod de productie interzis pentru acest agent) — de raportat separat
|
|
|
|
`goExecutor.oExecuta(<sql>)` — calea Oracle pe care `ScrieArticoleFacturaEditate` o foloseste
|
|
pentru **toate** comenzile ei — **agata procesul VFP headless la o eroare Oracle REALA**, sub
|
|
tranzactie manuala (`SQLSetprop(...,"Transactions",2)`), chiar daca Oracle a raspuns deja cu
|
|
eroarea. Constatat de doua ori, izolat, cu un script minimal (~15 linii, sters dupa investigatie):
|
|
|
|
- sesiunea Oracle arata `INACTIVE`/`SQL*Net message from client` (Oracle a raspuns, asteapta
|
|
urmatoarea comanda de la client) — **nu** e o incuietoare (`v$lock`/`v$transaction`: nimic
|
|
blocant);
|
|
- `EnumWindows` pe procesul VFP arata **doar** fereastra principala — **nu** e un dialog Windows
|
|
care asteapta input;
|
|
- `SQLEXEC` brut (fara `goExecutor`) pe **exact aceeasi comanda** intoarce eroarea instant
|
|
(`lnRes=-1`, `AERROR` populat corect, `alen=7`, `[1]=1526`) — deci nu e o problema a driverului
|
|
Oracle/OLEDB in sine.
|
|
|
|
### CAUZA GASITA de orchestrator, 10.08.2026 — e artefact headless, NU un defect de productie
|
|
|
|
Suspiciunea pe `goLog.Log()` de mai sus e **gresita**. Cauza reala, citita in cod:
|
|
|
|
`ORA-02291` ajunge in `oproceduri_comune.prg` ca eroare ODBC, deci `lnEroare1 = 1526` si
|
|
`lnEroare2 = 2291`. `2291` nu e in lista de reconectare (`:385`), deci executia intra pe ramura
|
|
`Otherwise` (`:421-424`):
|
|
|
|
```foxpro
|
|
If llShowError
|
|
lnRaspuns = amessagebox('Eroare necunoscuta' + Chr(13) + lcTextEroare, 0, 'Eroare')
|
|
Endif
|
|
```
|
|
|
|
**Acolo se agata: un `AMESSAGEBOX` modal, intr-un proces headless in care nimeni nu apasa OK.**
|
|
`goLog.Log()` (`:427`) vine **dupa** el si nici nu apuca sa ruleze. Explica si de ce `SQLEXEC` brut
|
|
intoarce eroarea instant — el nu trece prin ramura asta.
|
|
|
|
`llShowError` vine din `This.lShowError` cand apelantul nu-l paseaza (`:234` vs `:243`), iar
|
|
`ScrieArticoleFacturaEditate` cheama `goExecutor.oExecuta(m.lcSql)` fara al doilea argument pe toate
|
|
cele patru cai (`ofacturare_editare.prg:491, 502, 531, 547`) — deci mesajul chiar se afiseaza.
|
|
|
|
**Consecinta reala pentru livrare, inversa fata de ce scria mai sus**: in productie, cu utilizator
|
|
in fata ecranului, comportamentul e **corect** — se afiseaza mesajul, `Exit` iese din bucla,
|
|
helperul intoarce `.F.`, apelantul inchide tranzactia cu ROLLBACK. Aplicatia **nu** ramane agatata.
|
|
Agatarea e capcana headless deja documentata in `docs\progres.md` („Dialogurile native VFP blocheaza
|
|
testul headless la infinit"), lovita aici de un script minimal care nu avea mock pe `amessagebox`.
|
|
|
|
Ce ramane, ca **wart preexistent** al infrastructurii comune (nu al S5, si neatins): textul afisat e
|
|
`Eroare necunoscuta` + SQL-ul brut + `GETCALLSTACK()` — corect functional, urat pentru utilizator.
|
|
Priveste tot ROA, nu doar acest lant.
|
|
|
|
## B. Al doilea punct de intrare (`comun.vc2:2491`, `afisjurcom.do_modifica`) — INCHIS
|
|
|
|
Suita: `test_s5_al_doilea_intrare.prg`. Log: `test_s5_al_doilea_intrare_log.txt` (rulare
|
|
10.08.2026, 01:29:51-01:29:52, a doua trecere — vezi „Corectie" mai jos). **17 PASS / 0 FAIL.**
|
|
|
|
Reproduce integral secventa `comun.vc2:2222-2569` (garzile, cursoarele notei, salvarea), mai putin
|
|
partea de UI (gridul `actjur`, `Createobject([frm_modific2024], lnIdSet)` — sarit deliberat, risc
|
|
de blocaj headless; verificarea vizuala ramane la Marius, per briefing). Pe **aceeasi nota**
|
|
folosita de `test_s5_scriere_reala.prg`/`test_s5_discount_valuta.prg` (`id_vanzare=1049`) —
|
|
singurul document de test cunoscut care are simultan rand real in `VANZARI` **si** nota in luna
|
|
curenta (cerinta specifica a lui `afisjurcom.do_modifica`, `comun.vc2:2265-2268`, pe care
|
|
`do_editare_factura` nu o are in aceeasi forma).
|
|
|
|
Diferenta functionala fata de primul punct de intrare, singura care conteaza pentru acest test:
|
|
`afisjurcom.do_modifica` **nu** apeleaza `IncarcaVanzareDinNota` direct — apeleaza
|
|
`PregatesteArticoleFacturaEditare('tact')` (`comun.vc2:2436`), care populeaza `tvanz` **si**
|
|
`crsArticoleFactura` pe alta cale de cod. Dovedit REAL (nu static):
|
|
|
|
- `PregatesteArticoleFacturaEditare` gaseste documentul (`.T.`);
|
|
- garda noua (`Used('tvanz') And Reccount('tvanz')=1`) se satisface REAL prin aceasta cale;
|
|
- `tvanz.id_vanzare` corect (`1049`), `crsArticoleFactura` precarcat;
|
|
- blocul nou (`comun.vc2:2491-2493`) **s-a executat** (flag verificat direct in cod, nu prin
|
|
scanare de log);
|
|
- lantul complet a reusit (`lnSucces=1`), tranzactia s-a inchis cu **COMMIT**
|
|
(`Thisform.do_inchide_tranzactie(Iif(lnSucces<0,2,1))`, `comun.vc2:2541`) — spre deosebire de
|
|
suita A, aici nu s-a provocat niciun esec, deci lantul chiar reuseste si comite, ca in fluxul
|
|
real.
|
|
|
|
Fara nicio modificare de articole (ca blocul C din `test_s5_discount_valuta.prg`): `COD` s-a
|
|
realocat (`1140899 → 1140900`, efect normal al `finalizeaza_modificare_nota` la orice salvare,
|
|
chiar fara modificari), dar discount/totaluri/numar de linii active raman identice, verificat
|
|
**independent prin sqlplus** dupa terminarea procesului.
|
|
|
|
### Corectie facuta IN TIMPUL scrierii acestui test (nu a ajuns in fisierul final, dar a scris real in baza)
|
|
|
|
O prima varianta a testului apela `ScrieArticoleFacturaEditate` **fara** sa incarce intai `tvd`
|
|
(in fluxul real, `Load()`-ul lui `frm_modific2024` e cel care il populeaza din
|
|
`crsArticoleFactura` — sarit aici deliberat). Garda EXTERNA
|
|
(`Used('tvanz') And Reccount('tvanz')=1`) s-a satisfacut, dar garda INTERNA de no-op a helperului
|
|
(`!Used('tvd')`) a transformat apelul intr-un **no-op tacut** (intoarce tot `.T.`) — fara sa
|
|
corecteze reset-ul `STERS=0` pe care `pack_facturare.actualizeaza_vanzari` il face pe TOT
|
|
documentul (acelasi mecanism documentat in `rec_s5_scriere_reala.md`). Tranzactia a **comis**
|
|
reset-ul necorectat: linia `det=1582`, definitiv stearsa in `test_s5_scriere_reala.prg`
|
|
(09.08.2026), a fost reinviata real in Oracle (`STERS: 1 → 0`).
|
|
|
|
**Reparat imediat**, inainte de orice alta actiune: `UPDATE vanzari_detalii SET sters=1 WHERE
|
|
id_vanzare_det=1582; COMMIT;`, verificat prin `sqlplus` ca restul coloanelor (cantitate, pret,
|
|
pret_achizitie) au ramas neatinse. Varianta finala a testului incarca `tvd` cu
|
|
`IncarcaArticoleFactura(tnIdVanzare,'tvd')` chiar dupa `PregatesteArticoleFacturaEditare` (ca
|
|
Load()-ul formularului), deci helperul chiar corecteaza reset-ul — noua rulare confirma explicit,
|
|
prin asertia 17, ca `det=1582` ramane `sters=1` dupa salvare. Consemnat in antetul suitei finale,
|
|
ca precautie pentru cine reia/adapteaza testul.
|
|
|
|
Aceasta e o capcana de test (guard-ul `!Used('tvd')` functioneaza exact cum trebuie, prevenind un
|
|
no-op periculos sa arunce eroare — problema a fost ca testul nu a reprodus fidel ce face UI-ul real
|
|
inainte de acest punct), **nu** un defect de productie.
|
|
|
|
## C. Liniile din seturi de articole (`id_vanzare_set` nenul)
|
|
|
|
**Partea Oracle (agregarea pe seturi din `recalculeaza_totaluri_vanzari`) — NEACOPERIBILA pe datele
|
|
curente, confirmat prin interogare, nu presupus:**
|
|
|
|
```sql
|
|
select count(*) from vanzari v join vanzari_detalii vd on vd.id_vanzare=v.id_vanzare and vd.sters=0
|
|
where vd.id_vanzare_set is not null
|
|
and extract(year from v.data_act)=2026 and extract(month from v.data_act)=8;
|
|
-- 0 randuri
|
|
```
|
|
|
|
Cele mai recente documente cu linii de set active sunt din 2026-03 (`id_vanzare=1027`) si mai
|
|
vechi — niciunul din luna curenta (august 2026), cerinta obligatorie a gardei de editare
|
|
(`(pnAn*12)+pnLuna = (gnAn*12)+gnLuna`, verificata direct in suitele A si B de mai sus). Fara
|
|
fabricare de date (interzisa explicit in briefing): golul ramane deschis, ca risc cunoscut, pana
|
|
apare un document real editabil cu linii de set.
|
|
|
|
**Partea helper VFP (`ScrieArticoleFacturaEditate` trateaza corect o linie cu `id_vanzare_set`
|
|
nenul) — DEJA ACOPERITA, verificat prin recitirea suitei existente, fara munca noua necesara:**
|
|
`test_s5_validari_articole.prg`, sectiunea B1, randul 6 („componenta de set, pastrata"
|
|
`id_vanzare_set=999`, `det=558`) — asertia „clasificare: exact 3 UPDATE (liniile pastrate 555/556/
|
|
558, inclusiv nemodificata si componenta de set)" dovedeste ca helperul trateaza o linie cu
|
|
`id_vanzare_set` nenul identic cu orice alta linie pastrata (UPDATE normal, fara ramura speciala in
|
|
codul VFP — `id_vanzare_set` nu apare in nicio conditie din `ScrieArticoleFacturaEditate`,
|
|
confirmat si prin citirea sursei). Nu era nevoie de mock nou.
|
|
|
|
## Cifre PASS/FAIL, numarate din log
|
|
|
|
| Suita | Cifra | Verdict |
|
|
|---|---|---|
|
|
| `test_s5_rollback_real.prg` (nou) | **13 PASS / 0 FAIL** | Rollback la esec partial: contract (mock) + stare DB (real, SQLEXEC) |
|
|
| `test_s5_al_doilea_intrare.prg` (nou) | **17 PASS / 0 FAIL** | Al doilea punct de intrare, executie reala prin `comun.vc2:2491-2493` |
|
|
| `test_s5_validari_articole.prg` (existent, doar recitit) | 35 PASS / 0 FAIL (neschimbat) | Confirma acoperirea existenta pentru linia de set (B1/rand 6) |
|
|
|
|
## Date de test consumate
|
|
|
|
Pe `id_vanzare=1049` (acelasi document folosit de toate suitele S5 anterioare):
|
|
|
|
- **`cod` realocat: `1140898 → 1140899 → 1140900`** (ambele din suita B — prima trecere, cu
|
|
corectia de mai sus, apoi a doua trecere finala). Cine reia testele citeste `cod`-ul curent din
|
|
`VANZARI`, nu-l presupune.
|
|
- **Continutul liniilor si totalurile documentului raman identice** cu starea de dinaintea acestei
|
|
lucrari (verificat exhaustiv, prin sqlplus, dupa fiecare pas): `det=1581/1583/1588` active cu
|
|
aceleasi valori, `det=1582` ramane `sters=1`.
|
|
- Suita A (rollback) **nu a consumat nimic** — ambele parti (mock si real) se inchid fara COMMIT.
|
|
- Zero linii noi ramase, zero tranzactii deschise, zero procese `vfp9.exe` ramase — verificat prin
|
|
`sqlplus`/`tasklist` la finalul lucrarii.
|
|
|
|
## Fisiere atinse
|
|
|
|
- `COMUN\utile\Teste\editare_factura\test_s5_rollback_real.prg` (nou)
|
|
- `COMUN\utile\Teste\editare_factura\test_s5_al_doilea_intrare.prg` (nou)
|
|
- Niciun fisier de productie (`.vc2`/`.prg` de aplicatie) atins. `omodificari.vc2`,
|
|
`ofacturare_comun.vc2`, `comun.vc2`, `ofacturare_editare.prg`, `COMUN\clase\ofacturare.vc2` —
|
|
neatinse, conform interdictiei din briefing.
|
|
|
|
Diff (fisiere noi): diff aplicat (sters).
|