#13: formular de facturare unificat - etapa curenta
Squash al branch-ului de lucru plan13-s2. Cod: clasa noua ofacturare_util (geometrie si utilitare de formular), inrolata in roafacturare.prg; meniul "Facturare (nou)" plat, cu reparatia literalului peste limita VFP de 255 de caractere care impiedica compilarea metodei. Livrare: changelog 2.11.19, marcajul de versiune DB pentru scripturile finale din SCRIPTURI_CLAR\2026\09, inventarul livrarii in docs/livrare_13.md si registrul de erori deschise. Documentatia de lucru a etapei (cercetare, rapoarte, handoff-uri, snapshot-uri de scripturi si backup-uri de rollback) a fost scoasa din arbore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkyjGyrV2S7932om4kfSiK
This commit is contained in:
@@ -1,610 +0,0 @@
|
||||
# Proiectare S5b — proforma si copierea pe formularul unificat
|
||||
|
||||
Cercetare + proiectare READ-ONLY (fara editari de cod, fara `git_sync.ps1`/`txt2vcx.ps1`, fara
|
||||
commit, fara scriere Oracle — numai `SELECT`), pentru povestea **S5b** din
|
||||
`docs\plan_13_unificare_formular_facturare.md` (sectiunea `#### S5b`, liniile 2507-2530), deciziile
|
||||
10 si 11. Continua, fara sa reia, `docs\cercetare\s5b_proforma_descarcare_gestiune.md` (sursa de
|
||||
adevar pentru mecanismul `gestionabil=0` / `id_gestiune=-1000`) si foloseste rezultatele din
|
||||
`docs\cercetare\s4e_lista_preturi_pe_sursa.md` (coliziunea `id_c`) si
|
||||
`docs\cercetare\s4_punct2_registru_cantitate_ramasa.md` (Rol A/B ale `crsarticole`).
|
||||
|
||||
**Status: cercetare + proiectare incheiate.**
|
||||
|
||||
Nu se ating `COMUN\clase\ofacturare_comun.vc2` si `COMUN\programe\ofacturare_editare.prg`
|
||||
(perimetrul altei sarcini). `COMUN\programe\ofacturare.prg` si `ofacturare_comun.prg` sunt citite,
|
||||
nu editate — la fel `COMUN\clase\ofacturare.vc2` si `COMUN\clase\ofacturare_comun.vc2` (citire, nu
|
||||
editare; scriere interzisa doar pe al doilea).
|
||||
|
||||
---
|
||||
|
||||
## Descoperire centrala, care rescrie premisa de risc a lui S5b
|
||||
|
||||
Sursa de adevar anterioara (`s5b_proforma_descarcare_gestiune.md`) a stabilit ca gate-ul pentru
|
||||
proforma e sentinela `id_gestiune = -1000`, verificata **in interiorul** lui
|
||||
`contabilizeaza_articol` (`PACK:7472-7476`). Cercetarea de fata a gasit un strat **mai devreme si
|
||||
mai tare**: la `Termina`, `do_scrie_factura` **alege intre doua proceduri Oracle diferite** dupa
|
||||
`poDate.eProforma`, inainte sa se uite la `poDate.tip` (`COMUN\clase\ofacturare.vc2:14282-14300`):
|
||||
|
||||
```
|
||||
Do Case
|
||||
Case poDate.eProforma = 1
|
||||
* scrie_proforma are aceiasi parametri ca scrie_factura2
|
||||
* salveaza doar in vanzari, nu si in contabilitate
|
||||
lcSql = [{call pack_facturare.scrie_proforma(...)}]
|
||||
Case poDate.Tip = 4
|
||||
... lcSql = [{call pack_facturare.scrie_factura_avize(...)}]
|
||||
Case Inlist(poDate.Tip,3,21,25,28,42,47)
|
||||
... lcSql = [{call pack_facturare.scrie_factura2(...)}]
|
||||
Otherwise
|
||||
... lcSql = [{call pack_facturare.scrie_factura2(...)}]
|
||||
Endcase
|
||||
```
|
||||
|
||||
Comentariul din cod ("salveaza doar in vanzari, nu si in contabilitate") e literal adevarat, verificat
|
||||
pe corpul Oracle: `pack_facturare.scrie_proforma` (`PACK:5637-5671`) cheama **doar**
|
||||
`scrie_in_vanzari` (`PACK:13488-13760`) — care face `INSERT INTO VANZARI` (antet) **si**
|
||||
`INSERT INTO VANZARI_DETALII ... SELECT FROM VANZARI_DETALII_TEMP` (liniile, cu `ID_GESTIUNE` asa
|
||||
cum a ajuns in `TEMP`) — apoi marcheaza `VANZARI.EPROFORMA=1`. **`scrie_proforma` nu cheama
|
||||
niciodata `contabilizeaza_articol`.** `scrie_factura2`/`scrie_factura_avize`/`scrie_aviz_retur` sunt
|
||||
singurele trei proceduri care cheama `contabilizeaza_articol` (confirmat si in
|
||||
`docs\plan_13_unificare_formular_facturare.md:298-310`, runda 11) — si niciuna din ele nu ruleaza
|
||||
pentru `eProforma=1`.
|
||||
|
||||
**Consecinta:** pentru o proforma, `scrie_nota` (care scrie `NOTE_CONTABILE`) si `descarca_gestiune`
|
||||
nu ruleaza **deloc** — nu pentru ca sentinela `-1000` le blocheaza pe fiecare linie (desi si asta
|
||||
ramane adevarat, ca plasa suplimentara), ci pentru ca **intreaga functie care le cheama nu se
|
||||
executa**. Sentinela `-1000` din `contabilizeaza_articol` conteaza doar cand `contabilizeaza_articol`
|
||||
chiar ruleaza — adica exact pe drumul invers (vezi sectiunea 5), nu pe proforma insasi.
|
||||
|
||||
**De ce conteaza pentru S5b**: alegerea `scrie_proforma` vs. `scrie_factura2` se face **o singura
|
||||
data, la Termina**, citind `poDate.eProforma` **in acel moment** — nu depinde de cand/cum a fost
|
||||
comutat combo-ul, nici de valorile `gestionabil`/`id_gestiune` de pe liniile individuale. Asta e o
|
||||
veste buna pentru un sens al comutarii (proforma -> ramane proforma la salvare: corect, indiferent ce
|
||||
au liniile), dar **nu acopera** sensul opus (liniile marcate negestionabil sub proforma, apoi
|
||||
documentul comutat inapoi la factura inainte de Termina) — acolo `scrie_factura2` **chiar** ruleaza,
|
||||
si atunci sentinela `-1000` de pe liniile ramase de la proforma **chiar blocheaza** `descarca_gestiune`
|
||||
pe un document care ar trebui sa descarce. Vezi sectiunea 5.
|
||||
|
||||
---
|
||||
|
||||
## 1. Fluxul de azi al proformei, cap-coada
|
||||
|
||||
**1.1 Alegerea tipului.** Proforma nu e o valoare in `pack_facturare.ntip` (tipul de business,
|
||||
1-52) — e un atribut ortogonal, `poDate.nIdTipDoc` (5=FACTURA, 23=PROFORMA, 3=BON FISCAL,
|
||||
6=AVIZ), setat din combo-ul "Tip document" (`Ct_clb_fdoc._combobox1`,
|
||||
`RowSource = "FACTURA,PROFORMA,BON FISCAL"`, `ofacturare.vc2:8745-8754`). Setter-ul
|
||||
`nIdTipDoc_Assign` (`COMUN\programe\ofacturare_comun.prg:593-600`) deriva boolean-ul in acelasi
|
||||
moment: `This.eProforma = IIF(m.tnIdTipDoc = This.nIdTipDocProforma, 1, 0)`.
|
||||
|
||||
**1.2 Marcarea in masa la incarcarea cursorului.** In `factureaza()` (`COMUN\programe\ofacturare.prg`),
|
||||
dupa ce cursorul sursa (indiferent care — lista de preturi, comanda, contract, aviz, retur) e adus in
|
||||
`crsarticole` (Do Case pe `tnTip`, `:266-311`), **daca** `poDate.eProforma = 1`, se face un `UPDATE`
|
||||
de masa peste tot cursorul (`:330-334`):
|
||||
```
|
||||
* Daca este o proforma, consider toate articolele negestionabile, pentru a nu mai alege din stoc
|
||||
IF poDate.eProforma = 1
|
||||
UPDATE (m.lcCursor) SET gestionabil = 0
|
||||
GO TOP IN (m.lcCursor)
|
||||
ENDIF
|
||||
```
|
||||
Acest pas ruleaza **o singura data**, la incarcare, **inainte** ca formularul de linii sa se
|
||||
deschida — pentru ca la momentul lui `poDate.eProforma` e deja finala: combo-ul traieste in
|
||||
`frm_date_factura`/`frm_date_aviz`, un dialog modal care se **inchide** (`ofrmceredate.Show()` la
|
||||
`:235`, urmat de `Release ofrmceredate` la `:248`) **inainte** ca `Do Case`-ul de incarcare a
|
||||
cursorului sa ruleze (`:266` e dupa `:248`). Tipul nu se mai poate schimba dupa acest punct, azi.
|
||||
|
||||
**1.3 Ce face `gestionabil=0` la nivel de linie.** Cand operatorul adauga o linie, ramura care alege
|
||||
dialogul citeste exact acest camp (`ofacturare.vc2:13803-13809`):
|
||||
```
|
||||
Do Case
|
||||
Case (poArticol.gestionabil = 0 Or gnScadereStoc = 0 Or poDate.tip = 45)
|
||||
ofrmadarticol = Createobject("frm_articol_factura", lnCantitateMax, .F.)
|
||||
Otherwise
|
||||
Thisform.do_alege_stoc(...)
|
||||
Endcase
|
||||
```
|
||||
`frm_articol_factura` e dialogul generic pentru orice articol negestionabil din toata aplicatia
|
||||
(nu unul specific proformei) — ocoleste `do_alege_stoc` (alegerea lotului din stoc).
|
||||
`do_initializeaza_articol` (`ofacturare.vc2:13618-13623`) seteaza `id_gestiune=-1000` **doar daca
|
||||
proprietatea lipseste** pe obiectul articol (`Type(...) = "U"`):
|
||||
```
|
||||
If Type('toArticol.id_gestiune') = "U"
|
||||
AddProperty(toArticol,'id_gestiune',-1000)
|
||||
Endif
|
||||
```
|
||||
La scriere, `poArt.id_gestiune` merge direct ca `V_ID_GESTIUNE` catre
|
||||
`pack_facturare.adauga_articol_factura` (`ofacturare.vc2:14069-14073`), care il traduce
|
||||
(`PACK:5032-5034`: `IF V_ID_GESTIUNE <> -1000 THEN V_ID_GESTIUNE2 := V_ID_GESTIUNE; END IF;` —
|
||||
altfel ramane `NULL`), scris in `VANZARI_DETALII_TEMP.ID_GESTIUNE`.
|
||||
|
||||
**Nota de incertitudine, mostenita din raportul-sursa**: linia exacta unde proprietatea
|
||||
`id_gestiune` "lipseste" (`Type='U'`) pentru o linie de proforma scatter-uita din `crsfactura` nu a
|
||||
fost confirmata direct pe date vii — `crsfactura` are `id_gestiune` ca si camp cu valoare implicita,
|
||||
nu absent. Ramane argument indirect (fara `FACT-007` raportat in productie de ani), nu dovada de
|
||||
executie. **De verificat cu prioritate la implementare**, pentru ca proiectarea de mai jos (sectiunea
|
||||
4) muta acest mecanism dintr-un `UPDATE` de masa intr-o marcare per-linie, si trebuie sa stie exact
|
||||
ce camp seteaza.
|
||||
|
||||
**1.4 Routingul la Termina.** Vezi "Descoperirea centrala" de mai sus: `scrie_proforma`, nu
|
||||
`scrie_factura2`/`scrie_factura_avize` — fara nota contabila, fara descarcare de gestiune, indiferent
|
||||
de tipul de business original.
|
||||
|
||||
**1.5 Raportul propriu.** `listeaza_ofacturare` alege raportul dupa `poDate.eProforma`
|
||||
(`ofacturare.prg:1638-1643`):
|
||||
```
|
||||
Case (Between(poDate.tip, 1, 20) Or Inlist(poDate.tip, -1,-2,-3,-4,-8,-11,44,45,48,49,50,51,52)) And poDate.eProforma = 1
|
||||
lcRaport = [PROFORMA]
|
||||
lcRaportVal = [PROFORMA_VAL]
|
||||
lcSetare = [PROFORMA]
|
||||
```
|
||||
Independent de forma formularului (unificat sau nu) — declansat de `poDate.eProforma` la momentul
|
||||
listarii, care e populata corect din `nIdTipDoc_Assign` daca antetul reflecta starea finala.
|
||||
|
||||
**1.6 Garzile `eProforma = 0` pe atasamente (nu pe nota contabila).** Cinci guarde separate in
|
||||
`listeaza_ofacturare`, toate de forma `poDate.nRelistare = 0 And poDate.eProforma = 0 ...`, controland
|
||||
salvarea PDF-ului ca atasament arhivat (`export2pdf(..., poDate.cDocAtasate)` si
|
||||
`poDate.scrieAtasamente()`), **nu** scrierea notei contabile (care e blocata la alt nivel, sectiunea
|
||||
precedenta): `ofacturare.prg:1960` (factura in lei), `:1996` (aviz retur), `:2052` (factura in
|
||||
valuta), `:2063` (recapitulatie), `:2103` (`scrieAtasamente()`, arhivarea propriu-zisa). **Corectie
|
||||
fata de formularea din plan** (`plan_13_unificare_formular_facturare.md:548-549`, "fara nota
|
||||
contabila si fara atasamente, prin garzile `eProforma=0`"): cele doua efecte sunt reale amandoua, dar
|
||||
prin **mecanisme diferite** — nota contabila prin routing-ul `scrie_proforma`/`scrie_factura2`
|
||||
(sectiunea "Descoperire centrala"), atasamentele prin aceste cinci guarde explicite. Nu schimba nimic
|
||||
pentru proiectare, dar conteaza pentru cine cauta "garda de nota contabila" in cod si nu o gaseste la
|
||||
liniile citate de plan.
|
||||
|
||||
**1.7 Relistarea pe cale separata.** `frm_facturi.do_listare` (`COMUN\clase\ofacturare_comun.vc2:7233-`)
|
||||
reconstruieste `poDate` de la zero pentru un document deja emis, cu `poDate.eProforma = 1` setat
|
||||
explicit (`:7262`) cand se relisteaza o proforma din grid — nu refoloseste obiectul `poDate` din
|
||||
sesiunea de facturare curenta.
|
||||
|
||||
---
|
||||
|
||||
## 2. Fluxul de azi al copierii, cap-coada
|
||||
|
||||
**2.1 Degradarea de tip in `do_copiaza`.** `frm_facturi.do_copiaza`
|
||||
(`COMUN\clase\ofacturare_comun.vc2:3628-3713`) mapeaza **orice** tip de business catre unul din
|
||||
cinci "simple" — `T1` (lista de preturi), `T10` (lista de preturi valuta), `T5` (invoice),
|
||||
`T22` (aviz din lista de preturi), sau `T1`/`T10` pentru transfer/altele — pe un `Do Case` explicit
|
||||
peste `loFactura.tip` (`:3693-3708`). Factura/avizul din contract sau din comanda **nu se copiaza ca
|
||||
atare** — devine o factura simpla din lista de preturi. Apoi `DO copiere_factura WITH loFactura IN
|
||||
oproceduri_facturare.prg` (`:3710`).
|
||||
|
||||
**2.2 `copiere_factura` -> `factureaza(tip, toFactura)`.** `copiere_factura`
|
||||
(`COMUN\programe\oproceduri_facturare.prg:150-153`) cheama `factureaza(loFactura.tip, loFactura)` —
|
||||
`toFactura` (obiectul scatter-uit din `crsFacturi`) devine parametrul opțional al lui `factureaza`
|
||||
(`COMUN\programe\ofacturare.prg:81-82`), care seteaza `llCopiere = (Type('toFactura') = 'O')`
|
||||
(`:111`).
|
||||
|
||||
**2.3 Antetul precompletat, dar `nIdTipDoc` NU se propaga.**
|
||||
`poDate.completeaza_setari_document(toFactura, .T.)` (`ofacturare.prg:204`, apelat cand `m.llCopiere`)
|
||||
cheama `oDateFactura::completeaza_setari_document`
|
||||
(`COMUN\programe\ofacturare_comun.prg:362-412`), ramura `tlFactura=.T.` (`:368-390`): copiaza delegat,
|
||||
masina, sectie, agent, client, referinta la documentul sursa (`listaid = toDateAnterior.id_vanzare`) —
|
||||
dar **linia `.nIdTipDoc = toDateAnterior.nIdTipDoc` e comentata** (`:370`,
|
||||
`*.nIdTipDoc = toDateAnterior.nIdTipDoc`), deliberat. Documentul nou primeste `nIdTipDoc` implicit
|
||||
dupa tipul degradat (`Do Case` la `ofacturare.prg:187-196`: `tnTip < 21` sau in
|
||||
`{45,48,49,51,52}` => `5` FACTURA, altfel `6` AVIZ) — pentru tipurile degradate ale copierii (`T1=1`,
|
||||
`T5=5`, `T10=10`, `T22=22`), toate `<21`, deci **`nIdTipDoc=5` (FACTURA) intotdeauna**, ceea ce prin
|
||||
`nIdTipDoc_Assign` face **`poDate.eProforma = 0` pe documentul nou, indiferent daca sursa era
|
||||
proforma**. Confirma direct pe cod ce raportul-sursa dedusese din trasare (`s5b_proforma_descarcare_gestiune.md` §3).
|
||||
|
||||
**2.4 Numar nou, intotdeauna.** `poGeneratorNumere.creeaza_cursor_serii(poDate.nIdTipDoc)` (`:211`)
|
||||
ruleaza neconditionat, indiferent de copiere — copierea nu mosteneste numarul documentului sursa,
|
||||
alege intotdeauna un numar nou din seria tipului nou (`FACTURA`).
|
||||
|
||||
**2.5 Cursorul de linii candidate — intotdeauna `cursor_retur_document`.** `Do Case`-ul care alege
|
||||
cursorul Oracle de incarcat in `crsarticole` (`ofacturare.prg:266-308`) verifica **`Case m.llCopiere`
|
||||
primul**, inaintea oricarei ramuri pe `tnTip`:
|
||||
```
|
||||
Case m.llCopiere
|
||||
lcSqlCursor = [{call pack_facturare.cursor_retur_document(?poDate.in_valuta,?poDate.listaid,1,?poDate.eProforma,?gnIdUtil)}]
|
||||
```
|
||||
al treilea parametru pozitional `1` e `V_COPIERE`. Documentul sursa (proforma sau nu) intra prin
|
||||
`?poDate.listaid` (setat la `toDateAnterior.id_vanzare` in §2.3). `poDate.eProforma` trimis e cel al
|
||||
**documentului nou** (`0`, per §2.3), nu al sursei.
|
||||
|
||||
**2.6 Gestionabilitatea se restaureaza la copiere.** `cursor_retur_document`
|
||||
(`PACK_FACTURARE:3949-4000`) calculeaza `GESTIONABIL` cu exact aceasta expresie (`:3993-4000`):
|
||||
```sql
|
||||
(case
|
||||
when V_PROFORMA = 1 then 0
|
||||
when V_COPIERE = 1 then B.IN_STOC -- NOM_ARTICOLE.IN_STOC, articolul real
|
||||
else A.GESTIONABIL
|
||||
end) AS GESTIONABIL,
|
||||
```
|
||||
Cu `V_PROFORMA=0` (documentul nou nu e proforma) si `V_COPIERE=1`, ramura activa e
|
||||
`GESTIONABIL = B.IN_STOC` — valoarea reala din nomenclator, **indiferent daca documentul sursa era o
|
||||
proforma cu toate liniile fortate `gestionabil=0`**. Liniile copiate dintr-o proforma redevin
|
||||
gestionabile normal (daca articolul chiar e in stoc), trec prin `do_alege_stoc` la adaugare, primesc
|
||||
`id_gestiune` real, si descarca gestiune normal la emiterea facturii rezultate.
|
||||
|
||||
**2.7 Nimic auto-adaugat.** Comentariu explicit in cod (`ofacturare.prg:97-99`, in ramura
|
||||
`m.llCopiere` de mai jos in aceeasi functie):
|
||||
```
|
||||
* Nu adaug automat articolele din factura originala, ca sa dau posibilitate de modificare a cantitatilor, pretului, explicatiei
|
||||
* ofrmdetaliifactura.do_adauga_tot()
|
||||
```
|
||||
Liniile documentului sursa raman doar **candidate** in `crsarticole` (populat de `cursor_retur_document`
|
||||
la §2.5) — operatorul le adauga manual (sau cu "adauga tot"), la fel ca la orice document nou.
|
||||
|
||||
**2.8 Lista de preturi se adauga peste, doar la copiere.** Imediat dupa, tot in `factureaza()`
|
||||
(`ofacturare.prg:454-473`, citat integral in `docs\cercetare\s4e_lista_preturi_pe_sursa.md` §1):
|
||||
`pack_facturare.cursor_preturi(...)` intr-un cursor separat `crsArticoleTemp`, apoi
|
||||
`SELECT crsArticole / APPEND FROM DBF(lcCursorTemp)` — lipeste lista de preturi completa peste
|
||||
candidatii din documentul sursa, ca operatorul sa poata adauga si articole noi la copiere/modificare.
|
||||
Vezi sectiunea 6 pentru siguranta acestui pas.
|
||||
|
||||
---
|
||||
|
||||
## 3. Combo-ul `Ct_clb_fdoc` si realocarea de serie/numar la comutare
|
||||
|
||||
**Azi, combo-ul traieste exclusiv in dialogul separat `frm_date_factura`/`frm_date_aviz`**
|
||||
(clasa continuta in acelasi fisier text `ofacturare.vc2`, dar formular distinct de
|
||||
`frm_facturare_articole`/`frm_facturare_articole2`, care contin gridul de linii). Handler-ul e legat
|
||||
pe `LostFocus`, nu pe `InteractiveChange`:
|
||||
```
|
||||
PROCEDURE Ct_clb_fdoc._combobox1.LostFocus && ofacturare.vc2:9857-9859
|
||||
thisform.do_schimba_tipdoc()
|
||||
ENDPROC
|
||||
```
|
||||
`do_schimba_tipdoc` (`ofacturare.vc2:9396-9438`), pas cu pas:
|
||||
1. Determina `lnIdTipDoc` din textul combo-ului (`FACTURA`/`PROFORMA`/`BON FISCAL`/altfel `FACTURA`).
|
||||
2. Cheama neconditionat `poDate.initializeaza_setari_document(...)` cu un cod special (`-101` bon
|
||||
fiscal, `-102` proforma, sau `poDate.Tip` altfel) — realoca setarile de document (serie/numar)
|
||||
pentru noul tip, inainte sa stie daca tipul chiar s-a schimbat.
|
||||
3. **Iesire timpurie daca tipul nu s-a schimbat**: `IF poDate.nIdTipDoc = m.lnIdTipDoc THEN RETURN`.
|
||||
4. Daca s-a schimbat: `poDate.nract = 0`, `poDate.serie_act = ""` (curata selectia locala, nesalvata
|
||||
nicaieri inca), `poGeneratorNumere.dezaloca_numar(poDate.nIdTipDoc)` (**elibereaza in pool numarul
|
||||
vechi**, rezervat pe tipul vechi — nu se pierde, devine disponibil pentru alt document/alta sesiune;
|
||||
documentul nu are inca niciun numar scris in baza, fiind pre-Termina), apoi
|
||||
`poDate.nIdTipDoc = m.lnIdTipDoc` (declanseaza `nIdTipDoc_Assign`, care actualizeaza
|
||||
`eProforma`/`eBonFiscal`), si `poGeneratorNumere.creeaza_cursor_serii(poDate.nIdTipDoc)` reincarca
|
||||
seriile disponibile pentru noul tip, populand `clb_serie_act`.
|
||||
5. **Numarul vechi nu se "reia" automat** — utilizatorul trebuie sa aleaga din nou serie/numar pentru
|
||||
noul tip din controlul `clb_serie_act`, care s-a reincarcat la pasul 4.
|
||||
|
||||
**Ce NU atinge `do_schimba_tipdoc` azi**: `crsarticole`, `crsfactura`, `gestionabil`, `id_gestiune` —
|
||||
nimic legat de linii. **Motivul e structural, nu o omisiune**: azi comutarea e posibila **doar**
|
||||
inaintea oricarei linii, pentru ca `frm_date_factura` (unde traieste combo-ul) e un dialog modal
|
||||
care se inchide (`Release ofrmceredate`, `ofacturare.prg:248`) **inainte** ca Do Case-ul de incarcare
|
||||
a cursorului de linii sa ruleze (`:266`) — comutarea si incarcarea liniilor nu pot fi simultane azi.
|
||||
|
||||
**Ce se schimba cand combo-ul traieste in formularul unificat, cu gridul deja prezent**: exact
|
||||
premisa care dispare — combo-ul devine comutabil **si dupa** ce linii exista deja in `crsfactura`.
|
||||
`do_schimba_tipdoc` ramane corect pentru partea de serie/numar (pasii 1-5 de mai sus se aplica
|
||||
identic, indiferent daca gridul are linii sau nu — realocarea de serie e independenta de continutul
|
||||
documentului). **Ce lipseste e pasul 1.2/1.3 de mai sus (marcarea `gestionabil=0`/`id_gestiune=-1000`),
|
||||
care azi nu are nevoie sa fie legat de comutare pentru ca nu poate fi comutare cu linii deja
|
||||
prezente.** Vezi sectiunea 4.
|
||||
|
||||
---
|
||||
|
||||
## 4. Ce se rupe la unificare
|
||||
|
||||
**4.1 Marcarea negestionabil nu mai are un singur moment de executie.** Azi exista un singur loc
|
||||
(`ofacturare.prg:330-334`, dupa incarcarea cursorului, inaintea deschiderii gridului) unde
|
||||
`eProforma=1` implica `gestionabil=0` in masa. In formularul unificat, cu combo-ul viu in acelasi
|
||||
ecran cu gridul (decizia 10), sunt **trei momente distincte** care trebuie sa garanteze acelasi
|
||||
invariant, nu unul:
|
||||
a. **La deschiderea initiala**, daca formularul porneste direct pe tip Proforma (echivalent cu azi
|
||||
— se poate pastra `UPDATE` de masa pe cursorul candidat, daca inca exista un cursor de masa
|
||||
pentru sursa respectiva dupa S4/S4e; pe sursele deja mutate pe cautare filtrata/`APPEND BLANK`
|
||||
— S4e — nu mai exista cursor de masa de actualizat, marcarea trebuie facuta la construirea
|
||||
fiecarui rand).
|
||||
b. **La adaugarea unei linii noi cat timp `poDate.eProforma=1`** — deja identificat ca gol de
|
||||
proiectare in `s5b_proforma_descarcare_gestiune.md` §7 ("trebuie reimplementat linie-cu-linie,
|
||||
la momentul in care fiecare linie e adaugata"), confirmat aici ca valabil si pentru cazul in
|
||||
care operatorul a **pornit** documentul ca proforma inainte de a adauga prima linie (nu doar
|
||||
dupa un switch).
|
||||
c. **La comutarea combo-ului DUPA ce linii exista deja in `crsfactura`** (cazul explicit cerut de
|
||||
brief) — scenariu care azi nu poate exista, deci nu are cod de reutilizat. `do_schimba_tipdoc`
|
||||
trebuie extins (sau o metoda noua chemata din el) sa parcurga liniile deja prezente in
|
||||
`crsfactura` si sa aplice acelasi tratament ca la 1.2-1.3: `gestionabil=0`,
|
||||
`id_gestiune=-1000`, pe fiecare linie existenta, **cand comutarea intra pe Proforma**.
|
||||
*Corolarul necesar, netratat de nicio decizie/raport anterior*: pentru fiecare linie deja
|
||||
adaugata prin `do_alege_stoc` (gestionabila, cu `id_gestiune` real ales de operator), acea
|
||||
alegere de gestiune/lot devine irelevanta odata marcata negestionabil — de decis daca se
|
||||
**pastreaza tacit** valoarea veche (inofensiv, pentru ca `id_gestiune=-1000` o inlocuieste
|
||||
oricum in parametrul trimis la scriere) sau se **sterge explicit** din obiectul liniei, ca sa nu
|
||||
induca in eroare un ecran care ar afisa gestiunea aleasa pe o linie acum negestionabila.
|
||||
|
||||
**4.2 Combo-ul viu tot timpul inseamna ca `eProforma` poate flutura de mai multe ori inainte de
|
||||
Termina.** Azi tipul se alege o singura data, ireversibil (dialogul se inchide). In formularul
|
||||
unificat, operatorul poate comuta Factura -> Proforma -> Factura de mai multe ori inainte de a apasa
|
||||
`Termina`. Routing-ul de la Termina (sectiunea "Descoperire centrala") citeste `poDate.eProforma`
|
||||
**doar la momentul apasarii** — corect pentru starea finala — dar **starea liniilor** (marcate sau nu
|
||||
negestionabil, dupa istoricul comutarilor) nu se "reseteaza" singura la fiecare comutare, daca 4.1.c
|
||||
nu implementeaza si drumul invers. Vezi sectiunea 5.
|
||||
|
||||
**4.3 Realocarea de serie/numar (sectiunea 3) ramane corecta ca atare**, dar UX-ul ei (curatarea
|
||||
`clb_serie_act`, cererea catre operator sa aleaga din nou seria) trebuie sa functioneze si cu gridul
|
||||
de linii vizibil pe acelasi ecran — nu identificat niciun cod care sa presupuna ca gridul e ascuns in
|
||||
timpul realocarii; e o verificare vizuala, nu o problema de proiectare gasita in cod.
|
||||
|
||||
---
|
||||
|
||||
## 5. Drumul invers: proforma comutata inapoi in factura
|
||||
|
||||
**Acesta e riscul cel mai serios gasit in aceasta cercetare, nesemnalat explicit in rapoartele
|
||||
anterioare.**
|
||||
|
||||
Scenariu: operatorul porneste documentul ca Proforma (sau comuta pe Proforma la un moment dat),
|
||||
adauga linii — care, daca 4.1 e implementat corect, ajung marcate `gestionabil=0`/`id_gestiune=-1000`
|
||||
pe `crsfactura`. Apoi, **inainte de Termina**, comuta combo-ul inapoi pe Factura.
|
||||
|
||||
- **`poDate.eProforma` devine `0`** prin `nIdTipDoc_Assign`, corect.
|
||||
- **La Termina, routing-ul alege `scrie_factura2`/`scrie_factura_avize`** (sectiunea "Descoperire
|
||||
centrala") — care **chiar cheama** `contabilizeaza_articol` pentru fiecare linie.
|
||||
- **`contabilizeaza_articol` verifica exact sentinela `id_gestiune <> -1000`** (`PACK:7472-7476`)
|
||||
inainte de a chema `descarca_gestiune`. Liniile ramase marcate `-1000` de cand documentul era
|
||||
proforma **nu vor descarca gestiune**, desi documentul final e o factura reala, nu o proforma.
|
||||
- **Nu exista azi niciun mecanism care sa refaca `gestionabil`/`id_gestiune`** cand tipul revine la
|
||||
Factura in aceeasi sesiune. Singurul loc din tot codul citit unde gestionabilitatea se
|
||||
"restaureaza" e `cursor_retur_document` la **copiere** (`GESTIONABIL = B.IN_STOC` cand
|
||||
`V_COPIERE=1`, sectiunea 2.6) — mecanism legat de incarcarea unui cursor **nou**, la deschiderea
|
||||
unui document **nou**, nu de o comutare in acelasi document, in aceeasi sesiune, pe linii deja
|
||||
existente in `crsfactura`.
|
||||
|
||||
**Consecinta pe date**: o factura reala, emisa din formularul unificat dupa un du-te-vino prin
|
||||
Proforma, poate iesi din sesiune cu stocul nedescarcat pentru articole care ar fi trebuit sa-l
|
||||
descarce — silentios, fara eroare Oracle (sentinela `-1000` e o valoare valida pentru
|
||||
`contabilizeaza_articol`, nu declanseaza nicio exceptie).
|
||||
|
||||
**Ce trebuie proiectat, obligatoriu, pentru ca decizia 10 sa fie sigura**: la comutarea **dinspre**
|
||||
Proforma **catre** orice alt tip, liniile care au fost marcate negestionabil **exclusiv din cauza
|
||||
proformei** (nu articole real negestionabile in nomenclator) trebuie sa-si recapete
|
||||
`gestionabil`/`id_gestiune` reale, inainte de a ajunge la `Termina`. Doua variante, niciuna aleasa
|
||||
inca:
|
||||
a. **Re-interogare per linie** la comutare (analog cu `cursor_retur_document.GESTIONABIL`, dar
|
||||
aplicat pe liniile deja din `crsfactura`, nu la incarcarea unui cursor nou) — cere un apel
|
||||
Oracle (sau citire din nomenclator local, daca exista deja incarcat) per linie afectata, si
|
||||
re-deschiderea alegerii de gestiune/lot pentru cele gestionabile (echivalentul lui
|
||||
`do_alege_stoc`, care nu a rulat cand linia a fost adaugata sub Proforma).
|
||||
b. **Blocarea comutarii inapoi** cand exista deja linii adaugate sub Proforma — cere confirmare
|
||||
sau refuza tranzitia, obligand operatorul sa stearga liniile si sa le re-adauge sub noul tip.
|
||||
Mai simplu de implementat, cu cost UX (utilizatorul pierde munca de introducere).
|
||||
|
||||
**Nu e o decizie de proiectare pe care raportul o ia in locul lui Marius** — vezi sectiunea 11,
|
||||
punctul 1.
|
||||
|
||||
---
|
||||
|
||||
## 6. `id_c` la copiere — raspuns cu dovada
|
||||
|
||||
**Nu exista coliziune cu efect observabil pe drumul de copiere, azi.** Motivul, verificat direct pe
|
||||
cod (nu presupus, extras din `s4e_lista_preturi_pe_sursa.md` §1, reconfirmat aici pentru S5b):
|
||||
|
||||
`ofacturare.prg:454-473` face `APPEND FROM` peste `crsArticole`, lipind lista de preturi
|
||||
(`crsArticoleTemp`, numerotata `id_c` independent, cu `ROWNUM` propriu Oracle) peste continutul deja
|
||||
prezent (documentul copiat, incarcat la §2.5 din `cursor_retur_document`, cu propriul `id_c`
|
||||
independent). Cele doua seturi de `id_c` **se pot suprapune la nivel de valoare** — asta e adevarat,
|
||||
tehnic. Dar coliziunea **nu are efect**, pentru doua motive independente, ambele verificate:
|
||||
|
||||
1. **`Case m.llCopiere` e prima ramura verificata** in Do Case-ul de incarcare a cursorului
|
||||
(`ofacturare.prg:266-268`) — pentru orice document copiat, cursorul de baza e **intotdeauna**
|
||||
`cursor_retur_document`, indiferent de tipul original. Un document copiat nu (mai) e niciodata de
|
||||
tip `3` (comanda) dupa degradarea din `do_copiaza` (sectiunea 2.1: degradare catre
|
||||
`1,5,7,10,22,23` — **CORECTIE runda 13**, cifra veche `1,5,10,22` era gresita; setul real e citit
|
||||
din primul `CASE`, `ofacturare_comun.vc2:3693-3694`) —
|
||||
deci **nu poate ajunge** in ramura `Inlist(poDate.Tip,3,21,25,28,42,47)` a lui `do_scrie_factura`
|
||||
(`ofacturare.vc2:14332-14338`), care e singurul loc unde `id_c` conteaza pentru "cantitate
|
||||
ramasa" (Rol A, per `s4_punct2_registru_cantitate_ramasa.md`).
|
||||
2. **`do_sterge` potriveste pe `id_c`** (`ofacturare.vc2:14652-14655`), dar aceasta potrivire conteaza
|
||||
doar daca ceva citeste `crsarticole` ca registru dupa aceea — ceea ce nu se intampla pe tipurile
|
||||
rezultate din copiere (`1,5,7,10,22,23`, toate in ramura `Otherwise` a Do Case-ului de scriere, fara
|
||||
`Calculate Sum(cantitate)`).
|
||||
|
||||
**Concluzie, cu aceeasi rezerva ca in raportul-sursa**: coliziunea de `id_c` exista **tehnic** in
|
||||
datele din `crsArticole` dupa copiere, dar **nu are cale prin care sa produca un efect gresit**, atata
|
||||
timp cat tipul rezultat din copiere ramane in setul degradat (`1,5,7,10,22,23` — niciodata
|
||||
`3,21,25,28,42,47`).
|
||||
**Aceasta concluzie ramane valabila neschimbata si in formularul unificat**, pentru ca nu depinde de
|
||||
forma formularului — depinde doar de faptul ca `do_copiaza` degradeaza tipul inaintea oricarei
|
||||
incarcari de cursor, mecanism care nu se propune sa fie schimbat de S5b (sectiunea 7).
|
||||
|
||||
**O singura conditie de pastrat, explicit**: daca vreo poveste viitoare schimba `do_copiaza` sa NU
|
||||
mai degradeze tipul catre grupul "simplu" (de exemplu, sa permita copierea unei comenzi ca o comanda
|
||||
noua, nu ca factura din lista de preturi), concluzia de mai sus **trebuie re-verificata** — riscul de
|
||||
coliziune `id_c` descris in `s4e_lista_preturi_pe_sursa.md` verdict/punctul 1 ar deveni real.
|
||||
|
||||
---
|
||||
|
||||
## 7. Ce NU se atinge — lista explicita
|
||||
|
||||
Confirmate ca deja corecte si suficiente, fara nicio schimbare necesara pentru S5b:
|
||||
|
||||
1. **Sentinela `id_gestiune = -1000`** in `contabilizeaza_articol` (`PACK:7472-7476`) — ramane gate-ul
|
||||
de aparare pentru orice linie care ajunge totusi la contabilizare cu aceasta valoare (drumul
|
||||
invers, sectiunea 5, o foloseste ca sa NU descarce gestiune — ceea ce e exact problema de acolo,
|
||||
nu ceva de "reparat" in sentinela insasi).
|
||||
2. **Routing-ul `scrie_proforma` vs. `scrie_factura2`/`scrie_factura_avize`**
|
||||
(`ofacturare.vc2:14282-14300`) — corect prin constructie, citeste `poDate.eProforma` la momentul
|
||||
potrivit (Termina), nu are nevoie de nicio schimbare.
|
||||
3. **Cele cinci garzi `eProforma=0` pe atasamente** (`ofacturare.prg:1960,1996,2052,2063,2103`) —
|
||||
raman neschimbate, nu au legatura cu formularul (grid vs. dialog separat), doar cu momentul
|
||||
listarii/salvarii PDF, care ramane acelasi apel indiferent de forma UI.
|
||||
4. **Raportul propriu** (`PROFORMA`/`PROFORMA_VAL`, `ofacturare.prg:1638-1643`) — alegerea ramane pe
|
||||
`poDate.eProforma`, neschimbata.
|
||||
5. **`do_copiaza` (degradarea de tip)** — ramane exact cum e, decizia S5b (D) o cere explicit
|
||||
("degradarea de tip din `do_copiaza` ramane pentru copiere si nu se aplica la regenerare").
|
||||
6. **`copiere_factura` -> `factureaza(tip, toFactura)`** — punctul de intrare ramane neschimbat.
|
||||
7. **`completeaza_setari_document`** — comentariul de la `:370` (`nIdTipDoc` necopiat) e deliberat si
|
||||
ramane corect: documentul nou pleaca mereu ca Factura, indiferent de sursa, exact ce cere decizia
|
||||
S5b (copierea deschide "document nou", cu antetul editabil, nu proforma mostenita).
|
||||
8. **`cursor_retur_document` cu `V_COPIERE=1`** (`PACK:3949-4000`) — restaurarea `GESTIONABIL = B.IN_STOC`
|
||||
la copiere ramane corecta si suficienta pentru cazul "copiere", fara nicio schimbare (nu e acelasi
|
||||
mecanism cu comutarea in-sesiune de la sectiunea 5, care ramane un gol real).
|
||||
9. **Numarul alocat la copiere e intotdeauna nou** (`ofacturare.prg:208,211`, neconditionat de
|
||||
`llCopiere`) — nimic de schimbat.
|
||||
10. **Alocarea de serie/numar a lui `do_schimba_tipdoc`** (sectiunea 3) — mecanismul de dealocare +
|
||||
realocare ramane corect si reutilizabil ca atare in formularul unificat; doar absenta lui legata
|
||||
de linii (sectiunile 4-5) e golul de acoperit.
|
||||
|
||||
---
|
||||
|
||||
## 8. Pasi de implementare, ordonati
|
||||
|
||||
1. **Confirma pe date reale linia exacta unde `id_gestiune` devine `-1000`** pentru o linie de
|
||||
proforma (incertitudinea de la sectiunea 1.3) — headless, cu un `crsfactura` construit manual din
|
||||
`Scatter` pe o linie de proforma reala, inainte de orice alta schimbare de cod.
|
||||
*Gata cand:* se confirma cu certitudine (nu argument indirect) fie linia din
|
||||
`do_initializeaza_articol`, fie alt punct, unde proprietatea `id_gestiune` a liniei devine
|
||||
efectiv `-1000`.
|
||||
2. **Extrage marcarea "linie negestionabila pentru proforma" intr-o metoda proprie**, reutilizabila
|
||||
din trei locuri (sectiunea 4.1: incarcare initiala, adaugare linie noua, comutare combo pe linii
|
||||
existente) — un singur loc de intretinut pentru regula `eProforma=1 => gestionabil=0,
|
||||
id_gestiune=-1000`, nu trei copii.
|
||||
*Gata cand:* toate cele trei puncte de intrare cheama aceeasi metoda, verificat prin grep pe
|
||||
codul nou.
|
||||
3. **Leaga metoda de la pasul 2 de `do_schimba_tipdoc`**, pe ramura care duce spre Proforma, aplicata
|
||||
pe toate liniile deja prezente in `crsfactura` la momentul comutarii (sectiunea 4.1.c).
|
||||
*Gata cand:* pe un document cu linii deja adaugate ca Factura, comutarea combo-ului pe Proforma
|
||||
marcheaza `gestionabil=0`/`id_gestiune=-1000` pe fiecare linie existenta, verificabil prin citirea
|
||||
directa a `crsfactura` dupa comutare.
|
||||
4. **Proiecteaza si implementeaza drumul invers** (sectiunea 5) — varianta (a) sau (b), decizie a lui
|
||||
Marius (sectiunea 11, punctul 1). *Gata cand:* pe un document cu linii adaugate sub Proforma,
|
||||
comutat inapoi pe Factura inainte de Termina, fie liniile isi recapata `gestionabil`/`id_gestiune`
|
||||
reale (varianta a, verificabil prin `descarca_gestiune` apelat corect la emitere — vezi sectiunea
|
||||
9), fie comutarea inapoi e refuzata/necesita confirmare explicita (varianta b).
|
||||
5. **Verifica riscul de la sectiunea 4.1, corolarul**: decide daca `id_gestiune`/lotul ales anterior pe
|
||||
o linie acum negestionabila se pastreaza tacit sau se sterge din obiectul liniei — implementeaza
|
||||
alegerea si documenteaz-o in cod (un rand de comentariu, per conventia proiectului).
|
||||
6. **Regresie pe copiere**, fara nicio schimbare de cod asteptata (sectiunile 2, 6, 7) — pas de
|
||||
verificare, nu de implementare: confirma ca formularul unificat, rulat pe drumul de copiere, produce
|
||||
acelasi rezultat ca azi (sectiunea 9).
|
||||
7. **Regresie pe proforma simpla** (fara comutare, document pornit direct ca Proforma) — confirma ca
|
||||
pasii 2-3 nu au schimbat comportamentul cazului deja corect azi.
|
||||
|
||||
*Depinde de:* S5 (acoperirea tipurilor), S4/S4e (forma finala a incarcarii liniilor — pasul 2 trebuie
|
||||
sa stie daca opereaza pe un cursor de masa sau pe randuri individuale, dupa ce alte povesti decid
|
||||
asta pentru fiecare sursa).
|
||||
|
||||
---
|
||||
|
||||
## 9. Cum se verifica
|
||||
|
||||
**Proba ceruta de plan**: o proforma emisa din formularul unificat nu produce nota contabila si se
|
||||
listeaza pe raportul ei; o copie produce un document nou cu numar nou si acelasi continut.
|
||||
|
||||
**Interogari SQL concrete** (numai `SELECT`, rulate cu unealta PowerShell + `sqlplus.exe`, per
|
||||
mediul de proiect):
|
||||
|
||||
```sql
|
||||
-- 1. Proforma emisa din formularul unificat: fara nota contabila, fara descarcare de gestiune
|
||||
SELECT id_vanzare, tip, eproforma, sters FROM vanzari WHERE id_vanzare = :ID_TEST;
|
||||
-- eproforma trebuie sa fie 1
|
||||
|
||||
SELECT COUNT(*) FROM vanzari_detalii WHERE id_vanzare = :ID_TEST;
|
||||
-- trebuie sa coincida cu numarul de linii adaugate (liniile SE scriu, doar nu se contabilizeaza)
|
||||
|
||||
SELECT id_vanzare_det, id_articol, id_gestiune FROM vanzari_detalii WHERE id_vanzare = :ID_TEST;
|
||||
-- id_gestiune trebuie sa fie NULL pe fiecare linie (sentinela -1000 tradusa de adauga_articol_factura)
|
||||
|
||||
SELECT COUNT(*) FROM note_contabile nc
|
||||
JOIN act a ON a.id_fact = nc.id_fact -- sau echivalentul legaturii act/nota folosite in schema
|
||||
WHERE a.cod = (SELECT cod FROM vanzari WHERE id_vanzare = :ID_TEST);
|
||||
-- trebuie sa fie 0 -- nicio nota contabila generata
|
||||
|
||||
-- 2. Fara descarcare de gestiune: RUL nu are miscare noua dupa emiterea proformei
|
||||
SELECT COUNT(*) FROM rul WHERE dataora >= :MOMENT_EMITERE AND id_articol IN (:articolele_testate);
|
||||
-- trebuie sa fie identic cu inainte de emitere (0 randuri noi legate de acest document)
|
||||
|
||||
-- 3. Copie: document nou, numar nou, acelasi continut
|
||||
SELECT id_vanzare, numar_act, serie_act, eproforma FROM vanzari WHERE id_vanzare = :ID_COPIE;
|
||||
-- eproforma = 0; numar_act/serie_act diferite de documentul sursa
|
||||
|
||||
SELECT vd.id_articol, vd.cantitate, vd.pret, vd.id_gestiune
|
||||
FROM vanzari_detalii vd WHERE vd.id_vanzare = :ID_COPIE
|
||||
ORDER BY vd.id_articol;
|
||||
-- comparat linie cu linie cu vanzari_detalii al documentului sursa (:ID_TEST) -- acelasi articol/cantitate/pret;
|
||||
-- id_gestiune insa REAL (nu NULL), daca articolul e gestionabil -- confirma restaurarea de la sectiunea 2.6
|
||||
|
||||
-- 4. Drumul invers (sectiunea 5, dupa ce varianta e implementata): factura emisa dupa un du-te-vino prin Proforma
|
||||
-- descarca gestiune normal, ca orice factura
|
||||
SELECT id_vanzare, eproforma FROM vanzari WHERE id_vanzare = :ID_TEST_INVERS;
|
||||
-- eproforma = 0
|
||||
SELECT id_gestiune FROM vanzari_detalii WHERE id_vanzare = :ID_TEST_INVERS;
|
||||
-- NU mai e NULL pe liniile gestionabile -- confirma ca varianta aleasa la pasul 4 (sectiunea 8) functioneaza
|
||||
SELECT COUNT(*) FROM rul WHERE dataora >= :MOMENT_EMITERE_INVERS AND id_articol IN (:articolele_testate);
|
||||
-- trebuie sa arate miscare noua -- gestiunea s-a descarcat
|
||||
```
|
||||
|
||||
**Protocol**: fiecare interogare rulata **inainte si dupa** implementare, pe date de test resetate
|
||||
identic, per memoria de proiect "zero cazuri in date nu e dovada" — minim un caz per scenariu descris
|
||||
mai sus (proforma simpla, proforma cu switch la comutare, copiere din proforma, drumul invers),
|
||||
nu doar "a mers o data".
|
||||
|
||||
---
|
||||
|
||||
## 10. Ce nu se poate testa headless
|
||||
|
||||
- **Comutarea combo-ului `Ct_clb_fdoc` cu gridul de linii vizibil in acelasi ecran** — capcana deja
|
||||
confirmata pe acest proiect (`grid-coloane-nu-se-materializeaza-headless`, memorie de proiect):
|
||||
sub `-A -T`, `ColumnCount`/`RecordSource` raman artefacte, comportamentul real al `LostFocus`
|
||||
pe combo si al reincarcarii `clb_serie_act` cere harnessul UI vizibil.
|
||||
- **Dialogul `frm_articol_factura` vs. `do_alege_stoc`** (sectiunea 1.3, decizia de dialog dupa
|
||||
`gestionabil`) — depinde de randare de formular modal, nu apelabil direct fara UI.
|
||||
- **Verificarea vizuala ca liniile deja adaugate isi schimba starea la comutare** (sectiunea 4.1.c) —
|
||||
daca implementarea alege sa arate un indicator vizual (de exemplu, o coloana/culoare care marcheaza
|
||||
"negestionabil"), acel indicator nu se verifica headless; **continutul** `crsfactura` (valorile
|
||||
`gestionabil`/`id_gestiune`) **se poate** verifica headless, cu apeluri directe la metoda noua din
|
||||
pasul 2 (sectiunea 8), fara sa deschida formularul.
|
||||
- **Realocarea vizuala a seriei/numarului in `clb_serie_act`** — control de UI, comportamentul lui de
|
||||
reincarcare (`do_initializeaza`) nu se verifica fara randare.
|
||||
- **Ce se poate verifica headless, direct**: continutul `crsfactura`/`poDate` dupa apeluri directe
|
||||
(nu prin click) la metoda de marcare (pasul 2), la `do_schimba_tipdoc`, si la rutina drumului
|
||||
invers (pasul 4) — cu date de test pregatite manual (un `crsfactura` cu 2-3 linii, `poDate.eProforma`
|
||||
comutat programatic inainte si dupa) — confirma `gestionabil`, `id_gestiune`, `poDate.eProforma`,
|
||||
fara sa deschida formularul. La fel, toate interogarile SQL din sectiunea 9 sunt verificabile
|
||||
headless (SQL direct, fara UI).
|
||||
|
||||
---
|
||||
|
||||
## 11. Riscuri si decizii ramase lui Marius
|
||||
|
||||
1. **Drumul invers (sectiunea 5) — varianta (a) sau (b).** Cel mai important punct deschis al acestui
|
||||
raport: fara o decizie explicita aici, decizia 10 din plan ("proforma foloseste acelasi formular")
|
||||
ramane incompleta — un document care trece prin Proforma si revine la Factura in aceeasi sesiune
|
||||
poate iesi cu stocul nedescarcat, silentios. **Recomandare**: varianta (a) (re-interogare si
|
||||
re-deschidere a alegerii de gestiune la comutarea inapoi), pentru ca varianta (b) (blocarea
|
||||
comutarii) contrazice explicit decizia 10 ("combo-ul ramane in antetul unificat", implicit
|
||||
liber de folosit in ambele sensuri) si ar surprinde operatorul cu o pierdere de munca fara
|
||||
avertisment prealabil la momentul comutarii spre Proforma.
|
||||
2. **Ce se intampla cu `id_gestiune`/lotul ales anterior pe o linie marcata ulterior negestionabil**
|
||||
(sectiunea 4.1, corolarul) — pastrare tacita (mai simplu, fara cod nou) sau stergere explicita
|
||||
(mai clar pentru un ecran viitor care ar afisa gestiunea). **Recomandare**: pastrare tacita — nu
|
||||
ajunge niciodata la server oricum (sentinela `-1000` trimisa explicit ignora orice valoare veche),
|
||||
iar stergerea ar cere cod suplimentar fara beneficiu functional, doar cosmetic.
|
||||
3. **Incertitudinea ramasa din raportul-sursa** (sectiunea 1.3: linia exacta unde `id_gestiune` devine
|
||||
`-1000`) — necesara inainte de a scrie codul pasului 2 (sectiunea 8), nu doar o curiozitate.
|
||||
Nu e o decizie de produs, e o verificare tehnica obligatorie inaintea implementarii.
|
||||
4. **Indicator vizual pentru liniile marcate negestionabil la comutare** (mentionat la sectiunea 10) —
|
||||
optional, nu cerut explicit de plan; de decis daca merita un semnal in grid (culoare/iconita) sau
|
||||
ramane invizibil pana la emitere. Nu blocheaza nimic, dar afecteaza UX-ul comutarii repetate.
|
||||
5. **Testarea pe date reale a `FACT-007`** (mentionata in raportul-sursa ca argument indirect,
|
||||
nu dovada) — daca Marius vrea certitudine completa inainte de implementare, un test manual pe
|
||||
mediu de dezvoltare (proforma cu articol gestionabil din comanda, verificare directa
|
||||
`VANZARI_DETALII.ID_GESTIUNE IS NULL`) inchide definitiv acest gol, in afara perimetrului
|
||||
read-only al acestei cercetari.
|
||||
|
||||
---
|
||||
|
||||
## Handoff
|
||||
|
||||
Cercetare + proiectare incheiate intr-o singura sesiune, fara sa fie nevoie de predare de context.
|
||||
Toate cele 11 sectiuni cerute de brief sunt complete, cu `fisier:linie` verificat direct pe fisierele
|
||||
text reale (`ofacturare.vc2`, `ofacturare_comun.vc2`, `ofacturare.prg`, `ofacturare_comun.prg` — nu
|
||||
`.bak`) si pe corpul `PACK_FACTURARE` de pe `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`.
|
||||
|
||||
**Descoperirea centrala** (sectiunea "Descoperire centrala"): mecanismul care blocheaza nota
|
||||
contabila pe proforma nu e (doar) sentinela `-1000` din `contabilizeaza_articol`, ci alegerea
|
||||
`scrie_proforma` (fara contabilizare deloc) vs. `scrie_factura2`/`scrie_factura_avize` (cu
|
||||
contabilizare) in `do_scrie_factura`, facuta dupa `poDate.eProforma` la Termina. Aceasta descoperire
|
||||
schimba unde trebuie sa se concentreze grija de proiectare: nu pe "cum ajunge `-1000` la server"
|
||||
(deja acoperit corect de codul existent), ci pe **ce se intampla cu liniile deja marcate `-1000` cand
|
||||
documentul nu mai e proforma la Termina** — exact riscul din sectiunea 5, singurul loc unde sentinela
|
||||
chiar conteaza si azi nu exista nicio plasa.
|
||||
|
||||
Niciun fisier de cod atins, niciun `git_sync.ps1`/`txt2vcx.ps1` rulat, niciun commit, nicio scriere pe
|
||||
Oracle (doar `SELECT`/`Read`/`Grep` pe fisiere de pe disc).
|
||||
Reference in New Issue
Block a user