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
247 lines
15 KiB
Markdown
247 lines
15 KiB
Markdown
# 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.
|