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
483 lines
37 KiB
Markdown
483 lines
37 KiB
Markdown
# 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.
|