Files
roafacturare/docs/cercetare/s5_acoperire_tipuri.md
2026-09-09 22:19:22 +03:00

41 KiB

Cercetare + proiectare — S5: acoperirea tuturor tipurilor de document

Proiectare pe cod, READ-ONLY (fara editari, fara git_sync.ps1/txt2vcx.ps1, fara commit, fara scriere pe Oracle — numai SELECT), pentru povestea S5 din docs\plan_13_unificare_formular_facturare.md (#### S5). Nu s-a atins COMUN\clase\ofacturare_comun.vc2 si COMUN\programe\ofacturare_editare.prg (perimetrul altei sarcini in lucru) — doar citite cand au aparut in cautari (n-a fost cazul).

Sursa VFP: COMUN\clase\ofacturare.vc2 (frm_facturare_articole = formularul de productie, :10968-15739; frm_facturare_articole2 = prototipul, :15741-19355 — nu e subclasa a primului, mostenesc separat din _frmbase, au Init propriu fiecare). Sursa de rutare: COMUN\programe\ofacturare.prg (factureaza = standard, :81-...; factureaza2 = prototip, :660-...). Referinta de tipuri: COMUN\docs\tipuri_documente_facturare.md.

Verdict (rezumat, citeste asta primul)

  1. Do Case-ul din frm_facturare_articole.Init (ofacturare.vc2:15109-15248) acopera 21 de valori de tip (grupate in 14 ramuri): 1,2,3,4,5,6,7,8,9,10,21,22,23,24,25,26,28,29,41,42,47.
  2. Patru tipuri sunt reale, reachable prin factureaza(), dar nu apar in niciun Case — pierd titlu, cap de coloana, mesaj de stoc, vizibilitate discount, eliminare cSerie: 45 (factura restaurant), 48/49 (custodie cu/fara descarcare K), 52 (contract, factura fiscala valuta). Confirmat pe meniuri (Meniuri\politica.mn2:18,26,29, Meniuri\contracte.mn2:18) si pe rutarea cursorului (ofacturare.prg:271-282), care le recunoaste — doar Init-ul formularului de articole nu le-a "prins" niciodata. Nu doar 52, cum semnalase raportul S4b — sunt patru, nu unul.
  3. Cinci tipuri din referinta (43,44,46,50,51) nu sunt niciodata pasate lui factureaza() in tot arborele D:\ROA (cautare exhaustiva, zero potriviri) — nu ajung la acest formular deloc azi. 50 e marcat explicit "in lucru" in sursa; 51 (ROAACNPRO) foloseste id_set=50100, un interval separat de restul (25000+), semn ca provine dintr-un flux Oracle direct al altui produs, nu din factureaza() local.
  4. Descoperire centrala, dincolo de ce cerea misiunea: prototipul (frm_facturare_articole2.Init, :18988-19080) nu e o versiune partiala a Do Case-ului standard — e aproape gol. Singurul lucru pe care-l face pe tip e sa aleaga cuvantul lcTipDoc ("factura" vs "aviz"), pe o lista mai scurta (lipseste 24). Nu seteaza titlu (nu exista lb_titlu_alb_b121 in tot fisierul prototipului), nu schimba capul coloanei de cantitate, nu schimba mesajul de stoc, nu ascunde discountul, nu are deloc conceptul de coloana cSerie (gridul prototipului, grd_factura, n-are niciodata RemoveObject('cSerie') — cautare pe tot fisierul, zero potriviri in intervalul 15741-19355). Daca formularul unificat porneste de la prototip (cum indica decizia de baza a planului), toata diferentierea pe tip trebuie reconstruita de la zero, nu doar completata.
  5. Rutarea cursorului diverge intre standard si prototip pe trei tipuri, nu doua: 23 (confirmat deja de S4/S4b), plus 52 si 24, gasite aici — pe prototip, Case Inlist(tnTip, 2, 26, 6) (ofacturare.prg:762) omite 52 fata de standard (Inlist(tnTip, 2, 26, 6, 52), :283), si Case Inlist(tnTip, 8, 9) (:819) omite 24 fata de standard (Inlist(tnTip, 8, 9, 24), :307). Daca cineva ar factura tip 52 sau 24 prin prototip azi (gnFacturareNou=1), lcSqlCursor ar ramane nedefinit — eroare, nu doar diferenta de comportament.
  6. Tipurile 26 si 52 n-au niciun bookkeeping crsarticole (nici Rol A, nici Rol B) — inchis aici punctul lasat deschis de raportul S4 punctul 2: excluderea lor din toate cele patru Case-uri de bookkeeping din do_adauga_articol/do_sterge e totala (Do Case exhaustiv, fara ramura implicita), nu doar "neconfirmata".
  7. 27 si 30 raman pe calea lor — confirmat pe cod, cu o nuanta importanta pentru 30: nu e un formular separat, ci acelasi frm_facturare_articole, instantiat si trecut prin acelasi Init/Do Case, dar niciodata aratat (ofacturare.prg:444-453: calculeaza totalurile, apasa programatic but_termin1.Click(), apoi Release(), fara Show()). Tip 30 e afectat de golurile din Do Case exact ca oricare alt tip needitat — doar ca defectele (titlu, cap de coloana) nu se vad niciodata pe ecran.

0. Metoda de verificare — lista de referinta

Lista completa de tipuri vine din COMUN\docs\tipuri_documente_facturare.md (sursa unica, deja verificata pe cod de acea cercetare). Tipuri incluse in tabelul de mai jos: toate cele din sectiunile "Facturi" si "Avize de expeditie" (documentele care intra prin frm_facturare_articole/2). Sectiunea "Tipuri negative" (-1..-13) nu intra in acest formular — sunt scrise de alte produse (ROAGEST, ROAAUTO) prin propriile lor fluxuri, niciodata prin factureaza() din ROAFACTURARE (cautare exhaustiva factureaza(- in tot D:\ROA, zero potriviri) — declarate aici explicit ramase pe calea altui produs, nu "neacoperite".


1. Tabelul complet, tip cu tip

Coloane: tip = VANZARI.TIP · Case propriu = are ramura proprie in frm_facturare_articole.Init (ofacturare.vc2:15109-15248)? · titlu = ce seteaza pe lb_titlu_alb_b121.Caption · cap cantitate = ce seteaza pe grd_articole.cCantitate.header1.Caption (implicit ramane cel din design, [Cantitate in stoc], daca nu e suprascris) · mesaj stoc = This.cmesaj_cantitate · discount = clb_discount.Visible · cSerie = coloana ramane (Da) sau se scoate (Nu) · butoane = ce se face vizibil (but_urmator_tot1/but_retur, ambele .F. la design) · cursor standard = ramura din factureaza (ofacturare.prg:266-308) · cursor prototip = ramura din factureaza2 (:748-822, gol daca lipseste) · Rol crsarticole = A (cantitate ramasa de facturat) / B (plafon de sesiune) / — (fara bookkeeping), din docs\cercetare\s4_punct2_registru_cantitate_ramasa.md · stare S5 = acoperit azi / gol de completat / ramas pe calea veche / neatins.

Facturi

tip denumire Case propriu titlu cap cantitate mesaj stoc discount cSerie butoane vizibile cursor standard cursor prototip Rol stare S5
1 lista de preturi (lei) Da :15122 (grup 1,5,7,10) — (implicit) "Cantitate in stoc" "nu e pe stoc!" vizibil (implicit) Nu (scoasa) but_retur cursor_preturi (grup 1,22,5,29,7,10,23), :279-282 cursor_preturi (grup 1,22,5,29,7,10), :758-761 B (gestionabil, 1,22,29) acoperit azi, de portat
2 contract (lei) Da :15129 (grup 2,6) "FACTURA PE CTR. …" "Cantitate in stoc" "nu e pe stoc!" vizibil Nu — cursor_contract (grup 2,26,6,52), :283-291 cursor_contract (grup 2,26,6 — fara 52), :762-769 B doar pt. opt_facturare=0; — pe rest acoperit azi, de portat
3 comanda Da :15144 "FACTURA LA COMANDA …" "Cantitate comandata" "cantitate comandata facturata" vizibil Nu but_urmator_tot1 cursor_comanda (grup 3,21,25,28,42,47), :292-293 cursor_comanda (acelasi grup), :771-773 A acoperit azi, de portat
4 din avize Da :15151 "FACTURA DIN AVIZE" — (implicit) "cantitate de pe aviz facturata" ascuns (.F., :15154) Da (nu se scoate) but_urmator_tot1 cursor_avize, :294-295 cursor_avize, :774-775 A acoperit azi, de portat
5 lista de preturi valuta Da :15122 (grup 1,5,7,10) — "Cantitate in stoc" "nu e pe stoc!" vizibil Nu but_retur cursor_preturi cursor_preturi — acoperit azi, de portat
6 contract valuta Da :15129 (grup 2,6) "FACTURA PE CTR. …" "Cantitate in stoc" "nu e pe stoc!" vizibil Nu — cursor_contract cursor_contract B partial (ca 2) acoperit azi, de portat
7 credit note Da :15122 (grup 1,5,7,10) — "Cantitate in stoc" "nu e pe stoc!" vizibil Nu but_retur cursor_preturi cursor_preturi — acoperit azi, de portat
8 retur factura lei Da :15236 (grup 8,9) — "Cant. max. de returnat" "nu se mai poate returna" vizibil Da (nu se scoate) but_urmator_tot1 cursor_retur, :306-307 cursor_retur (grup 8,9), :819-820 B (invers) acoperit azi, de portat
9 retur factura valuta Da :15236 (grup 8,9) — "Cant. max. de returnat" "nu se mai poate returna" vizibil Da but_urmator_tot1 cursor_retur cursor_retur B (invers) acoperit azi, de portat
10 factura fiscala valuta Da :15122 (grup 1,5,7,10) — "Cantitate in stoc" "nu e pe stoc!" vizibil Nu but_retur cursor_preturi cursor_preturi — acoperit azi, de portat
43 bon fiscal magazine (ROARETAIL) Nu — — — — — — nicio ramura nicio ramura n/a neatins — niciodata pasat lui factureaza() (cautat in tot D:\ROA); colectat de la magazine prin alt flux
44 factura hotel Nu — — — — — — nicio ramura nicio ramura n/a neatins — la fel, zero apeluri factureaza(44
45 factura restaurant Nu — lipseste din Do Case nesetat nesetat (implicit) nesetat (ramane "nu e pe stoc!" default, :15108) nesetat (ramane vizibil) Da, ramane (nescoasa) nesetat cursor_preturi, :275-278 cursor_preturi, :754-757 — (exclus explicit din bookkeeping, :12871,17178) gol real de completat — reachable din Meniuri\politica.mn2:18
46 nota de plata restaurant Nu — — — — — — nicio ramura nicio ramura n/a neatins — zero apeluri factureaza(46; zero documente in date de test (tipuri_documente_facturare.md, capcana 2)
48 custodie cu descarcare K Nu — lipseste din Do Case nesetat nesetat nesetat nesetat Da, ramane nesetat cursor_articole_k, :271-273 cursor_articole_k, :750-752 — gol real de completat — reachable din Meniuri\politica.mn2:29 (submeniu Marfaincus)
49 custodie fara descarcare K Nu — lipseste din Do Case nesetat nesetat nesetat nesetat Da, ramane nesetat cursor_articole_k cursor_articole_k — gol real de completat — reachable din Meniuri\politica.mn2:26
50 (in lucru) retur custodie Nu — — — — — — nicio ramura nicio ramura n/a neatins, marcat explicit "in lucru" in tipuri_documente_facturare.md
51 factura ROAACNPRO Nu — — — — — — nicio ramura nicio ramura n/a neatins — id_set=50100, interval separat; probabil scris direct de ROAACNPRO, nu prin factureaza() local
52 contract, factura fiscala valuta Nu — lipseste din Do Case nesetat nesetat nesetat nesetat Da, ramane nesetat cursor_contract (grup 2,26,6,52) lipseste din grupul contract (:762) — lcSqlCursor nedefinit pe prototip — (confirmat, vezi §2) gol real de completat — reachable din Meniuri\contracte.mn2:18

Avize de expeditie

tip denumire Case propriu titlu cap cantitate mesaj stoc discount cSerie butoane vizibile cursor standard cursor prototip Rol stare S5
21 catre clienti, din comanda Da :15168 (grup 21,28,42,47) "AVIZ DE EXPEDITIE DIN COMANDA" — (implicit) "avizata cantitatea comandata" ascuns Nu but_urmator_tot1 cursor_comanda cursor_comanda A acoperit azi, de portat
22 catre clienti, din lista Da :15178 (grup 22,29) "AVIZ DE EXPEDITIE DIN LISTA DE PRETURI" — "nu e pe stoc!" ascuns Nu — cursor_preturi cursor_preturi B acoperit azi, de portat
23 transfer subunitati, din lista Da :15187 "TRANSFER INTRE SUBUNITATI" — "nu e pe stoc!" ascuns Nu — cursor_preturi (grup 1,22,5,29,7,10,23), :279 cursor_gestiune (grup 23,41), :776-778 B (cod comun, indiferent de sursa) acoperit azi, dar sursa de cursor diverge intre forme — vezi §3
24 aviz retur Da :15242 "RETUR AVIZ DE EXPEDITIE" "Cant. max. de returnat" "nu se mai poate returna" (nemodificat aici) Nu but_urmator_tot1 cursor_retur (grup 8,9,24), :306-307 lipseste din grupul retur (:819, doar 8,9) — lcSqlCursor nedefinit pe prototip B (invers) acoperit azi, dar prototipul n-are ramura de cursor — vezi §3
25 transfer subunitati, din comanda Da :15206 "TRANSFER INTRE SUBUNITATI PE BAZA DE COMANDA" — "avizata cantitatea comandata" ascuns Nu but_urmator_tot1 cursor_comanda cursor_comanda A acoperit azi, de portat
26 catre clienti, din contract Da :15216 "AVIZ DE EXPEDITIE DIN CONTRACTUL …" "Cantitate in stoc" "nu e pe stoc!" ascuns Nu — cursor_contract (grup 2,26,6,52) cursor_contract (grup 2,26,6 — fara 52, dar 26 e prezent) — (confirmat, §2) acoperit azi, de portat
27 transfer subunitati, pe lucrare n/a — ramane pe calea lui n/a n/a n/a n/a n/a n/a cursor_lucrare, :302-304 cursor_lucrare, :815-817 n/a ramas pe calea veche — frm_avizare_lucrare, confirmat §4
28 catre clienti debitori, din comanda Da :15168 (grup 21,28,42,47) "AVIZ DE EXPEDITIE DIN COMANDA" — "avizata cantitatea comandata" ascuns Nu but_urmator_tot1 cursor_comanda cursor_comanda A acoperit azi, de portat
29 catre clienti debitori, din lista Da :15178 (grup 22,29) "AVIZ DE EXPEDITIE DIN LISTA DE PRETURI" — "nu e pe stoc!" ascuns Nu — cursor_preturi cursor_preturi B acoperit azi, de portat
30 transfer subunitati, pe NIR n/a — ramane pe calea lui, dar prin acelasi formular (irelevant — formular niciodata aratat) (irelevant) (irelevant) (irelevant) (irelevant) (irelevant) cursor_aviz_nir, :299-300 cursor_aviz_nir, :813 n/a ramas pe calea veche, cu nuanta — vezi §4
41 retur transfer, lista pret Da :15197 "RETUR TRANSFER" — "nu e pe stoc!" ascuns Nu — cursor_gestiune, :296-298 cursor_gestiune (grup 23,41) B acoperit azi, de portat
42 catre clienti custodie, din comanda Da :15168 (grup 21,28,42,47) "AVIZ DE EXPEDITIE DIN COMANDA" — "avizata cantitatea comandata" ascuns Nu but_urmator_tot1 cursor_comanda cursor_comanda A acoperit azi, de portat
47 catre clienti custodie K, din comanda Da :15168 (grup 21,28,42,47) "AVIZ DE EXPEDITIE DIN COMANDA" — "avizata cantitatea comandata" ascuns Nu but_urmator_tot1 cursor_comanda cursor_comanda A acoperit azi, de portat
50 (in lucru) retur clienti custodie Nu — — — — — — nicio ramura nicio ramura n/a neatins, "in lucru"

Tipuri negative (-1..-13, ROAGEST/ROAAUTO): ramase pe calea altui produs — nu trec niciodata prin factureaza()/factureaza2 din ROAFACTURARE (cautare exhaustiva, zero potriviri), deci nu intra in perimetrul Do Case-ului acestui formular. Declarate aici explicit, nu omise.


2. Tipurile care nu intra in niciun Case — inventar complet

Cerinta explicita a misiunii: "nu doar 52". Lista completa, verificata pe intreg Do Case-ul (ofacturare.vc2:15109-15248, citit integral, nu esantion) fata de lista de referinta:

Nu apar in niciun Case al frm_facturare_articole.Init:

tip reachable prin factureaza()? ce pierde concret
43 Nu (0 apeluri in tot D:\ROA) irelevant — nu ajunge la acest formular
44 Nu irelevant
45 Da (Meniuri\politica.mn2:18) titlu, cap coloana cantitate, mesaj de stoc, cSerie nescoasa (ramane vizibila, desi tip 45 e explicit exclus din bookkeeping-ul de cantitate — cele doua lucruri nu sunt legate)
46 Nu irelevant — zero documente si in datele de test
48 Da (Meniuri\politica.mn2:29, submeniu Marfaincus) idem 45
49 Da (Meniuri\politica.mn2:26) idem 45
50 Nu, "in lucru" irelevant azi
51 Nu (interval id_set separat, alt produs) irelevant pentru acest formular
52 Da (Meniuri\contracte.mn2:18) titlu (ramane cel implicit al formularului), cSerie nescoasa, cap coloana cantitate implicit — cel mai vizibil defect, pentru ca 2/6 (acelasi grup logic) au titlu corect

Concluzie: din cele noua tipuri fara Case, patru sunt reale si vizibile utilizatorului azi (45, 48, 49, 52) — acestea sunt golul de completat cu valoare, nu doar 52. Celelalte cinci (43,44,46,50,51) nu ajung niciodata la acest formular in fluxul curent — nu au nevoie de ramura in Do Case pana cand ceva le conecteaza la factureaza() (posibil, dar in afara perimetrului observabil aici; de tratat ca risc, nu ca bug, la sectiunea 10).

De ce raman "invizibile" azi cu cSerie/titlu implicit, nu cu eroare: Do Case ... Endcase fara ramura Otherwise in VFP nu genereaza nicio eroare cand nimic nu se potriveste — pur si simplu sare peste tot blocul. De-asta tip 45/48/49/52 "merg" (formularul se deschide, factureaza cu succes), doar cu UI-ul netratat pentru cazul lor specific — un defect tacut, nu un crash, motiv probabil pentru care n-a fost observat/raportat pana acum.


3. Divergentele standard vs. prototip

Aspect Standard (factureaza) Prototip (factureaza2) Comportament corect de pastrat
Cursor pe tip 23 cursor_preturi (grup 1,22,5,29,7,10,23, :279) — tratat ca lista de preturi cursor_gestiune (grup 23,41, :776-778) — tratat ca transfer cursor_gestiune, impreuna cu 41 (deja stabilit de S4/S4b: transferul e o singura familie de tip, indiferent daca porneste "din lista" sau "retur"; tratarea ca lista de preturi pe standard e inconsistenta cu propriul titlu "TRANSFER INTRE SUBUNITATI" pe care tot standardul il afiseaza pentru tip 23)
Cursor pe tip 52 prezent, grupat cu 2,26,6 (:283) absent din grupul contract (:762, doar 2,26,6) — lcSqlCursor ramane nedefinit daca cineva factureaza tip 52 prin prototip prezent, grupat cu 2,6,26 — lipsa lui pe prototip e o eroare de portare, nu o alegere deliberata (nimic in cod sugereaza ca 52 trebuia tratat diferit de 2/6/26 la nivel de cursor)
Cursor pe tip 24 prezent, grupat cu 8,9 (:306-307) absent din grupul retur (:819, doar 8,9) — lcSqlCursor nedefinit prezent, grupat cu 8,9 — acelasi tip de omisiune ca la 52
Init: diferentiere pe tip 14 ramuri, seteaza titlu/cap coloana/mesaj/discount/cSerie/butoane practic nimic — doar lcTipDoc ("factura"/"aviz"), pe o lista fara tip 24 toata logica standardului, portata — prototipul nu are nimic de pastrat aici in afara de pozitia lcTipDoc
Coloana cSerie exista in grid prin design, se scoate condiționat (10 din 21 tipuri acoperite) nu exista deloc ca si coloana in grd_factura (gridul unic al prototipului) de decis explicit la proiectare (§5) — nu e o simpla portare, gridul insusi trebuie sa capete coloana
but_urmator_tot1 (sau echivalentul lui) vizibil pe 9 din 21 de tipuri (§1) nu exista conceptul in Init — prototipul nu are nimic care sa corespunda azi de portat lista completa de vizibilitate din standard
clb_discount.Visible ascuns explicit pe toate tipurile de aviz (21,28,42,47,22,29,23,41,25,26) niciodata atins in Init de portat integral

De ce conteaza asta pentru S5: planul spune ca formularul unificat se bazeaza pe prototip (arhitectura lui: grid unic, editare inline, cautare pe server — deja deciziile S1-S4). Dar diferentierea pe tip nu vine "aproape gata" din prototip — vine aproape in intregime din standard, si trebuie portata, nu doar completata cu cele patru tipuri lipsa. Cele doua liste (tipuri lipsa din standard: 45/48/49/52; tot ce lipseste din prototip: aproape totul) sunt probleme diferite, care se rezolva in aceeasi miscare daca proiectarea de la §5 porneste de la o sursa unica de configurare portata integral din standard, cu cele patru completari incluse de la inceput (nu adaugate separat, dupa portare).


4. Tipurile speciale (27, 30) — confirmate pe cod

Tip 27 — transfer pe baza de lucrare

Confirmat la trei niveluri, toate in ofacturare.prg:

  • Do Case tnTip = 27 -> poDate.nIdTipDoc = 6 (:188-189, tip document AVIZ);
  • Do Case tnTip = 27 -> lcObiect = [frm_date_aviz_lucrare] (:218-219) — formular de antet diferit, nu frm_date_aviz/frm_date_factura;
  • Do Case tnTip = 27 -> lcObject = [frm_avizare_lucrare] (:386-387) — formular de articole diferit, nu frm_facturare_articole. Cursorul sursa e si el propriu: cursor_lucrare (:302-304), populat pe poDate.id_lucrare, un camp pe care restul tipurilor nu-l au.

Ce il tine pe calea lui: id_lucrare — o legatura pe care niciun alt tip de document n-o are (lucrare de service/executie, nu comanda/aviz/contract). frm_avizare_lucrare grupeaza gestiunile destinatie diferit (crsgestiunidest, :388-393, cu optiunea <TOATE>), o structura pe care frm_facturare_articole/2 n-o au. Formularul unificat n-ar avea id_lucrare si n-ar avea gruparea pe gestiuni destinatie — motiv suficient sa ramana separat, confirmat pe cod, nu presupus.

Tip 30 — transfer pe baza de NIR

Nuanta importanta, gasita aici: tip 30 nu ocoleste frm_facturare_articole — il instantiaza, exact ca orice alt tip din grupul "otherwise" (ofacturare.prg:395, lcObject = [frm_facturare_articole], ramura Else a lui If tnTip = 27). Trece prin acelasi Init, acelasi Do Case de la :15109-15248 (unde 30 nu are ramura proprie — ar avea aceleasi goluri ca 45/48/49 daca ar fi vreodata aratat). Diferenta reala: formularul nu e niciodata aratat (ofacturare.prg:444-453):

IF tnTip = 30 && AVIZ DIN NIR
    ofrmdetaliifactura.do_calculeaza_totaluri()
    ofrmdetaliifactura.but_termin1.Click()
    plVizibil = .F.
    ...
ELSE
    ...
    If plVizibil
        ofrmdetaliifactura.Show()
    Else
        ofrmdetaliifactura.Release()
        pnButon = 2
    Endif
ENDIF

Ce il tine pe calea lui: nu structura formularului (e acelasi obiect), ci automatizarea completa a fluxului — cursorul sursa (cursor_aviz_nir, populat din VRUL/tranzactii de receptie, nu din comanda/lista de preturi) vine deja complet, iar codul apeleaza direct metodele de finalizare fara interactiune. Pentru formularul unificat: daca arhitectura noua pastreaza acelasi tipar ("creeaza obiectul, populeaza, cheama finalizarea, Release() fara Show()"), tip 30 continua sa functioneze neschimbat — nu are nevoie de ramura in configurarea vizuala (§5), pentru ca vizualul nu se vede niciodata. Singurul risc real: daca do_calculeaza_totaluri()/but_termin1.Click() ale formularului unificat ajung sa citeasca vreo proprietate pe care doar Do Case-ul vizual o seteaza azi (de exemplu, un cod care ar verifica This.cmesaj_cantitate sau lcTipDoc in logica de calcul, nu doar in UI) — de verificat explicit la implementare, nu presupus ca "nu conteaza pentru ca nu se vede".


5. Ce structura inlocuieste Do Case-ul de 140 de linii

Optiunile comparate

(a) Pastreaza Do Case, doar completeaza-l (adauga ramuri pentru 45/48/49/52, porteaza restul in prototip). Cost minim imediat, dar nu rezolva problema de fond: un Do Case fara Otherwise nu semnaleaza niciodata un tip lipsa — exact mecanismul care a produs golul de azi (patru tipuri reale pierdute, ani la rand, fara nicio eroare). Orice tip nou de document adaugat in viitor (suita are deja 46,50 "in lucru", 43,44,51 din alte fluxuri) risca aceeasi soarta.

(b) Metoda separata per grup de tipuri (configureaza_lista_preturi(), configureaza_comanda(), ...). Mai clar decat un Do Case unic, dar tot implicit — un tip nou tot nu declanseaza nicio eroare daca nimeni nu-l adauga in metoda corecta; doar muta problema din 140 de linii intr-un fisier cu mai multe metode mici, fara sa adauge un mecanism de detectie.

(c) Tabel de configurare per tip (RECOMANDAT). Un cursor/tabel cu un rand per tip, coloanele fiind exact proprietatile pe care Do Case-ul le seteaza azi: titlu, cap_cantitate, mesaj_stoc, discount_vizibil (L), are_serie (L), tip_doc (factura/aviz), buton_tot_vizibil (L), buton_retur_vizibil (L), grup_sursa (pentru meniul S4b: lista/comanda/aviz-comanda/transfer/ retur/contract-articole/contract-rate). Populat printr-un singur bloc de INSERT INTO (sau un DBF static, configuratie_tip_document.dbf, editabil fara compilare) — un rand per tip din tipuri_documente_facturare.md, inclusiv cele patru azi lipsa.

Init devine:

SELECT * FROM configuratie_tip_document WHERE tip = poDate.tip INTO CURSOR crscfgtip
If Reccount('crscfgtip') = 0
    *   tip necunoscut -- eroare explicita, nu formular netratat tacut
    AMESSAGEBOX("Tip de document necunoscut in configurare: " + Transform(poDate.tip), 16, "Eroare configurare")
    Thisform.Release()
    Return
Endif
This.lb_titlu_alb_b121.Caption = crscfgtip.titlu
This.grd_articole.cCantitate.header1.Caption = crscfgtip.cap_cantitate
This.cmesaj_cantitate = crscfgtip.mesaj_stoc
This.clb_discount.Visible = crscfgtip.discount_vizibil
If !crscfgtip.are_serie
    This.grd_articole.RemoveObject('cSerie')
Endif
This.but_urmator_tot1.Visible = crscfgtip.buton_tot_vizibil
This.but_retur.Visible = crscfgtip.buton_retur_vizibil

De ce e mai bun decat (a)/(b) pe cost de intretinere:

  • Un tip lipsa devine o eroare vizibila la deschidere, nu un formular netratat tacut — exact defectul care a permis golul de azi sa treaca neobservat ani la rand.
  • "Cat de usor se vede un tip lipsa" e mecanic, nu vizual — vezi §8, o interogare simpla compara lista de tipuri din configurare cu lista de referinta din tipuri_documente_facturare.md, fara sa ruleze formularul.
  • Grupurile identice raman explicite, nu implicite — azi, "tipurile 21,28,42,47 au acelasi titlu" se vede doar citind Inlist(...); intr-un tabel, acelasi lucru se vede ca patru randuri cu aceeasi valoare in coloana titlu — usor de generat cu un singur INSERT per grup (FOR EACH tip IN (21,28,42,47) ... INSERT ...), nu mai putin explicit, dar auditabil cu SELECT titlu, COUNT(*) GROUP BY titlu.
  • Coloana are_serie rezolva si divergenta standard/prototip de la §3 — prototipul nu are azi conceptul deloc; cu configurarea noua, adaugarea coloanei cSerie in gridul unificat devine conditionata de aceeasi sursa unica, indiferent de forma de baza.

Cost: portarea initiala a ~21 de randuri (14 ramuri distincte de azi + 4 completari + grupare explicita), plus un nou tabel/cursor de intretinut. Nu e cod nou complex — e date, nu logica; riscul de regresie e in acuratetea portarii (fiecare valoare trebuie sa corespunda exact cu ce face azi Do Case-ul), verificabil linie cu linie fata de tabelul din §1.

Recomandare finala: (c), cu tabelul de configurare implementat ca DBF static (nu cursor generat in cod) — editabil de oricine fara sa recompileze, si direct verificabil cu SELECT fara sa porneasca formularul (vezi §8).


6. Grupuri naturale de tipuri

Din tabelul §1, grupurile care au azi (sau ar trebui sa aiba) valori identice pe toate coloanele:

Grup Tipuri Ce difera in interiorul grupului
Lista de preturi, fara stoc special 1, 5, 7, 10 Nimic in Init — difera doar valuta/tip document la nivel de antet (poDate.in_valuta, nIdTipDoc), nu in acest formular
Contract, factura 2, 6 (+ 52 de adaugat) Nimic in Init dupa completare — 52 e valuta, ca 6, dar cu alt id_set; titlul/coloanele sunt identice
Aviz din comanda (clienti/debitori/custodie) 21, 28, 42, 47 Nimic in Init — difera doar destinatia comerciala (client normal/debitor/custodie), invizibila la acest nivel
Aviz din lista de preturi 22, 29 Nimic — difera doar client normal/debitor
Retur facturi 8, 9 Nimic — lei/valuta
Transfer subunitati 23, 41 Sens (din lista vs. retur) — titlu diferit ("TRANSFER..." vs "RETUR TRANSFER"), restul identic; trebuie unificate pe cursor (§3) inainte de unificare vizuala
Comanda proprie 3 Singur — cap de coloana propriu ("Cantitate comandata")
Avize proprii 4 Singur — discount vizibil (spre deosebire de toate celelalte avize)
Aviz din contract 26 Singur — titlu propriu, dar cursor comun cu grupul contract
Aviz retur 24 Singur — cursor comun cu 8/9, dar titlu si but_urmator_tot1 proprii
Custodie K 48, 49 Identice ca structura vizuala (ambele lipsesc azi) — difera doar cu/fara descarcare K, invizibil la acest nivel
Restaurant 45 Singur, azi lipsa

Observatie de proiectare: grupurile "aviz din comanda" (21/28/42/47) si "comanda" (3) au acelasi cap de coloana si mesaj de stoc conceptual ("cantitate comandata"), dar text usor diferit ("facturata"/"avizata") — pastrate distincte in tabelul de configurare (nu fortate identice), pentru ca diferenta e deliberata in codul de azi (:15149 vs :15176, verb diferit).


7. Pasi de implementare, ordonati

  1. Extrage tabelul de configurare din Do Case-ul standard, exhaustiv — un rand per tip din tipuri_documente_facturare.md care intra prin acest formular (Facturi + Avize, exclus 27/30/ negative), valorile copiate exact din §1. Gata cand: SELECT DISTINCT tip FROM configuratie_tip_document produce exact multimea {1,2,3,4,5,6,7,8,9,10,21,22,23,24,25,26,28,29, 41,42,45,47,48,49,52} (23 de tipuri) — nici unul in minus, nici unul in plus fata de lista calculata in §8.
  2. Completeaza cele patru randuri azi lipsa (45,48,49,52) cu valori coerente cu grupul lor logic (45 langa lista de preturi cu stoc dezactivat conceptual; 48/49 langa custodie K; 52 langa 2/6) — decizie de continut, nu doar de structura; de validat cu Marius inainte de a le considera "gata", pentru ca azi nu exista niciun titlu/mesaj de referinta pentru ele (nimeni nu l-a vazut pe ecran). Gata cand: cele patru randuri au valori nenule pe toate coloanele obligatorii (titlu, cap_cantitate, mesaj_stoc).
  3. Corecteaza rutarea cursorului: 23 trece pe cursor_gestiune (unificat cu 41, nu mai divide standard/prototip); 52 si 24 primesc ramura de cursor pe orice cale ramane vie din prototip (daca formularul unificat pastreaza factureaza2-stil, sau devine parte din calea unica daca factureaza/factureaza2 se unesc — decizie separata, in afara acestei povesti). Gata cand: deschiderea formularului pe tip 23, 24 si 52 prin calea noua produce acelasi continut in crsarticole ca varianta care functiona deja (23→prototip vechi pentru comparatie de continut, 24/52→standard).
  4. Adauga coloana cSerie in gridul unificat, condiționata pe are_serie — azi absenta din gridul prototipului; adaugata o singura data, aratata/ascunsa din configurare, nu prin RemoveObject scris de mana pe fiecare tip. Gata cand: pe un tip cu are_serie=.T. (ex. 4) coloana e vizibila; pe un tip cu are_serie=.F. (ex. 3) nu e.
  5. Inlocuieste Do Case-ul din Init cu citirea din configurare (structura din §5), inclusiv ramura de eroare explicita pe tip necunoscut. Gata cand: pentru fiecare din cele 23 de tipuri, deschiderea formularului seteaza exact valorile din tabelul §1/pasul 2 (comparatie automata, nu vizuala — proprietatile sunt citibile headless).
  6. Verifica tipurile speciale raman neatinse: 27 (cale total separata, neschimbata), 30 (acelasi formular, dar do_calculeaza_totaluri/but_termin1.Click() nu citesc nimic setat doar de vechiul Do Case vizual — verificare explicita, §4). Gata cand: un document tip 30 de test se finalizeaza cu acelasi rezultat in VANZARI/VANZARI_DETALII inainte si dupa migrare.
  7. Documenteaza tipurile neatinse (43,44,46,50,51) ca decizie explicita, nu ca omisiune — un comentariu in tabelul de configurare (* 43,44,46,50,51: neconectate la factureaza() in ROAFACTURARE, verificat <data>) ca viitorii cititori sa nu presupuna ca lipsesc din greseala. Gata cand: comentariul exista si linkeaza spre acest raport.

Depinde de: S4 (cautarea articolelor pe server) pentru arhitectura gridului unic — pasul 4 de aici presupune ca gridul unificat exista deja in forma stabilita de S4; S4b (bara de butoane) pentru buton_tot_vizibil/buton_retur_vizibil, care alimenteaza si meniul xmenu() de acolo — coloanele grup_sursa din tabelul de configurare (§5) sunt exact ce cere S4b sectiunea 3.


8. Cum se verifica ca acoperirea e completa — proba mecanica

Nu o citire — o interogare care compara doua liste. Doua surse de adevar:

  1. Lista de referinta: tipurile din COMUN\docs\tipuri_documente_facturare.md, sectiunile "Facturi" si "Avize de expeditie", minus cele confirmate neatinse azi de acest formular (27, 30 raman — vezi nuanta §4 — dar 43,44,46,50,51 se exclud daca raman neconectate; de recalculat lista la fiecare rulare, nu de la o constanta inghetata).
  2. Lista din configurare (dupa implementarea §5): SELECT DISTINCT tip FROM configuratie_tip_document.

Script de verificare (headless, fara UI, rulabil oricand):

* verifica_acoperire_tip.prg — proba mecanica pentru S5
LOCAL lnLipsa, lnInPlus
* 1. lista de referinta -- tinuta manual sincron cu tipuri_documente_facturare.md
*    (facturi + avize, exclus negative; 27/30 raman in lista, tratate separat la pasul 3)
DIMENSION laReferinta[23]
laReferinta = [1,2,3,4,5,6,7,8,9,10,21,22,23,24,25,26,27,28,29,30,41,42,47,52]  && + 45,48,49 dupa Pasul 2

* 2. lista din configurare
SELECT DISTINCT tip FROM configuratie_tip_document INTO CURSOR crsCfg

* 3. tipuri de referinta fara configurare (exclus 27, 30 -- cale separata confirmata)
* 4. tipuri in configurare fara corespondent in referinta (config "orfana")
* -- ambele liste trebuie sa fie goale la "gata"

Alternativ, fara sa astepte implementarea §5: acelasi principiu se aplica azi direct pe Do Case-ul din ofacturare.vc2:15109-15248, extragand tipurile din fiecare Case ... Inlist/= prin vfp_symbols.ps1 -Grep 'Case (poDate\.tip|Inlist\(poDate\.tip' si comparand rezultatul cu lista de referinta — exact tehnica folosita in aceasta cercetare pentru a produce tabelul din §1 (nu o citire vizuala, o extractie sistematica).

Pentru cursor (rutare, §3): acelasi principiu, pe ofacturare.prg, comparand tipurile din fiecare Do Case/Inlist de la :266-308 (standard) cu cele de la :748-822 (prototip) — orice tip prezent intr-una si absent in cealalta e o divergenta de raportat (asa au fost gasite 52 si 24 in aceasta sesiune).


9. Ce nu se poate testa headless

  • Titlul, capul de coloana, mesajul de stoc ca text afisat efectiv pe ecran — verificabile headless doar ca proprietati setate (This.lb_titlu_alb_b121.Caption dupa Init(), apelat direct cu un poDate de test), nu ca randare vizuala. Diferenta conteaza: o proprietate corect setata pe un control care nu exista (lb_titlu_alb_b121 lipsa din prototip azi) ar trece "headless" fara sa arate nimic real — de confirmat mai intai ca ambele controale exista in formularul unificat.
  • Coloanele de grid (grd_articole/grd_factura, coloana cSerie noua) — capcana deja cunoscuta pe acest proiect: sub -A -T (rulare headless), ColumnCount=0/RecordSource raman artefacte, coloanele nu se materializeaza. Exista un harness UI vizibil care le citeste corect — orice verificare a are_serie/coloanelor trebuie sa treaca prin acela, nu prin -A -T.
  • Tip 30 — fluxul complet fara Show() — se poate rula headless (nu deschide nicio fereastra prin constructie), dar verificarea "rezultatul in Oracle e identic inainte/dupa" cere date de test reale (un NIR cu articole), nu doar apelul metodei.
  • Popup-ul/dialogul viitor din S4b (xmenu(), cauta_alfa), daca grup_sursa din tabelul de configurare (§5/§6) ajunge sa-l alimenteze direct — mostenit ca limitare de la raportul S4b (§8 de acolo): continutul lcMeniu verificabil ca text, popup-ul afisat nu.
  • Comportamentul real al meniurilor politica.mn2/contracte.mn2 pentru tipurile 45/48/49/52 — se poate confirma ca exista intrarea de meniu (citire .mn2, facuta in aceasta cercetare), dar nu ca apasarea ei in productie deschide exact formularul asteptat, fara o rulare UI vizibila.

10. Riscuri si ce ramane de decis de Marius

  1. Continutul exact (titlu/mesaj) pentru cele patru tipuri azi netratate (45,48,49,52) — codul nu ofera niciun precedent vizual (n-au fost vazute niciodata corect pe ecran), deci textele propuse in Pasul 2 (§7) sunt o propunere, nu o recuperare a unui text existent. Recomandare: 45 langa grupul "lista de preturi fara stoc" (e exclus explicit din bookkeeping de stoc, :12871); 48/49 cu titlu care mentioneaza "custodie" (singurul lucru care le distinge conceptual azi, in afara de coeficientul K, invizibil la acest nivel); 52 identic cu 2/6 ("FACTURA PE CTR. ..."), pentru coerenta cu gruparea deja facuta corect in frm_date_factura.Init (:9530,9632,9670, grupul 2,6,52).
  2. Daca 23 trece pe cursor_gestiune pe calea unificata, comportamentul vizibil pentru operator se schimba (sursa de articole devine stocul din gestiune, nu lista de preturi) — decizie de produs, nu doar tehnica, deja semnalata de S4/S4b, dar repetata aici pentru ca afecteaza direct §5/§7 (tabelul de configurare trebuie sa reflecte alegerea finala, nu ambele variante). Recomandare: cursor_gestiune, argumentat de coerenta cu titlul "TRANSFER INTRE SUBUNITATI" pe care insusi standardul il afiseaza azi pentru 23 (titlul spune "transfer", cursorul azi spune "lista de preturi" — inconsistenta interna de rezolvat, nu de pastrat).
  3. Daca 43,44,46,50,51 raman permanent neconectate la factureaza(), sau exista planuri sa fie activate — nu s-a gasit nicio dovada de cod ca ar fi in curs, dar nici o confirmare ca sunt abandonate definitiv (in afara de 50, marcat explicit "in lucru" in sursa). De intrebat pe Marius direct, pentru ca raspunsul schimba daca tabelul de configurare (§5) trebuie sa le includa preventiv sau poate ramane cu 23 de randuri.
  4. Coloana cSerie pe gridul unificat — cost de adaugare — prototipul n-are azi conceptul deloc; adaugarea ei presupune modificari de grid (nu doar de cod), posibil in afara perimetrului text-only (.vc2/.sc2 prin txt2vcx.ps1) daca structura de coloane a gridului cere editare in IDE — de confirmat la implementare, nu presupus ca e o simpla proprietate.
  5. Tabel de configurare ca DBF static vs. INSERT-uri in cod — recomandarea (§5) e DBF, pentru editabilitate fara recompilare, dar suita foloseste azi predominant cod pentru acest fel de configurare (niciun precedent de DBF static de configurare gasit in frm_facturare_articole/ frm_date_factura) — de validat cu Marius daca abaterea de la conventia existenta merita beneficiul, sau daca un cursor generat in cod (mai aproape de stilul actual, dar mai putin editabil) e preferat.

Handoff

Cercetare + proiectare incheiata in aceasta sesiune, fara sa fie nevoie de predare de context. Toate cele zece sectiuni cerute de misiune sunt completate, cu fisier:linie verificat direct pe fisierele text reale (ofacturare.vc2, ofacturare.prg, nu .bak), plus meniurile .mn2 si raportul S4/S4b/S4_punct2 citate ca sursa pentru punctele deja stabilite (nereinvestigate).

Descoperiri dincolo de cerinta explicita a misiunii, semnalate clar in text: (1) patru tipuri lipsa din Do Case, nu unul (45/48/49/52, sectiunea 2); (2) prototipul (frm_facturare_articole2.Init) e aproape complet gol pe diferentiere de tip, nu doar incomplet (sectiunea 3) — cea mai mare descoperire a acestei sesiuni, cu impact direct asupra efortului de implementare estimat pentru S5; (3) doua divergente noi de rutare a cursorului (52, 24), pe langa cea deja cunoscuta (23) (sectiunea 3); (4) tipurile 26 si 52 confirmate fara niciun bookkeeping crsarticole, inchizand punctul lasat deschis de raportul S4 punctul 2 (sectiunea 1, nota de subsol pe tabel).

Niciun fisier de cod atins, niciun git_sync.ps1/txt2vcx.ps1 rulat, nicio scriere pe Oracle (numai Read/Grep/vfp_symbols.ps1 pe fisiere de pe disc).